Merge branch 'release/0.4.0'

This commit is contained in:
Jorge Martín 2023-12-22 13:23:18 +01:00
commit e664d0b716
2397 changed files with 25046 additions and 13161 deletions

1
.gitattributes vendored
View file

@ -1,2 +1,3 @@
**/snapshots/**/*.png filter=lfs diff=lfs merge=lfs -text **/snapshots/**/*.png filter=lfs diff=lfs merge=lfs -text
**/docs/images-lfs/*.png filter=lfs diff=lfs merge=lfs -text **/docs/images-lfs/*.png filter=lfs diff=lfs merge=lfs -text
libraries/mediaupload/impl/src/test/assets/* filter=lfs diff=lfs merge=lfs -text

View file

@ -1,5 +1,5 @@
name: Bug report for the Element X Android app name: Bug report for the Element X Android app
description: Report any issues that you have found with the Element X app. Please [check open issues](https://github.com/vector-im/element-x-android/issues) first, in case it has already been reported. description: Report any issues that you have found with the Element X app. Please [check open issues](https://github.com/element-hq/element-x-android/issues) first, in case it has already been reported.
labels: [T-Defect] labels: [T-Defect]
body: body:
- type: markdown - type: markdown

View file

@ -5,7 +5,7 @@ body:
- type: markdown - type: markdown
attributes: attributes:
value: | value: |
Thank you for taking the time to propose an enhancement to an existing feature. If you would like to propose a new feature or a major cross-platform change, please [start a discussion here](https://github.com/vector-im/element-meta/discussions/new?category=ideas). Thank you for taking the time to propose an enhancement to an existing feature. If you would like to propose a new feature or a major cross-platform change, please [start a discussion here](https://github.com/element-hq/element-meta/discussions/new?category=ideas).
- type: textarea - type: textarea
id: usecase id: usecase
attributes: attributes:

View file

@ -13,7 +13,7 @@ updates:
ignore: ignore:
- dependency-name: "*" - dependency-name: "*"
reviewers: reviewers:
- "vector-im/element-x-android-reviewers" - "element-hq/element-x-android-reviewers"
# Updates for Gradle dependencies used in the app # Updates for Gradle dependencies used in the app
- package-ecosystem: "gradle" - package-ecosystem: "gradle"
directory: "/" directory: "/"
@ -23,4 +23,4 @@ updates:
ignore: ignore:
- dependency-name: "*" - dependency-name: "*"
reviewers: reviewers:
- "vector-im/element-x-android-reviewers" - "element-hq/element-x-android-reviewers"

View file

@ -1,4 +1,4 @@
<!-- Please read [CONTRIBUTING.md](https://github.com/vector-im/element-x-android/blob/develop/CONTRIBUTING.md) before submitting your pull request --> <!-- Please read [CONTRIBUTING.md](https://github.com/element-hq/element-x-android/blob/develop/CONTRIBUTING.md) before submitting your pull request -->
## Type of change ## Type of change
@ -53,9 +53,9 @@ Uncomment this markdown table below and edit the last line `|||`:
- [ ] Changes have been tested on an Android device or Android emulator with API 23 - [ ] Changes have been tested on an Android device or Android emulator with API 23
- [ ] UI change has been tested on both light and dark themes - [ ] UI change has been tested on both light and dark themes
- [ ] Accessibility has been taken into account. See https://github.com/vector-im/element-x-android/blob/develop/CONTRIBUTING.md#accessibility - [ ] Accessibility has been taken into account. See https://github.com/element-hq/element-x-android/blob/develop/CONTRIBUTING.md#accessibility
- [ ] Pull request is based on the develop branch - [ ] Pull request is based on the develop branch
- [ ] Pull request includes a new file under ./changelog.d. See https://github.com/vector-im/element-x-android/blob/develop/CONTRIBUTING.md#changelog - [ ] Pull request includes a new file under ./changelog.d. See https://github.com/element-hq/element-x-android/blob/develop/CONTRIBUTING.md#changelog
- [ ] Pull request includes screenshots or videos if containing UI changes - [ ] Pull request includes screenshots or videos if containing UI changes
- [ ] Pull request includes a [sign off](https://matrix-org.github.io/synapse/latest/development/contributing_guide.html#sign-off) - [ ] Pull request includes a [sign off](https://matrix-org.github.io/synapse/latest/development/contributing_guide.html#sign-off)
- [ ] You've made a self review of your PR - [ ] You've made a self review of your PR

View file

@ -33,12 +33,12 @@ jobs:
# 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 }}
- name: Use JDK 17 - name: Use JDK 17
uses: actions/setup-java@v3 uses: actions/setup-java@v4
with: with:
distribution: 'temurin' # See 'Supported distributions' for available options distribution: 'temurin' # See 'Supported distributions' for available options
java-version: '17' java-version: '17'
- name: Configure gradle - name: Configure gradle
uses: gradle/gradle-build-action@v2.9.0 uses: gradle/gradle-build-action@v2.11.1
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
@ -50,7 +50,7 @@ jobs:
run: ./gradlew :app:assembleDebug -PallWarningsAsErrors=true $CI_GRADLE_ARG_PROPERTIES run: ./gradlew :app:assembleDebug -PallWarningsAsErrors=true $CI_GRADLE_ARG_PROPERTIES
- name: Upload APK APKs - name: Upload APK APKs
if: ${{ matrix.variant == 'debug' }} if: ${{ matrix.variant == 'debug' }}
uses: actions/upload-artifact@v3 uses: actions/upload-artifact@v4
with: with:
name: elementx-debug name: elementx-debug
path: | path: |

View file

@ -11,7 +11,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@11.3.0 uses: danger/danger-js@11.3.1
with: with:
args: "--dangerfile ./tools/danger/dangerfile.js" args: "--dangerfile ./tools/danger/dangerfile.js"
env: env:

View file

@ -12,7 +12,7 @@ jobs:
- name: Update Gradle Wrapper - name: Update Gradle Wrapper
uses: gradle-update/update-gradle-wrapper-action@v1 uses: gradle-update/update-gradle-wrapper-action@v1
# Skip in forks # Skip in forks
if: github.repository == 'vector-im/element-x-android' if: github.repository == 'element-hq/element-x-android'
with: with:
repo-token: ${{ secrets.GITHUB_TOKEN }} repo-token: ${{ secrets.GITHUB_TOKEN }}
target-branch: develop target-branch: develop

View file

@ -1,11 +1,10 @@
name: Maestro name: Maestro
# Run this flow only on pull request, and only when the pull request has been approved, to limit our usage of maestro cloud. # Run this flow only on pull request, and only when the pull request has the Run-Maestro label, to limit our usage of maestro cloud.
# https://docs.github.com/en/actions/using-workflows/events-that-trigger-workflows#running-a-workflow-when-a-pull-request-is-approved
on: on:
workflow_dispatch: workflow_dispatch:
pull_request_review: pull_request:
types: [submitted] types: [labeled]
# Enrich gradle.properties for CI/CD # Enrich gradle.properties for CI/CD
env: env:
@ -16,7 +15,7 @@ jobs:
maestro-cloud: maestro-cloud:
name: Maestro test suite name: Maestro test suite
runs-on: ubuntu-latest runs-on: ubuntu-latest
if: github.event.review.state == 'approved' || github.event_name == 'workflow_dispatch' if: github.event_name == 'workflow_dispatch' || github.event.label.name == 'Run-Maestro'
strategy: strategy:
fail-fast: false fail-fast: false
# Allow one per PR. # Allow one per PR.
@ -24,12 +23,17 @@ jobs:
group: ${{ format('maestro-{0}', github.ref) }} group: ${{ format('maestro-{0}', github.ref) }}
cancel-in-progress: true cancel-in-progress: true
steps: steps:
- name: Remove Run-Maestro label
if: ${{ github.event.label.name == 'Run-Maestro' }}
uses: actions-ecosystem/action-remove-labels@v1
with:
labels: Run-Maestro
- uses: actions/checkout@v4 - uses: actions/checkout@v4
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 }}
- uses: actions/setup-java@v3 - uses: actions/setup-java@v4
name: Use JDK 17 name: Use JDK 17
with: with:
distribution: 'temurin' # See 'Supported distributions' for available options distribution: 'temurin' # See 'Supported distributions' for available options

View file

@ -14,11 +14,11 @@ jobs:
nightly: nightly:
name: Build and publish nightly bundle to Firebase name: Build and publish nightly bundle to Firebase
runs-on: ubuntu-latest runs-on: ubuntu-latest
if: ${{ github.repository == 'vector-im/element-x-android' }} if: ${{ github.repository == 'element-hq/element-x-android' }}
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
- name: Use JDK 17 - name: Use JDK 17
uses: actions/setup-java@v3 uses: actions/setup-java@v4
with: with:
distribution: 'temurin' # See 'Supported distributions' for available options distribution: 'temurin' # See 'Supported distributions' for available options
java-version: '17' java-version: '17'

View file

@ -15,13 +15,13 @@ jobs:
nightlyReports: nightlyReports:
name: Create kover report artifact and upload sonar result. name: Create kover report artifact and upload sonar result.
runs-on: ubuntu-latest runs-on: ubuntu-latest
if: ${{ github.repository == 'vector-im/element-x-android' }} if: ${{ github.repository == 'element-hq/element-x-android' }}
steps: steps:
- name: ⏬ Checkout with LFS - name: ⏬ Checkout with LFS
uses: nschloe/action-cached-lfs-checkout@v1.2.2 uses: nschloe/action-cached-lfs-checkout@v1.2.2
- name: Use JDK 17 - name: Use JDK 17
uses: actions/setup-java@v3 uses: actions/setup-java@v4
with: with:
distribution: 'temurin' # See 'Supported distributions' for available options distribution: 'temurin' # See 'Supported distributions' for available options
java-version: '17' java-version: '17'
@ -37,7 +37,7 @@ jobs:
- name: ✅ Upload kover report - name: ✅ Upload kover report
if: always() if: always()
uses: actions/upload-artifact@v3 uses: actions/upload-artifact@v4
with: with:
name: kover-results name: kover-results
path: | path: |
@ -57,19 +57,19 @@ jobs:
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
- name: Use JDK 17 - name: Use JDK 17
uses: actions/setup-java@v3 uses: actions/setup-java@v4
with: with:
distribution: 'temurin' # See 'Supported distributions' for available options distribution: 'temurin' # See 'Supported distributions' for available options
java-version: '17' java-version: '17'
- name: Configure gradle - name: Configure gradle
uses: gradle/gradle-build-action@v2.9.0 uses: gradle/gradle-build-action@v2.11.1
with: with:
cache-read-only: ${{ github.ref != 'refs/heads/develop' }} cache-read-only: ${{ github.ref != 'refs/heads/develop' }}
- name: Dependency analysis - name: Dependency analysis
run: ./gradlew dependencyCheckAnalyze $CI_GRADLE_ARG_PROPERTIES run: ./gradlew dependencyCheckAnalyze $CI_GRADLE_ARG_PROPERTIES
- name: Upload dependency analysis - name: Upload dependency analysis
if: always() if: always()
uses: actions/upload-artifact@v3 uses: actions/upload-artifact@v4
with: with:
name: dependency-analysis name: dependency-analysis
path: build/reports/dependency-check-report.html path: build/reports/dependency-check-report.html

View file

@ -35,19 +35,19 @@ jobs:
# 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 }}
- name: Use JDK 17 - name: Use JDK 17
uses: actions/setup-java@v3 uses: actions/setup-java@v4
with: with:
distribution: 'temurin' # See 'Supported distributions' for available options distribution: 'temurin' # See 'Supported distributions' for available options
java-version: '17' java-version: '17'
- name: Configure gradle - name: Configure gradle
uses: gradle/gradle-build-action@v2.9.0 uses: gradle/gradle-build-action@v2.11.1
with: with:
cache-read-only: ${{ github.ref != 'refs/heads/develop' }} cache-read-only: ${{ github.ref != 'refs/heads/develop' }}
- name: Run code quality check suite - name: Run code quality check suite
run: ./gradlew runQualityChecks $CI_GRADLE_ARG_PROPERTIES run: ./gradlew runQualityChecks $CI_GRADLE_ARG_PROPERTIES
- name: Upload reports - name: Upload reports
if: always() if: always()
uses: actions/upload-artifact@v3 uses: actions/upload-artifact@v4
with: with:
name: linting-report name: linting-report
path: | path: |
@ -60,7 +60,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@11.3.0 uses: danger/danger-js@11.3.1
with: with:
args: "--dangerfile ./tools/danger/dangerfile-lint.js" args: "--dangerfile ./tools/danger/dangerfile-lint.js"
env: env:

View file

@ -2,6 +2,8 @@ name: Record screenshots
on: on:
workflow_dispatch: workflow_dispatch:
pull_request:
types: [ labeled ]
# Enrich gradle.properties for CI/CD # Enrich gradle.properties for CI/CD
env: env:
@ -9,26 +11,39 @@ env:
jobs: jobs:
record: record:
name: Record screenshots on branch ${{ github.ref_name }} name: Record screenshots on branch ${{ github.event.pull_request.head.ref || github.ref_name }}
runs-on: ubuntu-latest runs-on: ubuntu-latest
if: github.event_name == 'workflow_dispatch' || github.event.label.name == 'Record-Screenshots'
steps: steps:
- name: ⏬ Checkout with LFS - name: Remove Record-Screenshots label
if: github.event.label.name == 'Record-Screenshots'
uses: actions-ecosystem/action-remove-labels@v1
with:
labels: Record-Screenshots
- name: ⏬ Checkout with LFS (PR)
if: github.event.label.name == 'Record-Screenshots'
uses: nschloe/action-cached-lfs-checkout@v1.2.2
with:
persist-credentials: false
ref: ${{ github.event.pull_request.head.ref }}
- name: ⏬ Checkout with LFS (Branch)
if: github.event_name == 'workflow_dispatch'
uses: nschloe/action-cached-lfs-checkout@v1.2.2 uses: nschloe/action-cached-lfs-checkout@v1.2.2
with: with:
persist-credentials: false persist-credentials: false
- name: ☕️ Use JDK 17 - name: ☕️ Use JDK 17
uses: actions/setup-java@v3 uses: actions/setup-java@v4
with: with:
distribution: 'temurin' # See 'Supported distributions' for available options distribution: 'temurin' # See 'Supported distributions' for available options
java-version: '17' java-version: '17'
# 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/gradle-build-action@v2.9.0 uses: gradle/gradle-build-action@v2.11.1
with: with:
cache-read-only: ${{ github.ref != 'refs/heads/develop' }} cache-read-only: ${{ github.ref != 'refs/heads/develop' }}
- name: Record screenshots - name: Record screenshots
run: "./.github/workflows/scripts/recordScreenshots.sh" run: ./.github/workflows/scripts/recordScreenshots.sh
env: env:
GITHUB_TOKEN: ${{ secrets.DANGER_GITHUB_API_TOKEN }} GITHUB_TOKEN: ${{ secrets.DANGER_GITHUB_API_TOKEN }}
GITHUB_REPOSITORY: ${{ secrets.GITHUB_REPOSITORY }} GITHUB_REPOSITORY: ${{ secrets.GITHUB_REPOSITORY }}

View file

@ -20,12 +20,12 @@ jobs:
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
- name: Use JDK 17 - name: Use JDK 17
uses: actions/setup-java@v3 uses: actions/setup-java@v4
with: with:
distribution: 'temurin' # See 'Supported distributions' for available options distribution: 'temurin' # See 'Supported distributions' for available options
java-version: '17' java-version: '17'
- name: Configure gradle - name: Configure gradle
uses: gradle/gradle-build-action@v2.9.0 uses: gradle/gradle-build-action@v2.11.1
- 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 }}
@ -33,7 +33,7 @@ jobs:
ELEMENT_ANDROID_MAPTILER_DARK_MAP_ID: ${{ secrets.MAPTILER_DARK_MAP_ID }} ELEMENT_ANDROID_MAPTILER_DARK_MAP_ID: ${{ secrets.MAPTILER_DARK_MAP_ID }}
run: ./gradlew bundleRelease $CI_GRADLE_ARG_PROPERTIES run: ./gradlew bundleRelease $CI_GRADLE_ARG_PROPERTIES
- name: Upload bundle as artifact - name: Upload bundle as artifact
uses: actions/upload-artifact@v3 uses: actions/upload-artifact@v4
with: with:
name: elementx-app-bundle-unsigned name: elementx-app-bundle-unsigned
path: | path: |

View file

@ -48,6 +48,9 @@ do
esac esac
done done
BRANCH=$(git rev-parse --abbrev-ref HEAD)
echo Branch used: $BRANCH
if [[ -z ${TOKEN} ]]; then if [[ -z ${TOKEN} ]]; then
echo "No token specified, either set the env var GITHUB_TOKEN or use the --token option" echo "No token specified, either set the env var GITHUB_TOKEN or use the --token option"
exit 1 exit 1
@ -70,8 +73,6 @@ git config user.email "benoitm+elementbot@element.io"
git add -A git add -A
git commit -m "Update screenshots" git commit -m "Update screenshots"
BRANCH=$(git rev-parse --abbrev-ref HEAD)
echo "Pushing changes" echo "Pushing changes"
git push "https://$TOKEN@github.com/$REPO.git" $BRANCH:refs/heads/$BRANCH git push "https://$TOKEN@github.com/$REPO.git" $BRANCH
echo "Done!" echo "Done!"

View file

@ -27,12 +27,12 @@ jobs:
# 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 }}
- name: Use JDK 17 - name: Use JDK 17
uses: actions/setup-java@v3 uses: actions/setup-java@v4
with: with:
distribution: 'temurin' # See 'Supported distributions' for available options distribution: 'temurin' # See 'Supported distributions' for available options
java-version: '17' java-version: '17'
- name: Configure gradle - name: Configure gradle
uses: gradle/gradle-build-action@v2.9.0 uses: gradle/gradle-build-action@v2.11.1
with: with:
cache-read-only: ${{ github.ref != 'refs/heads/develop' }} cache-read-only: ${{ github.ref != 'refs/heads/develop' }}
- name: 🔊 Publish results to Sonar - name: 🔊 Publish results to Sonar

View file

@ -9,11 +9,11 @@ jobs:
sync-localazy: sync-localazy:
runs-on: ubuntu-latest runs-on: ubuntu-latest
# Skip in forks # Skip in forks
if: github.repository == 'vector-im/element-x-android' if: github.repository == 'element-hq/element-x-android'
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
- name: Set up Python 3.9 - name: Set up Python 3.9
uses: actions/setup-python@v4 uses: actions/setup-python@v5
with: with:
python-version: 3.9 python-version: 3.9
- name: Setup Localazy - name: Setup Localazy

35
.github/workflows/sync-sas-strings.yml vendored Normal file
View file

@ -0,0 +1,35 @@
name: Sync SAS strings
on:
workflow_dispatch:
schedule:
# At 00:00 on every Monday UTC
- cron: '0 0 * * 1'
jobs:
sync-sas-strings:
runs-on: ubuntu-latest
# Skip in forks
if: github.repository == 'element-hq/element-x-android'
# No concurrency required, runs every time on a schedule.
steps:
- uses: actions/checkout@v4
- name: Set up Python 3.8
uses: actions/setup-python@v5
with:
python-version: 3.9
- name: Install Prerequisite dependencies
run: |
pip install requests
- name: Run SAS String script
run: ./tools/sas/import_sas_strings.py
- name: Create Pull Request for SAS Strings
uses: peter-evans/create-pull-request@v5
with:
commit-message: Sync SAS Strings
title: Sync SAS Strings
body: |
- Update SAS Strings from matrix-doc.
branch: sync-sas-strings
base: develop

View file

@ -39,12 +39,12 @@ jobs:
# 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 }}
- name: ☕️ Use JDK 17 - name: ☕️ Use JDK 17
uses: actions/setup-java@v3 uses: actions/setup-java@v4
with: with:
distribution: 'temurin' # See 'Supported distributions' for available options distribution: 'temurin' # See 'Supported distributions' for available options
java-version: '17' java-version: '17'
- name: Configure gradle - name: Configure gradle
uses: gradle/gradle-build-action@v2.9.0 uses: gradle/gradle-build-action@v2.11.1
with: with:
cache-read-only: ${{ github.ref != 'refs/heads/develop' }} cache-read-only: ${{ github.ref != 'refs/heads/develop' }}
@ -59,7 +59,7 @@ jobs:
- name: 🚫 Upload kover failed coverage reports - name: 🚫 Upload kover failed coverage reports
if: failure() if: failure()
uses: actions/upload-artifact@v3 uses: actions/upload-artifact@v4
with: with:
name: kover-error-report name: kover-error-report
path: | path: |
@ -71,7 +71,7 @@ jobs:
- name: 🚫 Upload test results on error - name: 🚫 Upload test results on error
if: failure() if: failure()
uses: actions/upload-artifact@v3 uses: actions/upload-artifact@v4
with: with:
name: tests-and-screenshot-tests-results name: tests-and-screenshot-tests-results
path: | path: |

View file

@ -10,5 +10,5 @@ jobs:
steps: steps:
- uses: actions/add-to-project@main - uses: actions/add-to-project@main
with: with:
project-url: https://github.com/orgs/vector-im/projects/91 project-url: https://github.com/orgs/element-hq/projects/91
github-token: ${{ secrets.ELEMENT_BOT_TOKEN }} github-token: ${{ secrets.ELEMENT_BOT_TOKEN }}

View file

@ -10,11 +10,11 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
# Skip in forks # Skip in forks
if: > if: >
github.repository == 'vector-im/element-x-android' github.repository == 'element-hq/element-x-android'
steps: steps:
- uses: actions/add-to-project@main - uses: actions/add-to-project@main
with: with:
project-url: https://github.com/orgs/vector-im/projects/43 project-url: https://github.com/orgs/element-hq/projects/43
github-token: ${{ secrets.ELEMENT_BOT_TOKEN }} github-token: ${{ secrets.ELEMENT_BOT_TOKEN }}
move_needs_info: move_needs_info:
@ -24,7 +24,7 @@ jobs:
- uses: actions/add-to-project@main - uses: actions/add-to-project@main
id: addItem id: addItem
with: with:
project-url: https://github.com/orgs/vector-im/projects/91 project-url: https://github.com/orgs/element-hq/projects/91
github-token: ${{ secrets.ELEMENT_BOT_TOKEN }} github-token: ${{ secrets.ELEMENT_BOT_TOKEN }}
labeled: X-Needs-Info labeled: X-Needs-Info
- name: Print itemId - name: Print itemId
@ -32,7 +32,7 @@ jobs:
- uses: kalgurn/update-project-item-status@main - uses: kalgurn/update-project-item-status@main
if: ${{ steps.addItem.outputs.itemId }} if: ${{ steps.addItem.outputs.itemId }}
with: with:
project-url: https://github.com/orgs/vector-im/projects/91 project-url: https://github.com/orgs/element-hq/projects/91
github-token: ${{ secrets.ELEMENT_BOT_TOKEN }} github-token: ${{ secrets.ELEMENT_BOT_TOKEN }}
item-id: ${{ steps.addItem.outputs.itemId }} item-id: ${{ steps.addItem.outputs.itemId }}
status: "Needs info" status: "Needs info"
@ -45,7 +45,7 @@ jobs:
steps: steps:
- uses: actions/add-to-project@main - uses: actions/add-to-project@main
with: with:
project-url: https://github.com/orgs/vector-im/projects/73 project-url: https://github.com/orgs/element-hq/projects/73
github-token: ${{ secrets.ELEMENT_BOT_TOKEN }} github-token: ${{ secrets.ELEMENT_BOT_TOKEN }}
verticals_feature: verticals_feature:
@ -56,7 +56,7 @@ jobs:
steps: steps:
- uses: actions/add-to-project@main - uses: actions/add-to-project@main
with: with:
project-url: https://github.com/orgs/vector-im/projects/57 project-url: https://github.com/orgs/element-hq/projects/57
github-token: ${{ secrets.ELEMENT_BOT_TOKEN }} github-token: ${{ secrets.ELEMENT_BOT_TOKEN }}
qa: qa:
@ -68,7 +68,7 @@ jobs:
steps: steps:
- uses: actions/add-to-project@main - uses: actions/add-to-project@main
with: with:
project-url: https://github.com/orgs/vector-im/projects/69 project-url: https://github.com/orgs/element-hq/projects/69
github-token: ${{ secrets.ELEMENT_BOT_TOKEN }} github-token: ${{ secrets.ELEMENT_BOT_TOKEN }}
signoff: signoff:
@ -79,5 +79,5 @@ jobs:
steps: steps:
- uses: actions/add-to-project@main - uses: actions/add-to-project@main
with: with:
project-url: https://github.com/orgs/vector-im/projects/89 project-url: https://github.com/orgs/element-hq/projects/89
github-token: ${{ secrets.ELEMENT_BOT_TOKEN }} github-token: ${{ secrets.ELEMENT_BOT_TOKEN }}

2
.gitignore vendored
View file

@ -94,3 +94,5 @@ lint/tmp/
/tmp /tmp
.DS_Store .DS_Store
checkouts/**

View file

@ -2,6 +2,7 @@
<dictionary name="shared"> <dictionary name="shared">
<words> <words>
<w>backstack</w> <w>backstack</w>
<w>blurhash</w>
<w>ftue</w> <w>ftue</w>
<w>homeserver</w> <w>homeserver</w>
<w>konsist</w> <w>konsist</w>

2
.idea/kotlinc.xml generated
View file

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

10
.idea/migrations.xml generated Normal file
View file

@ -0,0 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectMigrations">
<option name="MigrateToGradleLocalJavaHome">
<set>
<option value="$PROJECT_DIR$" />
</set>
</option>
</component>
</project>

View file

@ -9,13 +9,10 @@ appId: ${APP_ID}
- tapOn: "Other" - tapOn: "Other"
- tapOn: - tapOn:
id: "change_server-server" id: "change_server-server"
# Test server that does not support sliding sync. - inputText: "element"
- inputText: "https://kieranml.ems-support.element.dev"
- hideKeyboard - hideKeyboard
- tapOn: "kieranml.ems-support.element.dev" - tapOn: "element.io"
- extendedWaitUntil: # Revert to matrix.org
visible: "This server currently doesnt support sliding sync." - tapOn:
timeout: 10000 id: "login-change_server"
- tapOn: "Cancel" - tapOn: "matrix.org"
- back
- back

View file

@ -23,7 +23,7 @@ appId: ${APP_ID}
- tapOn: - tapOn:
text: ${INVITEE2_MXID} text: ${INVITEE2_MXID}
index: 1 index: 1
- tapOn: "Send" - tapOn: "Invite"
- tapOn: "Back" - tapOn: "Back"
- tapOn: "aRoomName" - tapOn: "aRoomName"
- tapOn: "People" - tapOn: "People"

View file

@ -1,4 +1,4 @@
A full developer contributors list can be found [here](https://github.com/vector-im/element-x-android/graphs/contributors). A full developer contributors list can be found [here](https://github.com/element-hq/element-x-android/graphs/contributors).
# Core team: # Core team:

View file

@ -1,23 +1,74 @@
Changes in Element X v0.4.0 (2023-12-22)
========================================
Features ✨
----------
- Use the RTE library `TextView` to render text events in the timeline. Add support for mention pills - with no interaction yet. ([#1433](https://github.com/element-hq/element-x-android/issues/1433))
- Tapping on a user mention pill opens their profile. ([#1448](https://github.com/element-hq/element-x-android/issues/1448))
- Display different notifications for mentions. ([#1451](https://github.com/element-hq/element-x-android/issues/1451))
- Reply to a poll ([#1848](https://github.com/element-hq/element-x-android/issues/1848))
- Add plain text representation of messages ([#1850](https://github.com/element-hq/element-x-android/issues/1850))
- Allow polls to be edited when they have not been voted on ([#1869](https://github.com/element-hq/element-x-android/issues/1869))
- Scroll to end of timeline when sending a new message. ([#1877](https://github.com/element-hq/element-x-android/issues/1877))
- Confirm back navigation when editing a poll only if the poll was changed ([#1886](https://github.com/element-hq/element-x-android/issues/1886))
- Add option to delete a poll while editing the poll ([#1895](https://github.com/element-hq/element-x-android/issues/1895))
- Open room member avatar when you click on it inside the member details screen. ([#1907](https://github.com/element-hq/element-x-android/issues/1907))
- Poll history of a room is now accessible from the room details screen. ([#2014](https://github.com/element-hq/element-x-android/issues/2014))
- Always close the invite list screen when there is no more invite. ([#2022](https://github.com/element-hq/element-x-android/issues/2022))
Bugfixes 🐛
----------
- Fix see room in the room list after leaving it. ([#1006](https://github.com/element-hq/element-x-android/issues/1006))
- Adjust mention pills font weight and horizontal padding ([#1449](https://github.com/element-hq/element-x-android/issues/1449))
- Font size in 'All Chats' header was changing mid-animation. ([#1572](https://github.com/element-hq/element-x-android/issues/1572))
- Accessibility: do not read initial used for avatar out loud. ([#1864](https://github.com/element-hq/element-x-android/issues/1864))
- Use the right avatar for DMs in DM rooms ([#1912](https://github.com/element-hq/element-x-android/issues/1912))
- Fix scaling of timeline images: don't crop, don't set min/max aspect ratio values. ([#1940](https://github.com/element-hq/element-x-android/issues/1940))
- Fix rendering of user name with vertical text by clipping the text. ([#1950](https://github.com/element-hq/element-x-android/issues/1950))
- Do not render `roomId` if the room has no canonical alias. ([#1970](https://github.com/element-hq/element-x-android/issues/1970))
- Fix avatar not displayed in notification when the app is not in background ([#1991](https://github.com/element-hq/element-x-android/issues/1991))
- Fix wording in room invite members view: `Send` -> `Invite`. ([#2037](https://github.com/element-hq/element-x-android/issues/2037))
- Timestamp positioning was broken, specially for edited messages. ([#2060](https://github.com/element-hq/element-x-android/issues/2060))
- Emojis in custom reaction bottom sheet are too tiny. ([#2066](https://github.com/element-hq/element-x-android/issues/2066))
- Set a default power level to join calls. Also, create new rooms taking this power level into account.
Other changes
-------------
- Add a warning for 'mentions and keywords only' notification option if your homeserver does not support it ([#1749](https://github.com/element-hq/element-x-android/issues/1749))
- Remove `:libraries:theme` module, extract theme and tokens to [Compound Android](https://github.com/element-hq/compound-android). ([#1833](https://github.com/element-hq/element-x-android/issues/1833))
- Update poll icons from Compound ([#1849](https://github.com/element-hq/element-x-android/issues/1849))
- Add ability to see the room avatar in the media viewer. ([#1918](https://github.com/element-hq/element-x-android/issues/1918))
- RoomList: introduce incremental loading to improve performances. ([#1920](https://github.com/element-hq/element-x-android/issues/1920))
- Add toggle in the notification settings to disable notifications for room invites. ([#1944](https://github.com/element-hq/element-x-android/issues/1944))
- Update rendering of Emojis displayed during verification. ([#1965](https://github.com/element-hq/element-x-android/issues/1965))
- Hide sender info in direct rooms ([#1979](https://github.com/element-hq/element-x-android/issues/1979))
- Render images in Notification ([#1991](https://github.com/element-hq/element-x-android/issues/1991))
- Only process content.json from Localazy. ([#2031](https://github.com/element-hq/element-x-android/issues/2031))
- Always show user avatar in message action sheet ([#2032](https://github.com/element-hq/element-x-android/issues/2032))
- Hide room list dropdown menu. ([#2062](https://github.com/element-hq/element-x-android/issues/2062))
- Enable Chat backup, Mentions and Read Receipt in release. ([#2087](https://github.com/element-hq/element-x-android/issues/2087))
- Make most code used in Compose from `:libraries:matrix` and derived classes Immutable or Stable.
Changes in Element X v0.3.2 (2023-11-22) Changes in Element X v0.3.2 (2023-11-22)
======================================== ========================================
Features ✨ Features ✨
---------- ----------
- Add ongoing call indicator to rooms lists items. ([#1158](https://github.com/vector-im/element-x-android/issues/1158)) - Add ongoing call indicator to rooms lists items. ([#1158](https://github.com/element-hq/element-x-android/issues/1158))
- Add support for typing mentions in the message composer. ([#1453](https://github.com/vector-im/element-x-android/issues/1453)) - Add support for typing mentions in the message composer. ([#1453](https://github.com/element-hq/element-x-android/issues/1453))
- Add intentional mentions to messages. This needs to be enabled in developer options since it's disabled by default. ([#1591](https://github.com/vector-im/element-x-android/issues/1591)) - Add intentional mentions to messages. This needs to be enabled in developer options since it's disabled by default. ([#1591](https://github.com/element-hq/element-x-android/issues/1591))
- Update voice message recording behaviour. Instead of holding the record button, users can now tap the record button to start recording and tap again to stop recording. ([#1784](https://github.com/vector-im/element-x-android/issues/1784)) - Update voice message recording behaviour. Instead of holding the record button, users can now tap the record button to start recording and tap again to stop recording. ([#1784](https://github.com/element-hq/element-x-android/issues/1784))
Bugfixes 🐛 Bugfixes 🐛
---------- ----------
- Always ensure media temp dir exists ([#1790](https://github.com/vector-im/element-x-android/issues/1790)) - Always ensure media temp dir exists ([#1790](https://github.com/element-hq/element-x-android/issues/1790))
Other changes Other changes
------------- -------------
- Update icons and move away from `PreferenceText` components. ([#1718](https://github.com/vector-im/element-x-android/issues/1718)) - Update icons and move away from `PreferenceText` components. ([#1718](https://github.com/element-hq/element-x-android/issues/1718))
- Add item "This is the beginning of..." at the beginning of the timeline. ([#1801](https://github.com/vector-im/element-x-android/issues/1801)) - Add item "This is the beginning of..." at the beginning of the timeline. ([#1801](https://github.com/element-hq/element-x-android/issues/1801))
- LockScreen : rework LoggedInFlowNode and back management when locked. ([#1806](https://github.com/vector-im/element-x-android/issues/1806)) - LockScreen : rework LoggedInFlowNode and back management when locked. ([#1806](https://github.com/element-hq/element-x-android/issues/1806))
- Suppress usage of removeTimeline method. ([#1824](https://github.com/vector-im/element-x-android/issues/1824)) - Suppress usage of removeTimeline method. ([#1824](https://github.com/element-hq/element-x-android/issues/1824))
- Remove Element Call feature flag, it's now always enabled. - Remove Element Call feature flag, it's now always enabled.
- Reverted the EC base URL to `https://call.element.io`. - Reverted the EC base URL to `https://call.element.io`.
- Moved the option to override this URL to developer settings from advanced settings. - Moved the option to override this URL to developer settings from advanced settings.
@ -28,16 +79,16 @@ Changes in Element X v0.3.1 (2023-11-09)
Features ✨ Features ✨
---------- ----------
- Chat backup is still under a feature flag, but when enabled, user can enter their recovery key (it's also possible to input a passphrase) to unlock the encrypted room history. ([#1770](https://github.com/vector-im/element-x-android/pull/1770)) - Chat backup is still under a feature flag, but when enabled, user can enter their recovery key (it's also possible to input a passphrase) to unlock the encrypted room history. ([#1770](https://github.com/element-hq/element-x-android/pull/1770))
Bugfixes 🐛 Bugfixes 🐛
---------- ----------
- Improve confusing text in the 'ready to start verification' screen. ([#879](https://github.com/vector-im/element-x-android/issues/879)) - Improve confusing text in the 'ready to start verification' screen. ([#879](https://github.com/element-hq/element-x-android/issues/879))
- Message composer wasn't resized when selecting a several lines message to reply to, then a single line one. ([#1560](https://github.com/vector-im/element-x-android/issues/1560)) - Message composer wasn't resized when selecting a several lines message to reply to, then a single line one. ([#1560](https://github.com/element-hq/element-x-android/issues/1560))
Other changes Other changes
------------- -------------
- PIN: Set lock grace period to 0. ([#1732](https://github.com/vector-im/element-x-android/issues/1732)) - PIN: Set lock grace period to 0. ([#1732](https://github.com/element-hq/element-x-android/issues/1732))
Changes in Element X v0.3.0 (2023-10-31) Changes in Element X v0.3.0 (2023-10-31)
@ -45,24 +96,24 @@ Changes in Element X v0.3.0 (2023-10-31)
Features ✨ Features ✨
---------- ----------
- Element Call: change the 'join call' button in a chat room when there's an active call. ([#1158](https://github.com/vector-im/element-x-android/issues/1158)) - Element Call: change the 'join call' button in a chat room when there's an active call. ([#1158](https://github.com/element-hq/element-x-android/issues/1158))
- Mentions: add mentions suggestion view in RTE ([#1452](https://github.com/vector-im/element-x-android/issues/1452)) - Mentions: add mentions suggestion view in RTE ([#1452](https://github.com/element-hq/element-x-android/issues/1452))
- Record and send voice messages ([#1596](https://github.com/vector-im/element-x-android/issues/1596)) - Record and send voice messages ([#1596](https://github.com/element-hq/element-x-android/issues/1596))
- Enable voice messages for all users ([#1669](https://github.com/vector-im/element-x-android/issues/1669)) - Enable voice messages for all users ([#1669](https://github.com/element-hq/element-x-android/issues/1669))
- Receive and play a voice message ([#2084](https://github.com/vector-im/element-x-android/issues/2084)) - Receive and play a voice message ([#2084](https://github.com/element-hq/element-x-android/issues/2084))
- Enable Element Call integration in rooms by default, fix several issues when creating or joining calls. - Enable Element Call integration in rooms by default, fix several issues when creating or joining calls.
Bugfixes 🐛 Bugfixes 🐛
---------- ----------
- Group fallback notification to avoid having plenty of them displayed. ([#994](https://github.com/vector-im/element-x-android/issues/994)) - Group fallback notification to avoid having plenty of them displayed. ([#994](https://github.com/element-hq/element-x-android/issues/994))
- Hide keyboard when exiting the chat room screen. ([#1375](https://github.com/vector-im/element-x-android/issues/1375)) - Hide keyboard when exiting the chat room screen. ([#1375](https://github.com/element-hq/element-x-android/issues/1375))
- Always register the pusher when application starts ([#1481](https://github.com/vector-im/element-x-android/issues/1481)) - Always register the pusher when application starts ([#1481](https://github.com/element-hq/element-x-android/issues/1481))
- Ensure screen does not turn off when playing a video ([#1519](https://github.com/vector-im/element-x-android/issues/1519)) - Ensure screen does not turn off when playing a video ([#1519](https://github.com/element-hq/element-x-android/issues/1519))
- Fix issue where text is cleared when cancelling a reply ([#1617](https://github.com/vector-im/element-x-android/issues/1617)) - Fix issue where text is cleared when cancelling a reply ([#1617](https://github.com/element-hq/element-x-android/issues/1617))
Other changes Other changes
------------- -------------
- Remove usage of blocking methods. ([#1563](https://github.com/vector-im/element-x-android/issues/1563)) - Remove usage of blocking methods. ([#1563](https://github.com/element-hq/element-x-android/issues/1563))
Changes in Element X v0.2.4 (2023-10-12) Changes in Element X v0.2.4 (2023-10-12)
@ -70,20 +121,20 @@ Changes in Element X v0.2.4 (2023-10-12)
Features ✨ Features ✨
---------- ----------
- [Rich text editor] Add full screen mode ([#1447](https://github.com/vector-im/element-x-android/issues/1447)) - [Rich text editor] Add full screen mode ([#1447](https://github.com/element-hq/element-x-android/issues/1447))
- Improve rendering of m.emote. ([#1497](https://github.com/vector-im/element-x-android/issues/1497)) - Improve rendering of m.emote. ([#1497](https://github.com/element-hq/element-x-android/issues/1497))
- Improve deleted session behavior. ([#1520](https://github.com/vector-im/element-x-android/issues/1520)) - Improve deleted session behavior. ([#1520](https://github.com/element-hq/element-x-android/issues/1520))
Bugfixes 🐛 Bugfixes 🐛
---------- ----------
- WebP images can't be sent as media. ([#1483](https://github.com/vector-im/element-x-android/issues/1483)) - WebP images can't be sent as media. ([#1483](https://github.com/element-hq/element-x-android/issues/1483))
- Fix back button not working in bottom sheets. ([#1517](https://github.com/vector-im/element-x-android/issues/1517)) - Fix back button not working in bottom sheets. ([#1517](https://github.com/element-hq/element-x-android/issues/1517))
- Render body of unknown msgtype in the timeline and in the room list ([#1539](https://github.com/vector-im/element-x-android/issues/1539)) - Render body of unknown msgtype in the timeline and in the room list ([#1539](https://github.com/element-hq/element-x-android/issues/1539))
Other changes Other changes
------------- -------------
- Room : makes subscribeToSync/unsubscribeFromSync suspendable. ([#1457](https://github.com/vector-im/element-x-android/issues/1457)) - Room : makes subscribeToSync/unsubscribeFromSync suspendable. ([#1457](https://github.com/element-hq/element-x-android/issues/1457))
- Add some Konsist tests. ([#1526](https://github.com/vector-im/element-x-android/issues/1526)) - Add some Konsist tests. ([#1526](https://github.com/element-hq/element-x-android/issues/1526))
Changes in Element X v0.2.3 (2023-09-27) Changes in Element X v0.2.3 (2023-09-27)
@ -91,12 +142,12 @@ Changes in Element X v0.2.3 (2023-09-27)
Features ✨ Features ✨
---------- ----------
- Handle installation of Apks from the media viewer. ([#1432](https://github.com/vector-im/element-x-android/pull/1432)) - Handle installation of Apks from the media viewer. ([#1432](https://github.com/element-hq/element-x-android/pull/1432))
- Integrate SDK 0.1.58 ([#1437](https://github.com/vector-im/element-x-android/pull/1437)) - Integrate SDK 0.1.58 ([#1437](https://github.com/element-hq/element-x-android/pull/1437))
Other changes Other changes
------------- -------------
- Element call: add custom parameters to Element Call urls. ([#1434](https://github.com/vector-im/element-x-android/issues/1434)) - Element call: add custom parameters to Element Call urls. ([#1434](https://github.com/element-hq/element-x-android/issues/1434))
Changes in Element X v0.2.2 (2023-09-21) Changes in Element X v0.2.2 (2023-09-21)
@ -104,8 +155,8 @@ Changes in Element X v0.2.2 (2023-09-21)
Bugfixes 🐛 Bugfixes 🐛
---------- ----------
- Add animation when rendering the timeline to avoid glitches. ([#1323](https://github.com/vector-im/element-x-android/issues/1323)) - Add animation when rendering the timeline to avoid glitches. ([#1323](https://github.com/element-hq/element-x-android/issues/1323))
- Fix crash when trying to take a photo or record a video. ([#1395](https://github.com/vector-im/element-x-android/issues/1395)) - Fix crash when trying to take a photo or record a video. ([#1395](https://github.com/element-hq/element-x-android/issues/1395))
Changes in Element X v0.2.1 (2023-09-20) Changes in Element X v0.2.1 (2023-09-20)
@ -114,18 +165,18 @@ Changes in Element X v0.2.1 (2023-09-20)
Features ✨ Features ✨
---------- ----------
- Bump Rust SDK to `v0.1.56` - Bump Rust SDK to `v0.1.56`
- [Rich text editor] Add link support to rich text editor ([#1309](https://github.com/vector-im/element-x-android/issues/1309)) - [Rich text editor] Add link support to rich text editor ([#1309](https://github.com/element-hq/element-x-android/issues/1309))
- Let the SDK figure the best scheme given an homeserver URL (thus allowing HTTP homeservers) ([#1382](https://github.com/vector-im/element-x-android/issues/1382)) - Let the SDK figure the best scheme given an homeserver URL (thus allowing HTTP homeservers) ([#1382](https://github.com/element-hq/element-x-android/issues/1382))
Bugfixes 🐛 Bugfixes 🐛
---------- ----------
- Fix ANR on RoomList when notification settings change. ([#1370](https://github.com/vector-im/element-x-android/issues/1370)) - Fix ANR on RoomList when notification settings change. ([#1370](https://github.com/element-hq/element-x-android/issues/1370))
Other changes Other changes
------------- -------------
- Element Call: support scheme `io.element.call` ([#1377](https://github.com/vector-im/element-x-android/issues/1377)) - Element Call: support scheme `io.element.call` ([#1377](https://github.com/element-hq/element-x-android/issues/1377))
- [DI] Rework how dagger components are created and provided. ([#1378](https://github.com/vector-im/element-x-android/issues/1378)) - [DI] Rework how dagger components are created and provided. ([#1378](https://github.com/element-hq/element-x-android/issues/1378))
- Remove usage of async-uniffi as it leads to a deadlocks and memory leaks. ([#1381](https://github.com/vector-im/element-x-android/issues/1381)) - Remove usage of async-uniffi as it leads to a deadlocks and memory leaks. ([#1381](https://github.com/element-hq/element-x-android/issues/1381))
Changes in Element X v0.2.0 (2023-09-18) Changes in Element X v0.2.0 (2023-09-18)
@ -134,37 +185,37 @@ Changes in Element X v0.2.0 (2023-09-18)
Features ✨ Features ✨
---------- ----------
- Bump Rust SDK to `v0.1.54` - Bump Rust SDK to `v0.1.54`
- Add a "Mute" shortcut icon and a "Notifications" section in the room details screen ([#506](https://github.com/vector-im/element-x-android/issues/506)) - Add a "Mute" shortcut icon and a "Notifications" section in the room details screen ([#506](https://github.com/element-hq/element-x-android/issues/506))
- Add a notification permission screen to the initial flow. ([#897](https://github.com/vector-im/element-x-android/issues/897)) - Add a notification permission screen to the initial flow. ([#897](https://github.com/element-hq/element-x-android/issues/897))
- Integrate Element Call into EX by embedding a call in a WebView. ([#1300](https://github.com/vector-im/element-x-android/issues/1300)) - Integrate Element Call into EX by embedding a call in a WebView. ([#1300](https://github.com/element-hq/element-x-android/issues/1300))
- Implement Bloom effect modifier. ([#1217](https://github.com/vector-im/element-x-android/issues/1217)) - Implement Bloom effect modifier. ([#1217](https://github.com/element-hq/element-x-android/issues/1217))
- Set color on display name and default avatar in the timeline. ([#1224](https://github.com/vector-im/element-x-android/issues/1224)) - Set color on display name and default avatar in the timeline. ([#1224](https://github.com/element-hq/element-x-android/issues/1224))
- Display a thread decorator in timeline so we know when a message is coming from a thread. ([#1236](https://github.com/vector-im/element-x-android/issues/1236)) - Display a thread decorator in timeline so we know when a message is coming from a thread. ([#1236](https://github.com/element-hq/element-x-android/issues/1236))
- [Rich text editor] Integrate rich text editor library. Note that markdown is now not supported and further formatting support will be introduced through the rich text editor. ([#1172](https://github.com/vector-im/element-x-android/issues/1172)) - [Rich text editor] Integrate rich text editor library. Note that markdown is now not supported and further formatting support will be introduced through the rich text editor. ([#1172](https://github.com/element-hq/element-x-android/issues/1172))
- [Rich text editor] Add formatting menu (accessible via the '+' button) ([#1261](https://github.com/vector-im/element-x-android/issues/1261)) - [Rich text editor] Add formatting menu (accessible via the '+' button) ([#1261](https://github.com/element-hq/element-x-android/issues/1261))
- [Rich text editor] Add feature flag for rich text editor. Markdown support can now be enabled by disabling the rich text editor. ([#1289](https://github.com/vector-im/element-x-android/issues/1289)) - [Rich text editor] Add feature flag for rich text editor. Markdown support can now be enabled by disabling the rich text editor. ([#1289](https://github.com/element-hq/element-x-android/issues/1289))
- [Rich text editor] Update design ([#1332](https://github.com/vector-im/element-x-android/issues/1332)) - [Rich text editor] Update design ([#1332](https://github.com/element-hq/element-x-android/issues/1332))
Bugfixes 🐛 Bugfixes 🐛
---------- ----------
- Make links in room topic clickable ([#612](https://github.com/vector-im/element-x-android/issues/612)) - Make links in room topic clickable ([#612](https://github.com/element-hq/element-x-android/issues/612))
- Reply action: harmonize conditions in bottom sheet and swipe to reply. ([#1173](https://github.com/vector-im/element-x-android/issues/1173)) - Reply action: harmonize conditions in bottom sheet and swipe to reply. ([#1173](https://github.com/element-hq/element-x-android/issues/1173))
- Fix system bar color after login on light theme. ([#1222](https://github.com/vector-im/element-x-android/issues/1222)) - Fix system bar color after login on light theme. ([#1222](https://github.com/element-hq/element-x-android/issues/1222))
- Fix long click on simple formatted messages ([#1232](https://github.com/vector-im/element-x-android/issues/1232)) - Fix long click on simple formatted messages ([#1232](https://github.com/element-hq/element-x-android/issues/1232))
- Enable polls in release build. ([#1241](https://github.com/vector-im/element-x-android/issues/1241)) - Enable polls in release build. ([#1241](https://github.com/element-hq/element-x-android/issues/1241))
- Fix top padding in room list when app is opened in offline mode. ([#1297](https://github.com/vector-im/element-x-android/issues/1297)) - Fix top padding in room list when app is opened in offline mode. ([#1297](https://github.com/element-hq/element-x-android/issues/1297))
- [Rich text editor] Fix 'text formatting' option only partially visible ([#1335](https://github.com/vector-im/element-x-android/issues/1335)) - [Rich text editor] Fix 'text formatting' option only partially visible ([#1335](https://github.com/element-hq/element-x-android/issues/1335))
- [Rich text editor] Ensure keyboard opens for reply and text formatting modes ([#1337](https://github.com/vector-im/element-x-android/issues/1337)) - [Rich text editor] Ensure keyboard opens for reply and text formatting modes ([#1337](https://github.com/element-hq/element-x-android/issues/1337))
- [Rich text editor] Fix placeholder spilling onto multiple lines ([#1347](https://github.com/vector-im/element-x-android/issues/1347)) - [Rich text editor] Fix placeholder spilling onto multiple lines ([#1347](https://github.com/element-hq/element-x-android/issues/1347))
Other changes Other changes
------------- -------------
- Add a sub-screen "Notifications" in the existing application Settings ([#510](https://github.com/vector-im/element-x-android/issues/510)) - Add a sub-screen "Notifications" in the existing application Settings ([#510](https://github.com/element-hq/element-x-android/issues/510))
- Exclude some groups related to analytics to be included. ([#1191](https://github.com/vector-im/element-x-android/issues/1191)) - Exclude some groups related to analytics to be included. ([#1191](https://github.com/element-hq/element-x-android/issues/1191))
- Use the new SyncIndicator API. ([#1244](https://github.com/vector-im/element-x-android/issues/1244)) - Use the new SyncIndicator API. ([#1244](https://github.com/element-hq/element-x-android/issues/1244))
- Improve RoomSummary mapping by using RoomInfo. ([#1251](https://github.com/vector-im/element-x-android/issues/1251)) - Improve RoomSummary mapping by using RoomInfo. ([#1251](https://github.com/element-hq/element-x-android/issues/1251))
- Ensure Posthog data are sent to "https://posthog.element.io" ([#1269](https://github.com/vector-im/element-x-android/issues/1269)) - Ensure Posthog data are sent to "https://posthog.element.io" ([#1269](https://github.com/element-hq/element-x-android/issues/1269))
- New app icon, with monochrome support. ([#1363](https://github.com/vector-im/element-x-android/issues/1363)) - New app icon, with monochrome support. ([#1363](https://github.com/element-hq/element-x-android/issues/1363))
Changes in Element X v0.1.6 (2023-09-04) Changes in Element X v0.1.6 (2023-09-04)
@ -172,22 +223,22 @@ Changes in Element X v0.1.6 (2023-09-04)
Features ✨ Features ✨
---------- ----------
- Enable the Polls feature. Allows to create, view, vote and end polls. ([#1196](https://github.com/vector-im/element-x-android/issues/1196)) - Enable the Polls feature. Allows to create, view, vote and end polls. ([#1196](https://github.com/element-hq/element-x-android/issues/1196))
- Create poll. ([#1143](https://github.com/vector-im/element-x-android/issues/1143)) - Create poll. ([#1143](https://github.com/element-hq/element-x-android/issues/1143))
Bugfixes 🐛 Bugfixes 🐛
---------- ----------
- Ensure notification for Event from encrypted room get decrypted content. ([#1178](https://github.com/vector-im/element-x-android/issues/1178)) - Ensure notification for Event from encrypted room get decrypted content. ([#1178](https://github.com/element-hq/element-x-android/issues/1178))
- Make sure Snackbars are only displayed once. ([#928](https://github.com/vector-im/element-x-android/issues/928)) - Make sure Snackbars are only displayed once. ([#928](https://github.com/element-hq/element-x-android/issues/928))
- Fix the orientation of sent images. ([#1135](https://github.com/vector-im/element-x-android/issues/1135)) - Fix the orientation of sent images. ([#1135](https://github.com/element-hq/element-x-android/issues/1135))
- Bug reporter crashes when 'send logs' is disabled. ([#1168](https://github.com/vector-im/element-x-android/issues/1168)) - Bug reporter crashes when 'send logs' is disabled. ([#1168](https://github.com/element-hq/element-x-android/issues/1168))
- Add missing link to the terms on the analytics setting screen. ([#1177](https://github.com/vector-im/element-x-android/issues/1177)) - Add missing link to the terms on the analytics setting screen. ([#1177](https://github.com/element-hq/element-x-android/issues/1177))
- Re-enable `SyncService.withEncryptionSync` to improve decryption of notifications. ([#1198](https://github.com/vector-im/element-x-android/issues/1198)) - Re-enable `SyncService.withEncryptionSync` to improve decryption of notifications. ([#1198](https://github.com/element-hq/element-x-android/issues/1198))
- Crash with `aspectRatio` modifier when `Float.NaN` was used as input. ([#1995](https://github.com/vector-im/element-x-android/issues/1995)) - Crash with `aspectRatio` modifier when `Float.NaN` was used as input. ([#1995](https://github.com/element-hq/element-x-android/issues/1995))
Other changes Other changes
------------- -------------
- Remove unnecessary year in copyright mention. ([#1187](https://github.com/vector-im/element-x-android/issues/1187)) - Remove unnecessary year in copyright mention. ([#1187](https://github.com/element-hq/element-x-android/issues/1187))
Changes in Element X v0.1.5 (2023-08-28) Changes in Element X v0.1.5 (2023-08-28)
@ -195,7 +246,7 @@ Changes in Element X v0.1.5 (2023-08-28)
Bugfixes 🐛 Bugfixes 🐛
---------- ----------
- Fix crash when opening any room. ([#1160](https://github.com/vector-im/element-x-android/issues/1160)) - Fix crash when opening any room. ([#1160](https://github.com/element-hq/element-x-android/issues/1160))
Changes in Element X v0.1.4 (2023-08-28) Changes in Element X v0.1.4 (2023-08-28)
@ -203,32 +254,32 @@ Changes in Element X v0.1.4 (2023-08-28)
Features ✨ Features ✨
---------- ----------
- Allow cancelling media upload ([#769](https://github.com/vector-im/element-x-android/issues/769)) - Allow cancelling media upload ([#769](https://github.com/element-hq/element-x-android/issues/769))
- Enable OIDC support. ([#1127](https://github.com/vector-im/element-x-android/issues/1127)) - Enable OIDC support. ([#1127](https://github.com/element-hq/element-x-android/issues/1127))
- Add a "Setting up account" screen, displayed the first time the user logs in to the app (per account). ([#1149](https://github.com/vector-im/element-x-android/issues/1149)) - Add a "Setting up account" screen, displayed the first time the user logs in to the app (per account). ([#1149](https://github.com/element-hq/element-x-android/issues/1149))
Bugfixes 🐛 Bugfixes 🐛
---------- ----------
- Videos sent from the app were cropped in some cases. ([#862](https://github.com/vector-im/element-x-android/issues/862)) - Videos sent from the app were cropped in some cases. ([#862](https://github.com/element-hq/element-x-android/issues/862))
- Timeline: sender names are now displayed in one single line. ([#1033](https://github.com/vector-im/element-x-android/issues/1033)) - Timeline: sender names are now displayed in one single line. ([#1033](https://github.com/element-hq/element-x-android/issues/1033))
- Fix `TextButtons` being displayed in black. ([#1077](https://github.com/vector-im/element-x-android/issues/1077)) - Fix `TextButtons` being displayed in black. ([#1077](https://github.com/element-hq/element-x-android/issues/1077))
- Linkify links in HTML contents. ([#1079](https://github.com/vector-im/element-x-android/issues/1079)) - Linkify links in HTML contents. ([#1079](https://github.com/element-hq/element-x-android/issues/1079))
- Fix bug reporter failing after not finding some log files. ([#1082](https://github.com/vector-im/element-x-android/issues/1082)) - Fix bug reporter failing after not finding some log files. ([#1082](https://github.com/element-hq/element-x-android/issues/1082))
- Fix rendering of inline elements in list items. ([#1090](https://github.com/vector-im/element-x-android/issues/1090)) - Fix rendering of inline elements in list items. ([#1090](https://github.com/element-hq/element-x-android/issues/1090))
- Fix crash RuntimeException "No matching key found for the ciphertext in the stream" ([#1101](https://github.com/vector-im/element-x-android/issues/1101)) - Fix crash RuntimeException "No matching key found for the ciphertext in the stream" ([#1101](https://github.com/element-hq/element-x-android/issues/1101))
- Make links in messages clickable again. ([#1111](https://github.com/vector-im/element-x-android/issues/1111)) - Make links in messages clickable again. ([#1111](https://github.com/element-hq/element-x-android/issues/1111))
- When event has no id, just cancel parsing the latest room message for a room. ([#1125](https://github.com/vector-im/element-x-android/issues/1125)) - When event has no id, just cancel parsing the latest room message for a room. ([#1125](https://github.com/element-hq/element-x-android/issues/1125))
- Only display verification prompt after initial sync is done. ([#1131](https://github.com/vector-im/element-x-android/issues/1131)) - Only display verification prompt after initial sync is done. ([#1131](https://github.com/element-hq/element-x-android/issues/1131))
In development 🚧 In development 🚧
---------------- ----------------
- [Poll] Add feature flag in developer options ([#1064](https://github.com/vector-im/element-x-android/issues/1064)) - [Poll] Add feature flag in developer options ([#1064](https://github.com/element-hq/element-x-android/issues/1064))
- [Polls] Improve UI and render ended state ([#1113](https://github.com/vector-im/element-x-android/issues/1113)) - [Polls] Improve UI and render ended state ([#1113](https://github.com/element-hq/element-x-android/issues/1113))
Other changes Other changes
------------- -------------
- Compound: add `ListItem` and `ListSectionHeader` components. ([#990](https://github.com/vector-im/element-x-android/issues/990)) - Compound: add `ListItem` and `ListSectionHeader` components. ([#990](https://github.com/element-hq/element-x-android/issues/990))
- Migrate `object` to `data object` in sealed interface / class #1135 ([#1135](https://github.com/vector-im/element-x-android/issues/1135)) - Migrate `object` to `data object` in sealed interface / class #1135 ([#1135](https://github.com/element-hq/element-x-android/issues/1135))
Changes in Element X v0.1.2 (2023-08-16) Changes in Element X v0.1.2 (2023-08-16)
@ -236,20 +287,20 @@ Changes in Element X v0.1.2 (2023-08-16)
Bugfixes 🐛 Bugfixes 🐛
---------- ----------
- Filter push notifications using push rules. ([#640](https://github.com/vector-im/element-x-android/issues/640)) - Filter push notifications using push rules. ([#640](https://github.com/element-hq/element-x-android/issues/640))
- Use `for` instead of `forEach` in `DefaultDiffCacheInvalidator` to improve performance. ([#1035](https://github.com/vector-im/element-x-android/issues/1035)) - Use `for` instead of `forEach` in `DefaultDiffCacheInvalidator` to improve performance. ([#1035](https://github.com/element-hq/element-x-android/issues/1035))
In development 🚧 In development 🚧
---------------- ----------------
- [Poll] Render start event in the timeline ([#1031](https://github.com/vector-im/element-x-android/issues/1031)) - [Poll] Render start event in the timeline ([#1031](https://github.com/element-hq/element-x-android/issues/1031))
Other changes Other changes
------------- -------------
- Add Button component based on Compound designs ([#1021](https://github.com/vector-im/element-x-android/issues/1021)) - Add Button component based on Compound designs ([#1021](https://github.com/element-hq/element-x-android/issues/1021))
- Compound: implement dialogs. ([#1043](https://github.com/vector-im/element-x-android/issues/1043)) - Compound: implement dialogs. ([#1043](https://github.com/element-hq/element-x-android/issues/1043))
- Compound: customise `IconButton` component. ([#1049](https://github.com/vector-im/element-x-android/issues/1049)) - Compound: customise `IconButton` component. ([#1049](https://github.com/element-hq/element-x-android/issues/1049))
- Compound: implement `DropdownMenu` customisations. ([#1050](https://github.com/vector-im/element-x-android/issues/1050)) - Compound: implement `DropdownMenu` customisations. ([#1050](https://github.com/element-hq/element-x-android/issues/1050))
- Compound: implement Snackbar component. ([#1054](https://github.com/vector-im/element-x-android/issues/1054)) - Compound: implement Snackbar component. ([#1054](https://github.com/element-hq/element-x-android/issues/1054))
Changes in Element X v0.1.0 (2023-07-19) Changes in Element X v0.1.0 (2023-07-19)

View file

@ -1 +1 @@
* @vector-im/element-x-android-reviewers * @element-hq/element-x-android-reviewers

View file

@ -187,7 +187,7 @@ internal fun PinIconPreview() = ElementPreview {
} }
``` ```
This will allow to preview the composable in both light and dark mode in Android Studio. This will also automatically add UI tests. The GitHub action [Record screenshots](https://github.com/vector-im/element-x-android/actions/workflows/recordScreenshots.yml) has to be run to record the new screenshots. The PR reviewer can trigger this for you if you're not part of the core team. This will allow to preview the composable in both light and dark mode in Android Studio. This will also automatically add UI tests. The GitHub action [Record screenshots](https://github.com/element-hq/element-x-android/actions/workflows/recordScreenshots.yml) has to be run to record the new screenshots. The PR reviewer can trigger this for you if you're not part of the core team.
### Authors ### Authors

View file

@ -1,8 +1,8 @@
[![Latest build](https://github.com/vector-im/element-x-android/actions/workflows/build.yml/badge.svg?query=branch%3Adevelop)](https://github.com/vector-im/element-x-android/actions/workflows/build.yml?query=branch%3Adevelop) [![Latest build](https://github.com/element-hq/element-x-android/actions/workflows/build.yml/badge.svg?query=branch%3Adevelop)](https://github.com/element-hq/element-x-android/actions/workflows/build.yml?query=branch%3Adevelop)
[![Quality Gate Status](https://sonarcloud.io/api/project_badges/measure?project=vector-im_element-x-android&metric=alert_status)](https://sonarcloud.io/summary/new_code?id=vector-im_element-x-android) [![Quality Gate Status](https://sonarcloud.io/api/project_badges/measure?project=vector-im_element-x-android&metric=alert_status)](https://sonarcloud.io/summary/new_code?id=vector-im_element-x-android)
[![Vulnerabilities](https://sonarcloud.io/api/project_badges/measure?project=vector-im_element-x-android&metric=vulnerabilities)](https://sonarcloud.io/summary/new_code?id=vector-im_element-x-android) [![Vulnerabilities](https://sonarcloud.io/api/project_badges/measure?project=vector-im_element-x-android&metric=vulnerabilities)](https://sonarcloud.io/summary/new_code?id=vector-im_element-x-android)
[![Bugs](https://sonarcloud.io/api/project_badges/measure?project=vector-im_element-x-android&metric=bugs)](https://sonarcloud.io/summary/new_code?id=vector-im_element-x-android) [![Bugs](https://sonarcloud.io/api/project_badges/measure?project=vector-im_element-x-android&metric=bugs)](https://sonarcloud.io/summary/new_code?id=vector-im_element-x-android)
[![codecov](https://codecov.io/github/vector-im/element-x-android/branch/develop/graph/badge.svg?token=ecwvia7amV)](https://codecov.io/github/vector-im/element-x-android) [![codecov](https://codecov.io/github/element-hq/element-x-android/branch/develop/graph/badge.svg?token=ecwvia7amV)](https://codecov.io/github/vector-im/element-x-android)
[![Element X_Android Matrix room #element-x-android:matrix.org](https://img.shields.io/matrix/element-x-android:matrix.org.svg?label=%23element-x-android:matrix.org&logo=matrix&server_fqdn=matrix.org)](https://matrix.to/#/#element-x-android:matrix.org) [![Element X_Android Matrix room #element-x-android:matrix.org](https://img.shields.io/matrix/element-x-android:matrix.org.svg?label=%23element-x-android:matrix.org&logo=matrix&server_fqdn=matrix.org)](https://matrix.to/#/#element-x-android:matrix.org)
[![Localazy](https://img.shields.io/endpoint?url=https%3A%2F%2Fconnect.localazy.com%2Fstatus%2Felement%2Fdata%3Fcontent%3Dall%26title%3Dlocalazy%26logo%3Dtrue)](https://localazy.com/p/element) [![Localazy](https://img.shields.io/endpoint?url=https%3A%2F%2Fconnect.localazy.com%2Fstatus%2Felement%2Fdata%3Fcontent%3Dall%26title%3Dlocalazy%26logo%3Dtrue)](https://localazy.com/p/element)
@ -10,7 +10,7 @@
Element X Android is a [Matrix](https://matrix.org/) Android Client provided by [element.io](https://element.io/). This app is currently in a pre-alpha release stage with only basic functionalities. Element X Android is a [Matrix](https://matrix.org/) Android Client provided by [element.io](https://element.io/). This app is currently in a pre-alpha release stage with only basic functionalities.
The application is a total rewrite of [Element-Android](https://github.com/vector-im/element-android) using the [Matrix Rust SDK](https://github.com/matrix-org/matrix-rust-sdk) underneath and targeting devices running Android 6+. The UI layer is written using [Jetpack Compose](https://developer.android.com/jetpack/compose), and the navigation is managed using [Appyx](https://github.com/bumble-tech/appyx). The application is a total rewrite of [Element-Android](https://github.com/element-hq/element-android) using the [Matrix Rust SDK](https://github.com/matrix-org/matrix-rust-sdk) underneath and targeting devices running Android 6+. The UI layer is written using [Jetpack Compose](https://developer.android.com/jetpack/compose), and the navigation is managed using [Appyx](https://github.com/bumble-tech/appyx).
Learn more about why we are building Element X in our blog post: [https://element.io/blog/element-x-experience-the-future-of-element/](https://element.io/blog/element-x-experience-the-future-of-element/). Learn more about why we are building Element X in our blog post: [https://element.io/blog/element-x-experience-the-future-of-element/](https://element.io/blog/element-x-experience-the-future-of-element/).
@ -58,11 +58,11 @@ We're doing this as a way to share code between platforms and while we've seen p
## Status ## Status
This project is in work in progress. The app does not cover yet all functionalities we expect. The list of supported features can be found in [this issue](https://github.com/vector-im/element-x-android/issues/911). This project is in work in progress. The app does not cover yet all functionalities we expect. The list of supported features can be found in [this issue](https://github.com/element-hq/element-x-android/issues/911).
## Contributing ## Contributing
Want to get actively involved in the project? You're more than welcome! A good way to start is to check the issues that are labelled with the [good first issue](https://github.com/vector-im/element-x-android/issues?q=is%3Aissue+is%3Aopen+label%3A%22good+first+issue%22) label. Let us know by commenting the issue that you're starting working on it. Want to get actively involved in the project? You're more than welcome! A good way to start is to check the issues that are labelled with the [good first issue](https://github.com/element-hq/element-x-android/issues?q=is%3Aissue+is%3Aopen+label%3A%22good+first+issue%22) label. Let us know by commenting the issue that you're starting working on it.
But first make sure to read our [contribution guide](CONTRIBUTING.md) first. But first make sure to read our [contribution guide](CONTRIBUTING.md) first.
@ -75,7 +75,7 @@ Makes sure to select the `app` configuration when building (as we also have samp
## Support ## Support
When you are experiencing an issue on Element X Android, please first search in [GitHub issues](https://github.com/vector-im/element-x-android/issues) When you are experiencing an issue on Element X Android, please first search in [GitHub issues](https://github.com/element-hq/element-x-android/issues)
and then in [#element-x-android:matrix.org](https://matrix.to/#/#element-x-android:matrix.org). and then in [#element-x-android:matrix.org](https://matrix.to/#/#element-x-android:matrix.org).
If after your research you still have a question, ask at [#element-x-android:matrix.org](https://matrix.to/#/#element-x-android:matrix.org). Otherwise feel free to create a GitHub issue if you encounter a bug or a crash, by explaining clearly in detail what happened. You can also perform bug reporting from the application settings. This is especially recommended when you encounter a crash. If after your research you still have a question, ask at [#element-x-android:matrix.org](https://matrix.to/#/#element-x-android:matrix.org). Otherwise feel free to create a GitHub issue if you encounter a bug or a crash, by explaining clearly in detail what happened. You can also perform bug reporting from the application settings. This is especially recommended when you encounter a crash.

View file

@ -225,6 +225,7 @@ dependencies {
kapt(libs.dagger.compiler) kapt(libs.dagger.compiler)
testImplementation(libs.test.junit) testImplementation(libs.test.junit)
testImplementation(libs.test.robolectric)
testImplementation(libs.coroutines.test) testImplementation(libs.coroutines.test)
testImplementation(libs.molecule.runtime) testImplementation(libs.molecule.runtime)
testImplementation(libs.test.truth) testImplementation(libs.test.truth)

View file

@ -35,15 +35,15 @@ import androidx.core.view.WindowCompat
import com.bumble.appyx.core.integration.NodeHost import com.bumble.appyx.core.integration.NodeHost
import com.bumble.appyx.core.integrationpoint.NodeActivity import com.bumble.appyx.core.integrationpoint.NodeActivity
import com.bumble.appyx.core.plugin.NodeReadyObserver import com.bumble.appyx.core.plugin.NodeReadyObserver
import io.element.android.compound.theme.ElementTheme
import io.element.android.compound.theme.Theme
import io.element.android.compound.theme.isDark
import io.element.android.compound.theme.mapToTheme
import io.element.android.features.lockscreen.api.handleSecureFlag import io.element.android.features.lockscreen.api.handleSecureFlag
import io.element.android.features.lockscreen.api.isLocked import io.element.android.features.lockscreen.api.isLocked
import io.element.android.libraries.architecture.bindings import io.element.android.libraries.architecture.bindings
import io.element.android.libraries.core.log.logger.LoggerTag import io.element.android.libraries.core.log.logger.LoggerTag
import io.element.android.libraries.designsystem.utils.snackbar.LocalSnackbarDispatcher import io.element.android.libraries.designsystem.utils.snackbar.LocalSnackbarDispatcher
import io.element.android.libraries.theme.ElementTheme
import io.element.android.libraries.theme.theme.Theme
import io.element.android.libraries.theme.theme.isDark
import io.element.android.libraries.theme.theme.mapToTheme
import io.element.android.x.di.AppBindings import io.element.android.x.di.AppBindings
import io.element.android.x.intent.SafeUriHandler import io.element.android.x.intent.SafeUriHandler
import timber.log.Timber import timber.log.Timber

View file

@ -52,7 +52,7 @@ class MainNode(
override val daggerComponent = (context as DaggerComponentOwner).daggerComponent override val daggerComponent = (context as DaggerComponentOwner).daggerComponent
override fun resolve(navTarget: RootNavTarget, buildContext: BuildContext): Node { override fun resolve(navTarget: RootNavTarget, buildContext: BuildContext): Node {
return createNode<RootFlowNode>(context = buildContext) return createNode<RootFlowNode>(buildContext = buildContext)
} }
@Composable @Composable

View file

@ -57,6 +57,7 @@ class TracingInitializer : Initializer<Unit> {
) )
} }
bugReporter.cleanLogDirectoryIfNeeded() bugReporter.cleanLogDirectoryIfNeeded()
bugReporter.setCurrentTracingFilter(tracingConfiguration.filterConfiguration.filter)
tracingService.setupTracing(tracingConfiguration) tracingService.setupTracing(tracingConfiguration)
// Also set env variable for rust back trace // Also set env variable for rust back trace
Os.setenv("RUST_BACKTRACE", "1", true) Os.setenv("RUST_BACKTRACE", "1", true)

View file

@ -14,6 +14,6 @@
~ limitations under the License. ~ limitations under the License.
--> -->
<paths xmlns:android="http://schemas.android.com/apk/res/android"> <paths>
<cache-path name="cache" path="." /> <cache-path name="cache" path="." />
</paths> </paths>

View file

@ -0,0 +1,92 @@
/*
* Copyright (c) 2023 New Vector Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.element.android.x.intent
import android.content.Context
import android.content.Intent
import com.google.common.truth.Truth.assertThat
import io.element.android.libraries.deeplink.DeepLinkCreator
import io.element.android.libraries.matrix.test.A_ROOM_ID
import io.element.android.libraries.matrix.test.A_SESSION_ID
import io.element.android.libraries.matrix.test.A_THREAD_ID
import io.element.android.x.MainActivity
import org.junit.Test
import org.junit.runner.RunWith
import org.robolectric.RobolectricTestRunner
import org.robolectric.RuntimeEnvironment
@RunWith(RobolectricTestRunner::class)
class IntentProviderImplTest {
@Test
fun `test getViewRoomIntent with Session`() {
val sut = createIntentProviderImpl()
val result = sut.getViewRoomIntent(
sessionId = A_SESSION_ID,
roomId = null,
threadId = null,
)
result.commonAssertions()
assertThat(result.data.toString()).isEqualTo("elementx://open/@alice:server.org")
}
@Test
fun `test getViewRoomIntent with Session and Room`() {
val sut = createIntentProviderImpl()
val result = sut.getViewRoomIntent(
sessionId = A_SESSION_ID,
roomId = A_ROOM_ID,
threadId = null,
)
result.commonAssertions()
assertThat(result.data.toString()).isEqualTo("elementx://open/@alice:server.org/!aRoomId:domain")
}
@Test
fun `test getViewRoomIntent with Session, Room and Thread`() {
val sut = createIntentProviderImpl()
val result = sut.getViewRoomIntent(
sessionId = A_SESSION_ID,
roomId = A_ROOM_ID,
threadId = A_THREAD_ID,
)
result.commonAssertions()
assertThat(result.data.toString()).isEqualTo("elementx://open/@alice:server.org/!aRoomId:domain/\$aThreadId")
}
@Test
fun `test getInviteListIntent`() {
val sut = createIntentProviderImpl()
val result = sut.getInviteListIntent(
sessionId = A_SESSION_ID,
)
result.commonAssertions()
assertThat(result.data.toString()).isEqualTo("elementx://open/@alice:server.org/invites")
}
private fun createIntentProviderImpl(): IntentProviderImpl {
return IntentProviderImpl(
context = RuntimeEnvironment.getApplication() as Context,
deepLinkCreator = DeepLinkCreator(),
)
}
private fun Intent.commonAssertions() {
assertThat(action).isEqualTo(Intent.ACTION_VIEW)
assertThat(component?.className).isEqualTo(MainActivity::class.java.name)
}
}

View file

@ -14,9 +14,8 @@
* limitations under the License. * limitations under the License.
*/ */
package io.element.android.features.analytics.api package io.element.android.appconfig
object Config { object AnalyticsConfig {
const val POLICY_LINK = "https://element.io/cookie-policy" const val POLICY_LINK = "https://element.io/cookie-policy"
} }

View file

@ -14,7 +14,7 @@
* limitations under the License. * limitations under the License.
*/ */
package io.element.android.libraries.push.impl package io.element.android.appconfig
object NotificationConfig { object NotificationConfig {
// TODO EAx Implement and set to true at some point // TODO EAx Implement and set to true at some point

View file

@ -0,0 +1,24 @@
/*
* Copyright (c) 2023 New Vector Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.element.android.appconfig
object RoomListConfig {
const val showInviteMenuItem = false
const val showReportProblemMenuItem = false
const val hasDropdownMenu = showInviteMenuItem || showReportProblemMenuItem
}

View file

@ -58,12 +58,14 @@ dependencies {
implementation(projects.services.analytics.api) implementation(projects.services.analytics.api)
testImplementation(libs.test.junit) testImplementation(libs.test.junit)
testImplementation(libs.test.robolectric)
testImplementation(libs.coroutines.test) testImplementation(libs.coroutines.test)
testImplementation(libs.molecule.runtime) testImplementation(libs.molecule.runtime)
testImplementation(libs.test.truth) testImplementation(libs.test.truth)
testImplementation(libs.test.turbine) testImplementation(libs.test.turbine)
testImplementation(projects.libraries.matrix.test) testImplementation(projects.libraries.matrix.test)
testImplementation(projects.features.networkmonitor.test) testImplementation(projects.features.networkmonitor.test)
testImplementation(projects.features.login.impl)
testImplementation(projects.tests.testutils) testImplementation(projects.tests.testutils)
testImplementation(projects.features.rageshake.test) testImplementation(projects.features.rageshake.test)
testImplementation(projects.features.rageshake.impl) testImplementation(projects.features.rageshake.impl)

View file

@ -33,13 +33,12 @@ import dagger.assisted.AssistedInject
import io.element.android.anvilannotations.ContributesNode import io.element.android.anvilannotations.ContributesNode
import io.element.android.appnav.di.SessionComponentFactory import io.element.android.appnav.di.SessionComponentFactory
import io.element.android.libraries.architecture.NodeInputs import io.element.android.libraries.architecture.NodeInputs
import io.element.android.libraries.architecture.bindings
import io.element.android.libraries.architecture.createNode import io.element.android.libraries.architecture.createNode
import io.element.android.libraries.architecture.inputs import io.element.android.libraries.architecture.inputs
import io.element.android.libraries.di.AppScope import io.element.android.libraries.di.AppScope
import io.element.android.libraries.di.DaggerComponentOwner import io.element.android.libraries.di.DaggerComponentOwner
import io.element.android.libraries.matrix.api.MatrixClient import io.element.android.libraries.matrix.api.MatrixClient
import io.element.android.libraries.matrix.ui.di.MatrixUIBindings import io.element.android.libraries.matrix.ui.media.ImageLoaderHolder
import kotlinx.parcelize.Parcelize import kotlinx.parcelize.Parcelize
/** /**
@ -52,6 +51,7 @@ class LoggedInAppScopeFlowNode @AssistedInject constructor(
@Assisted buildContext: BuildContext, @Assisted buildContext: BuildContext,
@Assisted plugins: List<Plugin>, @Assisted plugins: List<Plugin>,
sessionComponentFactory: SessionComponentFactory, sessionComponentFactory: SessionComponentFactory,
private val imageLoaderHolder: ImageLoaderHolder,
) : ParentNode<LoggedInAppScopeFlowNode.NavTarget>( ) : ParentNode<LoggedInAppScopeFlowNode.NavTarget>(
navModel = PermanentNavModel( navModel = PermanentNavModel(
navTargets = setOf(NavTarget), navTargets = setOf(NavTarget),
@ -78,8 +78,7 @@ class LoggedInAppScopeFlowNode @AssistedInject constructor(
super.onBuilt() super.onBuilt()
lifecycle.subscribe( lifecycle.subscribe(
onCreate = { onCreate = {
val imageLoaderFactory = bindings<MatrixUIBindings>().loggedInImageLoaderFactory() Coil.setImageLoader(imageLoaderHolder.get(inputs.matrixClient))
Coil.setImageLoader(imageLoaderFactory)
}, },
) )
} }

View file

@ -25,7 +25,6 @@ import androidx.compose.ui.Modifier
import androidx.lifecycle.Lifecycle import androidx.lifecycle.Lifecycle
import androidx.lifecycle.lifecycleScope import androidx.lifecycle.lifecycleScope
import androidx.lifecycle.repeatOnLifecycle import androidx.lifecycle.repeatOnLifecycle
import com.bumble.appyx.core.composable.Children
import com.bumble.appyx.core.composable.PermanentChild 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
@ -57,8 +56,8 @@ import io.element.android.features.preferences.api.PreferencesEntryPoint
import io.element.android.features.roomlist.api.RoomListEntryPoint import io.element.android.features.roomlist.api.RoomListEntryPoint
import io.element.android.features.securebackup.api.SecureBackupEntryPoint import io.element.android.features.securebackup.api.SecureBackupEntryPoint
import io.element.android.features.verifysession.api.VerifySessionEntryPoint import io.element.android.features.verifysession.api.VerifySessionEntryPoint
import io.element.android.libraries.architecture.BackstackNode import io.element.android.libraries.architecture.BackstackView
import io.element.android.libraries.architecture.animation.rememberDefaultTransitionHandler import io.element.android.libraries.architecture.BaseFlowNode
import io.element.android.libraries.architecture.createNode import io.element.android.libraries.architecture.createNode
import io.element.android.libraries.architecture.waitForChildAttached import io.element.android.libraries.architecture.waitForChildAttached
import io.element.android.libraries.deeplink.DeeplinkData import io.element.android.libraries.deeplink.DeeplinkData
@ -67,6 +66,7 @@ import io.element.android.libraries.di.SessionScope
import io.element.android.libraries.matrix.api.MatrixClient import io.element.android.libraries.matrix.api.MatrixClient
import io.element.android.libraries.matrix.api.core.MAIN_SPACE import io.element.android.libraries.matrix.api.core.MAIN_SPACE
import io.element.android.libraries.matrix.api.core.RoomId import io.element.android.libraries.matrix.api.core.RoomId
import io.element.android.libraries.matrix.api.roomlist.RoomList
import io.element.android.libraries.matrix.api.sync.SyncState import io.element.android.libraries.matrix.api.sync.SyncState
import io.element.android.libraries.push.api.notifications.NotificationDrawerManager import io.element.android.libraries.push.api.notifications.NotificationDrawerManager
import io.element.android.services.appnavstate.api.AppNavigationStateService import io.element.android.services.appnavstate.api.AppNavigationStateService
@ -99,7 +99,7 @@ class LoggedInFlowNode @AssistedInject constructor(
private val lockScreenStateService: LockScreenService, private val lockScreenStateService: LockScreenService,
private val matrixClient: MatrixClient, private val matrixClient: MatrixClient,
snackbarDispatcher: SnackbarDispatcher, snackbarDispatcher: SnackbarDispatcher,
) : BackstackNode<LoggedInFlowNode.NavTarget>( ) : BaseFlowNode<LoggedInFlowNode.NavTarget>(
backstack = BackStack( backstack = BackStack(
initialElement = NavTarget.RoomList, initialElement = NavTarget.RoomList,
savedStateMap = buildContext.savedStateMap, savedStateMap = buildContext.savedStateMap,
@ -149,6 +149,23 @@ class LoggedInFlowNode @AssistedInject constructor(
} }
) )
observeSyncStateAndNetworkStatus() observeSyncStateAndNetworkStatus()
observeInvitesLoadingState()
}
private fun observeInvitesLoadingState() {
lifecycleScope.launch {
repeatOnLifecycle(Lifecycle.State.STARTED) {
matrixClient.roomListService.invites.loadingState
.collect { inviteState ->
when (inviteState) {
is RoomList.LoadingState.Loaded -> if (inviteState.numberOfRooms == 0) {
backstack.removeLast(NavTarget.InviteList)
}
RoomList.LoadingState.NotLoaded -> Unit
}
}
}
}
} }
@OptIn(FlowPreview::class) @OptIn(FlowPreview::class)
@ -256,6 +273,10 @@ class LoggedInFlowNode @AssistedInject constructor(
} }
is NavTarget.Room -> { is NavTarget.Room -> {
val callback = object : RoomLoadedFlowNode.Callback { val callback = object : RoomLoadedFlowNode.Callback {
override fun onOpenRoom(roomId: RoomId) {
backstack.push(NavTarget.Room(roomId))
}
override fun onForwardedToSingleRoom(roomId: RoomId) { override fun onForwardedToSingleRoom(roomId: RoomId) {
coroutineScope.launch { attachRoom(roomId) } coroutineScope.launch { attachRoom(roomId) }
} }
@ -362,12 +383,7 @@ class LoggedInFlowNode @AssistedInject constructor(
override fun View(modifier: Modifier) { override fun View(modifier: Modifier) {
Box(modifier = modifier) { Box(modifier = modifier) {
val lockScreenState by lockScreenStateService.lockState.collectAsState() val lockScreenState by lockScreenStateService.lockState.collectAsState()
Children( BackstackView()
navModel = backstack,
modifier = Modifier,
// Animate navigation to settings and to a room
transitionHandler = rememberDefaultTransitionHandler(),
)
val isFtueDisplayed by ftueState.shouldDisplayFlow.collectAsState() val isFtueDisplayed by ftueState.shouldDisplayFlow.collectAsState()
if (!isFtueDisplayed) { if (!isFtueDisplayed) {
PermanentChild(permanentNavModel = permanentNavModel, navTarget = NavTarget.LoggedInPermanent) PermanentChild(permanentNavModel = permanentNavModel, navTarget = NavTarget.LoggedInPermanent)

View file

@ -20,7 +20,6 @@ import android.os.Parcelable
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import coil.Coil import coil.Coil
import com.bumble.appyx.core.composable.Children
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.node.Node import com.bumble.appyx.core.node.Node
@ -33,8 +32,8 @@ import io.element.android.anvilannotations.ContributesNode
import io.element.android.features.login.api.LoginEntryPoint import io.element.android.features.login.api.LoginEntryPoint
import io.element.android.features.onboarding.api.OnBoardingEntryPoint import io.element.android.features.onboarding.api.OnBoardingEntryPoint
import io.element.android.features.preferences.api.ConfigureTracingEntryPoint import io.element.android.features.preferences.api.ConfigureTracingEntryPoint
import io.element.android.libraries.architecture.BackstackNode import io.element.android.libraries.architecture.BackstackView
import io.element.android.libraries.architecture.animation.rememberDefaultTransitionHandler import io.element.android.libraries.architecture.BaseFlowNode
import io.element.android.libraries.di.AppScope import io.element.android.libraries.di.AppScope
import io.element.android.libraries.matrix.ui.media.NotLoggedInImageLoaderFactory import io.element.android.libraries.matrix.ui.media.NotLoggedInImageLoaderFactory
import kotlinx.parcelize.Parcelize import kotlinx.parcelize.Parcelize
@ -47,7 +46,7 @@ class NotLoggedInFlowNode @AssistedInject constructor(
private val configureTracingEntryPoint: ConfigureTracingEntryPoint, private val configureTracingEntryPoint: ConfigureTracingEntryPoint,
private val loginEntryPoint: LoginEntryPoint, private val loginEntryPoint: LoginEntryPoint,
private val notLoggedInImageLoaderFactory: NotLoggedInImageLoaderFactory, private val notLoggedInImageLoaderFactory: NotLoggedInImageLoaderFactory,
) : BackstackNode<NotLoggedInFlowNode.NavTarget>( ) : BaseFlowNode<NotLoggedInFlowNode.NavTarget>(
backstack = BackStack( backstack = BackStack(
initialElement = NavTarget.OnBoarding, initialElement = NavTarget.OnBoarding,
savedStateMap = buildContext.savedStateMap savedStateMap = buildContext.savedStateMap
@ -111,11 +110,6 @@ class NotLoggedInFlowNode @AssistedInject constructor(
@Composable @Composable
override fun View(modifier: Modifier) { override fun View(modifier: Modifier) {
Children( BackstackView()
navModel = backstack,
modifier = modifier,
// Animate navigation to login screen
transitionHandler = rememberDefaultTransitionHandler(),
)
} }
} }

View file

@ -24,7 +24,6 @@ import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.lifecycle.lifecycleScope import androidx.lifecycle.lifecycleScope
import com.bumble.appyx.core.composable.Children
import com.bumble.appyx.core.modality.BuildContext import com.bumble.appyx.core.modality.BuildContext
import com.bumble.appyx.core.node.Node import com.bumble.appyx.core.node.Node
import com.bumble.appyx.core.node.node import com.bumble.appyx.core.node.node
@ -46,8 +45,8 @@ import io.element.android.features.login.api.oidc.OidcAction
import io.element.android.features.login.api.oidc.OidcActionFlow import io.element.android.features.login.api.oidc.OidcActionFlow
import io.element.android.features.rageshake.api.bugreport.BugReportEntryPoint import io.element.android.features.rageshake.api.bugreport.BugReportEntryPoint
import io.element.android.features.signedout.api.SignedOutEntryPoint import io.element.android.features.signedout.api.SignedOutEntryPoint
import io.element.android.libraries.architecture.BackstackNode import io.element.android.libraries.architecture.BackstackView
import io.element.android.libraries.architecture.animation.rememberDefaultTransitionHandler import io.element.android.libraries.architecture.BaseFlowNode
import io.element.android.libraries.architecture.createNode import io.element.android.libraries.architecture.createNode
import io.element.android.libraries.architecture.waitForChildAttached import io.element.android.libraries.architecture.waitForChildAttached
import io.element.android.libraries.deeplink.DeeplinkData import io.element.android.libraries.deeplink.DeeplinkData
@ -74,7 +73,7 @@ class RootFlowNode @AssistedInject constructor(
private val signedOutEntryPoint: SignedOutEntryPoint, private val signedOutEntryPoint: SignedOutEntryPoint,
private val intentResolver: IntentResolver, private val intentResolver: IntentResolver,
private val oidcActionFlow: OidcActionFlow, private val oidcActionFlow: OidcActionFlow,
) : BackstackNode<RootFlowNode.NavTarget>( ) : BaseFlowNode<RootFlowNode.NavTarget>(
backstack = BackStack( backstack = BackStack(
initialElement = NavTarget.SplashScreen, initialElement = NavTarget.SplashScreen,
savedStateMap = buildContext.savedStateMap, savedStateMap = buildContext.savedStateMap,
@ -134,8 +133,8 @@ class RootFlowNode @AssistedInject constructor(
private suspend fun restoreSessionIfNeeded( private suspend fun restoreSessionIfNeeded(
sessionId: SessionId, sessionId: SessionId,
onFailure: () -> Unit = {}, onFailure: () -> Unit,
onSuccess: (SessionId) -> Unit = {}, onSuccess: (SessionId) -> Unit,
) { ) {
matrixClientsHolder.getOrRestore(sessionId) matrixClientsHolder.getOrRestore(sessionId)
.onSuccess { .onSuccess {
@ -149,8 +148,8 @@ class RootFlowNode @AssistedInject constructor(
} }
private suspend fun tryToRestoreLatestSession( private suspend fun tryToRestoreLatestSession(
onSuccess: (SessionId) -> Unit = {}, onSuccess: (SessionId) -> Unit,
onFailure: () -> Unit = {} onFailure: () -> Unit
) { ) {
val latestSessionId = authenticationService.getLatestSessionId() val latestSessionId = authenticationService.getLatestSessionId()
if (latestSessionId == null) { if (latestSessionId == null) {
@ -172,11 +171,7 @@ class RootFlowNode @AssistedInject constructor(
modifier = modifier, modifier = modifier,
onOpenBugReport = this::onOpenBugReport, onOpenBugReport = this::onOpenBugReport,
) { ) {
Children( BackstackView()
navModel = backstack,
// Animate opening the bug report screen
transitionHandler = rememberDefaultTransitionHandler(),
)
} }
} }

View file

@ -34,6 +34,8 @@ class IntentResolver @Inject constructor(
private val oidcIntentResolver: OidcIntentResolver private val oidcIntentResolver: OidcIntentResolver
) { ) {
fun resolve(intent: Intent): ResolvedIntent? { fun resolve(intent: Intent): ResolvedIntent? {
if (intent.canBeIgnored()) return null
val deepLinkData = deeplinkParser.getFromIntent(intent) val deepLinkData = deeplinkParser.getFromIntent(intent)
if (deepLinkData != null) return ResolvedIntent.Navigation(deepLinkData) if (deepLinkData != null) return ResolvedIntent.Navigation(deepLinkData)
@ -45,3 +47,8 @@ class IntentResolver @Inject constructor(
return null return null
} }
} }
private fun Intent.canBeIgnored(): Boolean {
return action == Intent.ACTION_MAIN &&
categories?.contains(Intent.CATEGORY_LAUNCHER) == true
}

View file

@ -25,8 +25,8 @@ import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
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.libraries.designsystem.preview.PreviewsDayNight
import io.element.android.libraries.designsystem.preview.ElementPreview import io.element.android.libraries.designsystem.preview.ElementPreview
import io.element.android.libraries.designsystem.preview.PreviewsDayNight
@Composable @Composable
fun LoggedInView( fun LoggedInView(

View file

@ -33,12 +33,12 @@ import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import io.element.android.libraries.designsystem.preview.PreviewsDayNight import io.element.android.compound.theme.ElementTheme
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.theme.components.CircularProgressIndicator import io.element.android.libraries.designsystem.theme.components.CircularProgressIndicator
import io.element.android.libraries.designsystem.theme.components.Surface import io.element.android.libraries.designsystem.theme.components.Surface
import io.element.android.libraries.designsystem.theme.components.Text import io.element.android.libraries.designsystem.theme.components.Text
import io.element.android.libraries.theme.ElementTheme
import io.element.android.libraries.ui.strings.CommonStrings import io.element.android.libraries.ui.strings.CommonStrings
@Composable @Composable

View file

@ -30,17 +30,17 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource import androidx.compose.ui.res.stringResource
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.theme.ElementTheme
import io.element.android.features.networkmonitor.api.ui.ConnectivityIndicatorView import io.element.android.features.networkmonitor.api.ui.ConnectivityIndicatorView
import io.element.android.libraries.designsystem.atomic.molecules.IconTitlePlaceholdersRowMolecule import io.element.android.libraries.designsystem.atomic.molecules.IconTitlePlaceholdersRowMolecule
import io.element.android.libraries.designsystem.components.avatar.AvatarSize import io.element.android.libraries.designsystem.components.avatar.AvatarSize
import io.element.android.libraries.designsystem.components.button.BackButton import io.element.android.libraries.designsystem.components.button.BackButton
import io.element.android.libraries.designsystem.preview.PreviewsDayNight
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.theme.components.CircularProgressIndicator import io.element.android.libraries.designsystem.theme.components.CircularProgressIndicator
import io.element.android.libraries.designsystem.theme.components.Scaffold import io.element.android.libraries.designsystem.theme.components.Scaffold
import io.element.android.libraries.designsystem.theme.components.Text import io.element.android.libraries.designsystem.theme.components.Text
import io.element.android.libraries.designsystem.theme.components.TopAppBar import io.element.android.libraries.designsystem.theme.components.TopAppBar
import io.element.android.libraries.theme.ElementTheme
import io.element.android.libraries.ui.strings.CommonStrings import io.element.android.libraries.ui.strings.CommonStrings
@OptIn(ExperimentalLayoutApi::class) @OptIn(ExperimentalLayoutApi::class)

View file

@ -25,7 +25,6 @@ import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue import androidx.compose.runtime.getValue
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.lifecycle.lifecycleScope import androidx.lifecycle.lifecycleScope
import com.bumble.appyx.core.composable.Children
import com.bumble.appyx.core.modality.BuildContext import com.bumble.appyx.core.modality.BuildContext
import com.bumble.appyx.core.node.Node import com.bumble.appyx.core.node.Node
import com.bumble.appyx.core.node.node import com.bumble.appyx.core.node.node
@ -38,7 +37,8 @@ import dagger.assisted.AssistedInject
import io.element.android.anvilannotations.ContributesNode import io.element.android.anvilannotations.ContributesNode
import io.element.android.features.networkmonitor.api.NetworkMonitor import io.element.android.features.networkmonitor.api.NetworkMonitor
import io.element.android.features.networkmonitor.api.NetworkStatus import io.element.android.features.networkmonitor.api.NetworkStatus
import io.element.android.libraries.architecture.BackstackNode import io.element.android.libraries.architecture.BackstackView
import io.element.android.libraries.architecture.BaseFlowNode
import io.element.android.libraries.architecture.NodeInputs import io.element.android.libraries.architecture.NodeInputs
import io.element.android.libraries.architecture.createNode import io.element.android.libraries.architecture.createNode
import io.element.android.libraries.architecture.inputs import io.element.android.libraries.architecture.inputs
@ -57,7 +57,7 @@ class RoomFlowNode @AssistedInject constructor(
loadingRoomStateFlowFactory: LoadingRoomStateFlowFactory, loadingRoomStateFlowFactory: LoadingRoomStateFlowFactory,
private val networkMonitor: NetworkMonitor, private val networkMonitor: NetworkMonitor,
) : ) :
BackstackNode<RoomFlowNode.NavTarget>( BaseFlowNode<RoomFlowNode.NavTarget>(
backstack = BackStack( backstack = BackStack(
initialElement = NavTarget.Loading, initialElement = NavTarget.Loading,
savedStateMap = buildContext.savedStateMap, savedStateMap = buildContext.savedStateMap,
@ -130,10 +130,7 @@ class RoomFlowNode @AssistedInject constructor(
@Composable @Composable
override fun View(modifier: Modifier) { override fun View(modifier: Modifier) {
Children( BackstackView()
navModel = backstack,
modifier = modifier,
)
} }
} }

View file

@ -22,7 +22,6 @@ import androidx.compose.runtime.DisposableEffect
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.lifecycle.Lifecycle import androidx.lifecycle.Lifecycle
import androidx.lifecycle.lifecycleScope import androidx.lifecycle.lifecycleScope
import com.bumble.appyx.core.composable.Children
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.node.Node import com.bumble.appyx.core.node.Node
@ -35,9 +34,9 @@ import io.element.android.anvilannotations.ContributesNode
import io.element.android.appnav.di.RoomComponentFactory import io.element.android.appnav.di.RoomComponentFactory
import io.element.android.features.messages.api.MessagesEntryPoint import io.element.android.features.messages.api.MessagesEntryPoint
import io.element.android.features.roomdetails.api.RoomDetailsEntryPoint import io.element.android.features.roomdetails.api.RoomDetailsEntryPoint
import io.element.android.libraries.architecture.BackstackNode import io.element.android.libraries.architecture.BackstackView
import io.element.android.libraries.architecture.BaseFlowNode
import io.element.android.libraries.architecture.NodeInputs import io.element.android.libraries.architecture.NodeInputs
import io.element.android.libraries.architecture.animation.rememberDefaultTransitionHandler
import io.element.android.libraries.architecture.inputs import io.element.android.libraries.architecture.inputs
import io.element.android.libraries.di.DaggerComponentOwner import io.element.android.libraries.di.DaggerComponentOwner
import io.element.android.libraries.di.SessionScope import io.element.android.libraries.di.SessionScope
@ -64,7 +63,7 @@ class RoomLoadedFlowNode @AssistedInject constructor(
private val appCoroutineScope: CoroutineScope, private val appCoroutineScope: CoroutineScope,
roomComponentFactory: RoomComponentFactory, roomComponentFactory: RoomComponentFactory,
roomMembershipObserver: RoomMembershipObserver, roomMembershipObserver: RoomMembershipObserver,
) : BackstackNode<RoomLoadedFlowNode.NavTarget>( ) : BaseFlowNode<RoomLoadedFlowNode.NavTarget>(
backstack = BackStack( backstack = BackStack(
initialElement = plugins.filterIsInstance(Inputs::class.java).first().initialElement, initialElement = plugins.filterIsInstance(Inputs::class.java).first().initialElement,
savedStateMap = buildContext.savedStateMap, savedStateMap = buildContext.savedStateMap,
@ -74,6 +73,7 @@ class RoomLoadedFlowNode @AssistedInject constructor(
), DaggerComponentOwner { ), DaggerComponentOwner {
interface Callback : Plugin { interface Callback : Plugin {
fun onOpenRoom(roomId: RoomId)
fun onForwardedToSingleRoom(roomId: RoomId) fun onForwardedToSingleRoom(roomId: RoomId)
fun onOpenGlobalNotificationSettings() fun onOpenGlobalNotificationSettings()
} }
@ -134,6 +134,10 @@ class RoomLoadedFlowNode @AssistedInject constructor(
override fun onOpenGlobalNotificationSettings() { override fun onOpenGlobalNotificationSettings() {
callbacks.forEach { it.onOpenGlobalNotificationSettings() } callbacks.forEach { it.onOpenGlobalNotificationSettings() }
} }
override fun onOpenRoom(roomId: RoomId) {
callbacks.forEach { it.onOpenRoom(roomId) }
}
} }
return roomDetailsEntryPoint.nodeBuilder(this, buildContext) return roomDetailsEntryPoint.nodeBuilder(this, buildContext)
.params(RoomDetailsEntryPoint.Params(initialTarget)) .params(RoomDetailsEntryPoint.Params(initialTarget))
@ -197,10 +201,6 @@ class RoomLoadedFlowNode @AssistedInject constructor(
} }
} }
} }
Children( BackstackView()
navModel = backstack,
modifier = modifier,
transitionHandler = rememberDefaultTransitionHandler(),
)
} }
} }

View file

@ -27,16 +27,16 @@ import io.element.android.features.rageshake.api.crash.CrashDetectionEvents
import io.element.android.features.rageshake.api.crash.CrashDetectionView import io.element.android.features.rageshake.api.crash.CrashDetectionView
import io.element.android.features.rageshake.api.detection.RageshakeDetectionEvents import io.element.android.features.rageshake.api.detection.RageshakeDetectionEvents
import io.element.android.features.rageshake.api.detection.RageshakeDetectionView import io.element.android.features.rageshake.api.detection.RageshakeDetectionView
import io.element.android.libraries.designsystem.preview.PreviewsDayNight
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.theme.components.Text import io.element.android.libraries.designsystem.theme.components.Text
import io.element.android.services.apperror.impl.AppErrorView import io.element.android.services.apperror.impl.AppErrorView
@Composable @Composable
fun RootView( fun RootView(
state: RootState, state: RootState,
onOpenBugReport: () -> Unit,
modifier: Modifier = Modifier, modifier: Modifier = Modifier,
onOpenBugReport: () -> Unit = {},
children: @Composable BoxScope.() -> Unit, children: @Composable BoxScope.() -> Unit,
) { ) {
Box( Box(
@ -69,7 +69,10 @@ fun RootView(
@PreviewsDayNight @PreviewsDayNight
@Composable @Composable
internal fun RootPreview(@PreviewParameter(RootStateProvider::class) rootState: RootState) = ElementPreview { internal fun RootPreview(@PreviewParameter(RootStateProvider::class) rootState: RootState) = ElementPreview {
RootView(rootState) { RootView(
state = rootState,
onOpenBugReport = {},
) {
Text("Children") Text("Children")
} }
} }

View file

@ -25,7 +25,7 @@ import com.bumble.appyx.core.plugin.Plugin
import com.bumble.appyx.navmodel.backstack.activeElement import com.bumble.appyx.navmodel.backstack.activeElement
import com.bumble.appyx.testing.junit4.util.MainDispatcherRule import com.bumble.appyx.testing.junit4.util.MainDispatcherRule
import com.bumble.appyx.testing.unit.common.helper.parentNodeTestHelper import com.bumble.appyx.testing.unit.common.helper.parentNodeTestHelper
import com.google.common.truth.Truth import com.google.common.truth.Truth.assertThat
import io.element.android.appnav.di.RoomComponentFactory import io.element.android.appnav.di.RoomComponentFactory
import io.element.android.appnav.room.RoomLoadedFlowNode import io.element.android.appnav.room.RoomLoadedFlowNode
import io.element.android.features.messages.api.MessagesEntryPoint import io.element.android.features.messages.api.MessagesEntryPoint
@ -83,7 +83,7 @@ class RoomFlowNodeTest {
} }
override fun build(): Node { override fun build(): Node {
return node(buildContext) {}.also { return node(buildContext) {}.also {
nodeId = it.id nodeId = it.id
} }
} }
@ -122,10 +122,10 @@ class RoomFlowNodeTest {
val roomFlowNodeTestHelper = roomFlowNode.parentNodeTestHelper() val roomFlowNodeTestHelper = roomFlowNode.parentNodeTestHelper()
// THEN // THEN
Truth.assertThat(roomFlowNode.backstack.activeElement).isEqualTo(RoomLoadedFlowNode.NavTarget.Messages) assertThat(roomFlowNode.backstack.activeElement).isEqualTo(RoomLoadedFlowNode.NavTarget.Messages)
roomFlowNodeTestHelper.assertChildHasLifecycle(RoomLoadedFlowNode.NavTarget.Messages, Lifecycle.State.CREATED) roomFlowNodeTestHelper.assertChildHasLifecycle(RoomLoadedFlowNode.NavTarget.Messages, Lifecycle.State.CREATED)
val messagesNode = roomFlowNode.childNode(RoomLoadedFlowNode.NavTarget.Messages)!! val messagesNode = roomFlowNode.childNode(RoomLoadedFlowNode.NavTarget.Messages)!!
Truth.assertThat(messagesNode.id).isEqualTo(fakeMessagesEntryPoint.nodeId) assertThat(messagesNode.id).isEqualTo(fakeMessagesEntryPoint.nodeId)
} }
@Test @Test
@ -147,6 +147,6 @@ class RoomFlowNodeTest {
// THEN // THEN
roomFlowNodeTestHelper.assertChildHasLifecycle(RoomLoadedFlowNode.NavTarget.RoomDetails, Lifecycle.State.CREATED) roomFlowNodeTestHelper.assertChildHasLifecycle(RoomLoadedFlowNode.NavTarget.RoomDetails, Lifecycle.State.CREATED)
val roomDetailsNode = roomFlowNode.childNode(RoomLoadedFlowNode.NavTarget.RoomDetails)!! val roomDetailsNode = roomFlowNode.childNode(RoomLoadedFlowNode.NavTarget.RoomDetails)!!
Truth.assertThat(roomDetailsNode.id).isEqualTo(fakeRoomDetailsEntryPoint.nodeId) assertThat(roomDetailsNode.id).isEqualTo(fakeRoomDetailsEntryPoint.nodeId)
} }
} }

View file

@ -0,0 +1,184 @@
/*
* Copyright (c) 2023 New Vector Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.element.android.appnav.intent
import android.app.Activity
import android.content.Intent
import androidx.core.net.toUri
import com.google.common.truth.Truth.assertThat
import io.element.android.features.login.api.oidc.OidcAction
import io.element.android.features.login.impl.oidc.DefaultOidcIntentResolver
import io.element.android.features.login.impl.oidc.OidcUrlParser
import io.element.android.libraries.deeplink.DeepLinkCreator
import io.element.android.libraries.deeplink.DeeplinkData
import io.element.android.libraries.deeplink.DeeplinkParser
import io.element.android.libraries.matrix.test.A_ROOM_ID
import io.element.android.libraries.matrix.test.A_SESSION_ID
import io.element.android.libraries.matrix.test.A_THREAD_ID
import org.junit.Assert.assertThrows
import org.junit.Test
import org.junit.runner.RunWith
import org.robolectric.RobolectricTestRunner
import org.robolectric.RuntimeEnvironment
@RunWith(RobolectricTestRunner::class)
class IntentResolverTest {
@Test
fun `resolve launcher intent should return null`() {
val sut = createIntentResolver()
val intent = Intent(RuntimeEnvironment.getApplication(), Activity::class.java).apply {
action = Intent.ACTION_MAIN
addCategory(Intent.CATEGORY_LAUNCHER)
}
val result = sut.resolve(intent)
assertThat(result).isNull()
}
@Test
fun `test resolve navigation intent root`() {
val sut = createIntentResolver()
val intent = Intent(RuntimeEnvironment.getApplication(), Activity::class.java).apply {
action = Intent.ACTION_VIEW
data = DeepLinkCreator().room(
sessionId = A_SESSION_ID,
roomId = null,
threadId = null,
)
.toUri()
}
val result = sut.resolve(intent)
assertThat(result).isEqualTo(
ResolvedIntent.Navigation(
deeplinkData = DeeplinkData.Root(
sessionId = A_SESSION_ID,
)
)
)
}
@Test
fun `test resolve navigation intent room`() {
val sut = createIntentResolver()
val intent = Intent(RuntimeEnvironment.getApplication(), Activity::class.java).apply {
action = Intent.ACTION_VIEW
data = DeepLinkCreator().room(
sessionId = A_SESSION_ID,
roomId = A_ROOM_ID,
threadId = null,
)
.toUri()
}
val result = sut.resolve(intent)
assertThat(result).isEqualTo(
ResolvedIntent.Navigation(
deeplinkData = DeeplinkData.Room(
sessionId = A_SESSION_ID,
roomId = A_ROOM_ID,
threadId = null,
)
)
)
}
@Test
fun `test resolve navigation intent thread`() {
val sut = createIntentResolver()
val intent = Intent(RuntimeEnvironment.getApplication(), Activity::class.java).apply {
action = Intent.ACTION_VIEW
data = DeepLinkCreator().room(
sessionId = A_SESSION_ID,
roomId = A_ROOM_ID,
threadId = A_THREAD_ID,
)
.toUri()
}
val result = sut.resolve(intent)
assertThat(result).isEqualTo(
ResolvedIntent.Navigation(
deeplinkData = DeeplinkData.Room(
sessionId = A_SESSION_ID,
roomId = A_ROOM_ID,
threadId = A_THREAD_ID,
)
)
)
}
@Test
fun `test resolve oidc go back`() {
val sut = createIntentResolver()
val intent = Intent(RuntimeEnvironment.getApplication(), Activity::class.java).apply {
action = Intent.ACTION_VIEW
data = "io.element:/callback?error=access_denied&state=IFF1UETGye2ZA8pO".toUri()
}
val result = sut.resolve(intent)
assertThat(result).isEqualTo(
ResolvedIntent.Oidc(
oidcAction = OidcAction.GoBack
)
)
}
@Test
fun `test resolve oidc success`() {
val sut = createIntentResolver()
val intent = Intent(RuntimeEnvironment.getApplication(), Activity::class.java).apply {
action = Intent.ACTION_VIEW
data = "io.element:/callback?state=IFF1UETGye2ZA8pO&code=y6X1GZeqA3xxOWcTeShgv8nkgFJXyzWB".toUri()
}
val result = sut.resolve(intent)
assertThat(result).isEqualTo(
ResolvedIntent.Oidc(
oidcAction = OidcAction.Success(
url = "io.element:/callback?state=IFF1UETGye2ZA8pO&code=y6X1GZeqA3xxOWcTeShgv8nkgFJXyzWB"
)
)
)
}
@Test
fun `test resolve oidc invalid`() {
val sut = createIntentResolver()
val intent = Intent(RuntimeEnvironment.getApplication(), Activity::class.java).apply {
action = Intent.ACTION_VIEW
data = "io.element:/callback/invalid".toUri()
}
assertThrows(IllegalStateException::class.java) {
sut.resolve(intent)
}
}
@Test
fun `test resolve invalid`() {
val sut = createIntentResolver()
val intent = Intent(RuntimeEnvironment.getApplication(), Activity::class.java).apply {
action = Intent.ACTION_VIEW
data = "io.element:/invalid".toUri()
}
val result = sut.resolve(intent)
assertThat(result).isNull()
}
private fun createIntentResolver(): IntentResolver {
return IntentResolver(
deeplinkParser = DeeplinkParser(),
oidcIntentResolver = DefaultOidcIntentResolver(
oidcUrlParser = OidcUrlParser()
),
)
}
}

View file

@ -60,8 +60,9 @@ class LoggedInPresenterTest {
}.test { }.test {
val initialState = awaitItem() val initialState = awaitItem()
assertThat(initialState.showSyncSpinner).isFalse() assertThat(initialState.showSyncSpinner).isFalse()
roomListService.postSyncIndicator(RoomListService.SyncIndicator.Show)
consumeItemsUntilPredicate { it.showSyncSpinner } consumeItemsUntilPredicate { it.showSyncSpinner }
roomListService.postState(RoomListService.State.Running) roomListService.postSyncIndicator(RoomListService.SyncIndicator.Hide)
consumeItemsUntilPredicate { !it.showSyncSpinner } consumeItemsUntilPredicate { !it.showSyncSpinner }
} }
} }

View file

@ -17,7 +17,7 @@
package io.element.android.appnav.room package io.element.android.appnav.room
import app.cash.turbine.test import app.cash.turbine.test
import com.google.common.truth.Truth import com.google.common.truth.Truth.assertThat
import io.element.android.libraries.matrix.api.roomlist.RoomList import io.element.android.libraries.matrix.api.roomlist.RoomList
import io.element.android.libraries.matrix.test.A_ROOM_ID 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
@ -39,8 +39,8 @@ class LoadingRoomStateFlowFactoryTest {
flowFactory flowFactory
.create(this, A_ROOM_ID) .create(this, A_ROOM_ID)
.test { .test {
Truth.assertThat(awaitItem()).isEqualTo(LoadingRoomState.Loading) assertThat(awaitItem()).isEqualTo(LoadingRoomState.Loading)
Truth.assertThat(awaitItem()).isEqualTo(LoadingRoomState.Loaded(room)) assertThat(awaitItem()).isEqualTo(LoadingRoomState.Loaded(room))
} }
} }
@ -53,10 +53,10 @@ class LoadingRoomStateFlowFactoryTest {
flowFactory flowFactory
.create(this, A_ROOM_ID) .create(this, A_ROOM_ID)
.test { .test {
Truth.assertThat(awaitItem()).isEqualTo(LoadingRoomState.Loading) assertThat(awaitItem()).isEqualTo(LoadingRoomState.Loading)
matrixClient.givenGetRoomResult(A_ROOM_ID, room) matrixClient.givenGetRoomResult(A_ROOM_ID, room)
roomListService.postAllRoomsLoadingState(RoomList.LoadingState.Loaded(1)) roomListService.postAllRoomsLoadingState(RoomList.LoadingState.Loaded(1))
Truth.assertThat(awaitItem()).isEqualTo(LoadingRoomState.Loaded(room)) assertThat(awaitItem()).isEqualTo(LoadingRoomState.Loaded(room))
} }
} }
@ -68,12 +68,9 @@ class LoadingRoomStateFlowFactoryTest {
flowFactory flowFactory
.create(this, A_ROOM_ID) .create(this, A_ROOM_ID)
.test { .test {
Truth.assertThat(awaitItem()).isEqualTo(LoadingRoomState.Loading) assertThat(awaitItem()).isEqualTo(LoadingRoomState.Loading)
roomListService.postAllRoomsLoadingState(RoomList.LoadingState.Loaded(1)) roomListService.postAllRoomsLoadingState(RoomList.LoadingState.Loaded(1))
Truth.assertThat(awaitItem()).isEqualTo(LoadingRoomState.Error) assertThat(awaitItem()).isEqualTo(LoadingRoomState.Error)
} }
} }
} }

View file

@ -62,7 +62,7 @@ allprojects {
config.from(files("$rootDir/tools/detekt/detekt.yml")) config.from(files("$rootDir/tools/detekt/detekt.yml"))
} }
dependencies { dependencies {
detektPlugins("io.nlopez.compose.rules:detekt:0.3.3") detektPlugins("io.nlopez.compose.rules:detekt:0.3.8")
} }
// KtLint // KtLint
@ -130,10 +130,10 @@ sonar {
property("sonar.host.url", "https://sonarcloud.io") property("sonar.host.url", "https://sonarcloud.io")
property("sonar.projectVersion", "1.0") // TODO project(":app").android.defaultConfig.versionName) property("sonar.projectVersion", "1.0") // TODO project(":app").android.defaultConfig.versionName)
property("sonar.sourceEncoding", "UTF-8") property("sonar.sourceEncoding", "UTF-8")
property("sonar.links.homepage", "https://github.com/vector-im/element-x-android/") property("sonar.links.homepage", "https://github.com/element-hq/element-x-android/")
property("sonar.links.ci", "https://github.com/vector-im/element-x-android/actions") property("sonar.links.ci", "https://github.com/element-hq/element-x-android/actions")
property("sonar.links.scm", "https://github.com/vector-im/element-x-android/") property("sonar.links.scm", "https://github.com/element-hq/element-x-android/")
property("sonar.links.issue", "https://github.com/vector-im/element-x-android/issues") property("sonar.links.issue", "https://github.com/element-hq/element-x-android/issues")
property("sonar.organization", "new_vector_ltd_organization") property("sonar.organization", "new_vector_ltd_organization")
property("sonar.login", if (project.hasProperty("SONAR_LOGIN")) project.property("SONAR_LOGIN")!! else "invalid") property("sonar.login", if (project.hasProperty("SONAR_LOGIN")) project.property("SONAR_LOGIN")!! else "invalid")
@ -236,11 +236,11 @@ koverMerged {
name = "Global minimum code coverage." name = "Global minimum code coverage."
target = kotlinx.kover.api.VerificationTarget.ALL target = kotlinx.kover.api.VerificationTarget.ALL
bound { bound {
minValue = 60 minValue = 65
// Setting a max value, so that if coverage is bigger, it means that we have to change minValue. // Setting a max value, so that if coverage is bigger, it means that we have to change minValue.
// For instance if we have minValue = 20 and maxValue = 30, and current code coverage is now 31.32%, update // For instance if we have minValue = 20 and maxValue = 30, and current code coverage is now 31.32%, update
// minValue to 25 and maxValue to 35. // minValue to 25 and maxValue to 35.
maxValue = 70 maxValue = 75
counter = kotlinx.kover.api.CounterType.INSTRUCTION counter = kotlinx.kover.api.CounterType.INSTRUCTION
valueType = kotlinx.kover.api.VerificationValueType.COVERED_PERCENTAGE valueType = kotlinx.kover.api.VerificationValueType.COVERED_PERCENTAGE
} }
@ -376,3 +376,22 @@ subprojects {
} }
} }
} }
subprojects {
tasks.withType<org.jetbrains.kotlin.gradle.tasks.KotlinCompile>().configureEach {
kotlinOptions {
if (project.findProperty("composeCompilerReports") == "true") {
freeCompilerArgs += listOf(
"-P",
"plugin:androidx.compose.compiler.plugins.kotlin:reportsDestination=${project.layout.buildDirectory.asFile.get().absolutePath}/compose_compiler"
)
}
if (project.findProperty("composeCompilerMetrics") == "true") {
freeCompilerArgs += listOf(
"-P",
"plugin:androidx.compose.compiler.plugins.kotlin:metricsDestination=${project.layout.buildDirectory.asFile.get().absolutePath}/compose_compiler"
)
}
}
}
}

View file

@ -117,7 +117,7 @@ You can also have access to the aars through the [release](https://github.com/ma
#### Build the SDK locally #### Build the SDK locally
Easiest way: run the script [./tools/sdk/build_rust_sdk.sh](./tools/sdk/build_rust_sdk.sh) and just answer the questions. Easiest way: run the script [../tools/sdk/build_rust_sdk.sh](../tools/sdk/build_rust_sdk.sh) and just answer the questions.
Legacy way: Legacy way:
@ -322,7 +322,7 @@ We are using [Gradle version catalog](https://docs.gradle.org/current/userguide/
All the dependencies (including android artifact, gradle plugin, etc.) should be declared in [../gradle/libs.versions.toml](libs.versions.toml) file. All the dependencies (including android artifact, gradle plugin, etc.) should be declared in [../gradle/libs.versions.toml](libs.versions.toml) file.
Some dependency, mainly because they are not shared can be declared in `build.gradle.kts` files. Some dependency, mainly because they are not shared can be declared in `build.gradle.kts` files.
[Renovate](https://github.com/apps/renovate) is set up on the project. This tool will automatically create Pull Request to upgrade our dependencies one by one. A [dependency dashboard issue](https://github.com/vector-im/element-x-android/issues/150) is maintained by the tool and allow to perform some actions. [Renovate](https://github.com/apps/renovate) is set up on the project. This tool will automatically create Pull Request to upgrade our dependencies one by one. A [dependency dashboard issue](https://github.com/element-hq/element-x-android/issues/150) is maintained by the tool and allow to perform some actions.
### Test ### Test

View file

@ -63,7 +63,7 @@ bundle exec danger pr <PR_URL> --dangerfile=./tools/danger/dangerfile.js
For instance: For instance:
```shell ```shell
bundle exec danger pr https://github.com/vector-im/element-android/pull/6637 --dangerfile=./tools/danger/dangerfile.js bundle exec danger pr https://github.com/element-hq/element-android/pull/6637 --dangerfile=./tools/danger/dangerfile.js
``` ```
We may need to create a GitHub token to have less API rate limiting, and then set the env var: We may need to create a GitHub token to have less API rate limiting, and then set the env var:
@ -84,7 +84,7 @@ bundle exec danger-kotlin pr <PR_URL> --dangerfile=./tools/danger/dangerfile.js
To let Danger check all the PRs, including PRs form forks, a GitHub account have been created: To let Danger check all the PRs, including PRs form forks, a GitHub account have been created:
- login: ElementBot - login: ElementBot
- password: Stored on Passbolt - password: Stored on Passbolt
- GitHub token: A token with limited access has been created and added to the repository https://github.com/vector-im/element-android as secret DANGER_GITHUB_API_TOKEN. This token is not saved anywhere else. In case of problem, just delete it and create a new one, then update the secret. - GitHub token: A token with limited access has been created and added to the repository https://github.com/element-hq/element-x-android as secret DANGER_GITHUB_API_TOKEN. This token is not saved anywhere else. In case of problem, just delete it and create a new one, then update the secret.
PRs from forks do not always have access to the secret `secrets.DANGER_GITHUB_API_TOKEN`, so `secrets.GITHUB_TOKEN` is also provided to the job environment. If `secrets.DANGER_GITHUB_API_TOKEN` is available, it will be used, so user `ElementBot` will comment the PR. Else `secrets.GITHUB_TOKEN` will be used, and bot `github-actions` will comment the PR. PRs from forks do not always have access to the secret `secrets.DANGER_GITHUB_API_TOKEN`, so `secrets.GITHUB_TOKEN` is also provided to the job environment. If `secrets.DANGER_GITHUB_API_TOKEN` is available, it will be used, so user `ElementBot` will comment the PR. Else `secrets.GITHUB_TOKEN` will be used, and bot `github-actions` will comment the PR.

View file

@ -8,15 +8,15 @@
1) Disable "Use Android Studio HTTP proxy settings" and pick "Manual proxy configuration". 1) Disable "Use Android Studio HTTP proxy settings" and pick "Manual proxy configuration".
1) Set `127.0.0.1` as "Host name" and `8080` as "Port number". 1) Set `127.0.0.1` as "Host name" and `8080` as "Port number".
1) Click "Apply" and verify that "Proxy status" is "Success" and close the settings window. 1) Click "Apply" and verify that "Proxy status" is "Success" and close the settings window.
<img width="932" alt="Screenshot 2023-10-04 at 14 48 47" src="https://github.com/vector-im/element-x-android/assets/1273124/bf99a053-20b0-42a4-91d3-9602f709f684"> <img width="932" alt="Screenshot 2023-10-04 at 14 48 47" src="https://github.com/element-hq/element-x-android/assets/1273124/bf99a053-20b0-42a4-91d3-9602f709f684">
1) Install the mitmproxy CA cert (this is needed to see traffic from java/kotlin code, it's not needed for traffic coming from native code e.g. the matrix-rust-sdk). 1) Install the mitmproxy CA cert (this is needed to see traffic from java/kotlin code, it's not needed for traffic coming from native code e.g. the matrix-rust-sdk).
1) Open the emulator Chrome browser app 1) Open the emulator Chrome browser app
1) Go to the url `mitm.it` 1) Go to the url `mitm.it`
1) Follow the instructions to install the CA cert on Android devices. 1) Follow the instructions to install the CA cert on Android devices.
<img width="606" alt="Screenshot 2023-10-04 at 14 51 27" src="https://github.com/vector-im/element-x-android/assets/1273124/5f2b6f27-6958-4ea7-97fe-c7f06d105da5"> <img width="606" alt="Screenshot 2023-10-04 at 14 51 27" src="https://github.com/element-hq/element-x-android/assets/1273124/5f2b6f27-6958-4ea7-97fe-c7f06d105da5">
1) Slightly modify the Element X app source code. 1) Slightly modify the Element X app source code.
1) Go to the `RustMatrixClientFactory.create()` method. 1) Go to the `RustMatrixClientFactory.create()` method.
1) Add `.disableSslVerification()` in the `ClientBuilder` method chain. 1) Add `.disableSslVerification()` in the `ClientBuilder` method chain.
1) Build and run the Element X app. 1) Build and run the Element X app.
1) Enjoy, you will see all the traffic in mitmproxy's web interface. 1) Enjoy, you will see all the traffic in mitmproxy's web interface.
<img width="1110" alt="Screenshot 2023-10-04 at 14 50 03" src="https://github.com/vector-im/element-x-android/assets/1273124/5d039efd-448d-426c-a384-dbbceb9f33ac"> <img width="1110" alt="Screenshot 2023-10-04 at 14 50 03" src="https://github.com/element-hq/element-x-android/assets/1273124/5d039efd-448d-426c-a384-dbbceb9f33ac">

View file

@ -64,7 +64,7 @@ A comprehensive [color definition documentation](https://compound.element.io/?pa
Most icons should be available as part of the [Compound icon library](https://compound.element.io/?path=/docs/tokens-icons--docs) Most icons should be available as part of the [Compound icon library](https://compound.element.io/?path=/docs/tokens-icons--docs)
All drawable are auto-generated as part of the design tokens library. You can find All drawable are auto-generated as part of the design tokens library. You can find
all assets in [`vector-im/compound-design-tokens#assets/android`](https://github.com/vector-im/compound-design-tokens/tree/develop/assets/android) all assets in [`element-hq/compound-design-tokens#assets/android`](https://github.com/element-hq/compound-design-tokens/tree/main/assets/android)
If you are missing an icon, follow to [contribution guidelines for icons](https://www.figma.com/file/gkNXqPoiJhEv2wt0EJpew4/Compound-Icons?type=design&node-id=178-3119&t=j2uSJD9xPXJn5aRM-0) If you are missing an icon, follow to [contribution guidelines for icons](https://www.figma.com/file/gkNXqPoiJhEv2wt0EJpew4/Compound-Icons?type=design&node-id=178-3119&t=j2uSJD9xPXJn5aRM-0)

View file

@ -18,11 +18,11 @@ The easiest way to do that is to use the debug signature that is shared between
You can clone the project by running: You can clone the project by running:
```bash ```bash
git clone git@github.com:vector-im/element-x-android.git git clone git@github.com:element-hq/element-x-android.git
``` ```
or or
```bash ```bash
git clone https://github.com/vector-im/element-x-android.git git clone https://github.com/element-hq/element-x-android.git
``` ```
You will also need to install [bundletool](https://developer.android.com/studio/command-line/bundletool). On MacOS, you can run the following command: You will also need to install [bundletool](https://developer.android.com/studio/command-line/bundletool). On MacOS, you can run the following command:
@ -33,7 +33,7 @@ brew install bundletool
## Steps ## Steps
1. Open the GitHub release that you want to install from https://github.com/vector-im/element-x-android/releases 1. Open the GitHub release that you want to install from https://github.com/element-hq/element-x-android/releases
2. Download the asset `app-release-signed.aab` 2. Download the asset `app-release-signed.aab`
3. Navigate to the folder where you cloned the project and run the following command: 3. Navigate to the folder where you cloned the project and run the following command:
```bash ```bash

View file

@ -1,14 +1,14 @@
This file contains some rough notes about Oidc implementation, with some examples of actual data. This file contains some rough notes about Oidc implementation, with some examples of actual data.
[ios implementation](https://github.com/vector-im/element-x-ios/compare/develop...doug/oidc-temp) [ios implementation](https://github.com/element-hq/element-x-ios/compare/develop...doug/oidc-temp)
Rust sdk branch: https://github.com/matrix-org/matrix-rust-sdk/tree/oidc-ffi Rust sdk branch: https://github.com/matrix-org/matrix-rust-sdk/tree/oidc-ffi
Figma https://www.figma.com/file/o9p34zmiuEpZRyvZXJZAYL/FTUE?node-id=133-5426&t=yQXKeANatk6keoZF-0 Figma https://www.figma.com/file/o9p34zmiuEpZRyvZXJZAYL/FTUE?node-id=133-5426&t=yQXKeANatk6keoZF-0
Server list: https://github.com/vector-im/oidc-playground Server list: https://github.com/element-hq/oidc-playground
Metadata iOS: (from https://github.com/vector-im/element-x-ios/blob/5f9d07377cebc4f21d9668b1a25f6e3bb22f64a1/ElementX/Sources/Services/Authentication/AuthenticationServiceProxy.swift#L28) Metadata iOS: (from https://github.com/element-hq/element-x-ios/blob/5f9d07377cebc4f21d9668b1a25f6e3bb22f64a1/ElementX/Sources/Services/Authentication/AuthenticationServiceProxy.swift#L28)
clientName: InfoPlistReader.main.bundleDisplayName, clientName: InfoPlistReader.main.bundleDisplayName,
redirectUri: "io.element:/callback", redirectUri: "io.element:/callback",

View file

@ -86,13 +86,13 @@ Exceptions can occur:
We use automatic assignment for PR reviews. **A PR is automatically routed by GitHub to one team member** using the round robin algorithm. Additional reviewers can be used for complex changes or when the first reviewer is not confident enough on the changes. We use automatic assignment for PR reviews. **A PR is automatically routed by GitHub to one team member** using the round robin algorithm. Additional reviewers can be used for complex changes or when the first reviewer is not confident enough on the changes.
The process is the following: The process is the following:
- The PR creator selects the [element-x-android-reviewers](https://github.com/orgs/vector-im/teams/element-x-android-reviewers) team as a reviewer. - The PR creator selects the [element-x-android-reviewers](https://github.com/orgs/element-hq/teams/element-x-android-reviewers) team as a reviewer.
- GitHub automatically assign the reviewer. If the reviewer is not available (holiday, etc.), remove them and set again the team, GitHub will select another reviewer. - GitHub automatically assign the reviewer. If the reviewer is not available (holiday, etc.), remove them and set again the team, GitHub will select another reviewer.
- Alternatively, the PR creator can directly assign specific people if they have another Android developer in their team or they think a specific reviewer should take a look at their PR. - Alternatively, the PR creator can directly assign specific people if they have another Android developer in their team or they think a specific reviewer should take a look at their PR.
- Reviewers get a notification to make the review: they review the code following the good practice (see the rest of this document). - Reviewers get a notification to make the review: they review the code following the good practice (see the rest of this document).
- After making their own review, if they feel not confident enough, they can ask another person for a full review, or they can tag someone within a PR comment to check specific lines. - After making their own review, if they feel not confident enough, they can ask another person for a full review, or they can tag someone within a PR comment to check specific lines.
For PRs coming from the community, the issue wrangler can assign either the team [element-x-android-reviewers](https://github.com/orgs/vector-im/teams/element-x-android-reviewers) or any member directly. For PRs coming from the community, the issue wrangler can assign either the team [element-x-android-reviewers](https://github.com/orgs/element-hq/teams/element-x-android-reviewers) or any member directly.
##### PR review time ##### PR review time

View file

@ -30,7 +30,7 @@ If installed correctly, `git push` and `git pull` will now include LFS content.
## Recording ## Recording
Recording of screenshots is done by triggering the GitHub action [Record screenshots](https://github.com/vector-im/element-x-android/actions/workflows/recordScreenshots.yml), to avoid differences of generated binary files (png images) depending on developers' environment. Recording of screenshots is done by triggering the GitHub action [Record screenshots](https://github.com/element-hq/element-x-android/actions/workflows/recordScreenshots.yml), to avoid differences of generated binary files (png images) depending on developers' environment.
So basically, you will create a branch, do some commits with your work on it, then push your branch, trigger the GitHub action to record the screenshots (only if you think preview may have changed), and finally create a pull request. The GitHub action will record the screenshots and commit the changes to the branch. So basically, you will create a branch, do some commits with your work on it, then push your branch, trigger the GitHub action to record the screenshots (only if you think preview may have changed), and finally create a pull request. The GitHub action will record the screenshots and commit the changes to the branch.

View file

@ -1,2 +1,2 @@
First release of Element X 🚀! First release of Element X 🚀!
Full changelog: https://github.com/vector-im/element-x-android/releases Full changelog: https://github.com/element-hq/element-x-android/releases

View file

@ -1,2 +1,2 @@
Main changes in this version: bug fixes and add OIDC support. Main changes in this version: bug fixes and add OIDC support.
Full changelog: https://github.com/vector-im/element-x-android/releases Full changelog: https://github.com/element-hq/element-x-android/releases

View file

@ -1,2 +1,2 @@
Main changes in this version: bug fixes and add OIDC support. Main changes in this version: bug fixes and add OIDC support.
Full changelog: https://github.com/vector-im/element-x-android/releases Full changelog: https://github.com/element-hq/element-x-android/releases

View file

@ -1,2 +1,2 @@
Main changes in this version: bugfixes. Main changes in this version: bugfixes.
Full changelog: https://github.com/vector-im/element-x-android/releases Full changelog: https://github.com/element-hq/element-x-android/releases

View file

@ -1,2 +1,2 @@
Main changes in this version: Element Call, design update, bugfixes Main changes in this version: Element Call, design update, bugfixes
Full changelog: https://github.com/vector-im/element-x-android/releases Full changelog: https://github.com/element-hq/element-x-android/releases

View file

@ -1,2 +1,2 @@
Main changes in this version: Element Call, design update, bugfixes Main changes in this version: Element Call, design update, bugfixes
Full changelog: https://github.com/vector-im/element-x-android/releases Full changelog: https://github.com/element-hq/element-x-android/releases

View file

@ -1,2 +1,2 @@
Main changes in this version: bugfixes Main changes in this version: bugfixes
Full changelog: https://github.com/vector-im/element-x-android/releases Full changelog: https://github.com/element-hq/element-x-android/releases

View file

@ -1,2 +1,2 @@
Main changes in this version: bugfixes. Main changes in this version: bugfixes.
Full changelog: https://github.com/vector-im/element-x-android/releases Full changelog: https://github.com/element-hq/element-x-android/releases

View file

@ -1,2 +1,2 @@
Main changes in this version: bugfixes. Main changes in this version: bugfixes.
Full changelog: https://github.com/vector-im/element-x-android/releases Full changelog: https://github.com/element-hq/element-x-android/releases

View file

@ -1,2 +1,2 @@
Main changes in this version: Element Call, voice message. Main changes in this version: Element Call, voice message.
Full changelog: https://github.com/vector-im/element-x-android/releases Full changelog: https://github.com/element-hq/element-x-android/releases

View file

@ -1,2 +1,2 @@
Main changes in this version: Mainly bug fixes. Main changes in this version: Mainly bug fixes.
Full changelog: https://github.com/vector-im/element-x-android/releases Full changelog: https://github.com/element-hq/element-x-android/releases

View file

@ -4,4 +4,4 @@ Main changes in this version:
- Adding mentions to a message is now possible, but it's disabled by default as it's a work in progress. They can be enabled in the developer options. - Adding mentions to a message is now possible, but it's disabled by default as it's a work in progress. They can be enabled in the developer options.
- Voice messages behavior changed: there is no need to keep pressing to record, to start recording a message just tap on the mic button, then tap again to stop recording. - Voice messages behavior changed: there is no need to keep pressing to record, to start recording a message just tap on the mic button, then tap again to stop recording.
- Added a marker in the timeline to indicate the starting point of the room messages. - Added a marker in the timeline to indicate the starting point of the room messages.
Full changelog: https://github.com/vector-im/element-x-android/releases Full changelog: https://github.com/element-hq/element-x-android/releases

View file

@ -0,0 +1,13 @@
Main changes in this version:
- New timeline messages rendering.
- Added support for user mentions.
- Enabled chat backup so you can restore previous message history.
- Added read receipts.
- Several improvements to polls, including poll history.
- Several UI/UX improvements.
- Set a default power level to join room calls.
- Added an option to disable notifications for invites.
- Fixed a bug with the text composer and suggestions on Android 14.
Full changelog: https://github.com/element-hq/element-x-android/releases

View file

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="screen_analytics_settings_share_data">"Elemzési adatok megosztása"</string>
<string name="screen_analytics_settings_help_us_improve">"Anonim használati adatok megosztása a problémák azonosítása érdekében."</string>
<string name="screen_analytics_settings_read_terms">"%1$s olvashatja el a feltételeinket."</string>
<string name="screen_analytics_settings_read_terms_content_link">"Itt"</string>
</resources>

View file

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="screen_analytics_settings_share_data">"Bagikan data analitik"</string>
<string name="screen_analytics_settings_help_us_improve">"Bagikan data penggunaan anonim untuk membantu kami mengidentifikasi masalah."</string>
<string name="screen_analytics_settings_read_terms">"Anda dapat membaca semua persyaratan kami %1$s."</string>
<string name="screen_analytics_settings_read_terms_content_link">"di sini"</string>
</resources>

View file

@ -39,6 +39,7 @@ dependencies {
implementation(projects.libraries.uiStrings) implementation(projects.libraries.uiStrings)
api(projects.features.analytics.api) api(projects.features.analytics.api)
api(projects.services.analytics.api) api(projects.services.analytics.api)
implementation(projects.appconfig)
implementation(libs.androidx.datastore.preferences) implementation(libs.androidx.datastore.preferences)
implementation(libs.androidx.browser) implementation(libs.androidx.browser)
ksp(libs.showkase.processor) ksp(libs.showkase.processor)

View file

@ -17,7 +17,6 @@
package io.element.android.features.analytics.impl package io.element.android.features.analytics.impl
import android.app.Activity import android.app.Activity
import androidx.compose.material.MaterialTheme
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.platform.LocalContext
@ -27,7 +26,8 @@ import com.bumble.appyx.core.plugin.Plugin
import dagger.assisted.Assisted import dagger.assisted.Assisted
import dagger.assisted.AssistedInject import dagger.assisted.AssistedInject
import io.element.android.anvilannotations.ContributesNode import io.element.android.anvilannotations.ContributesNode
import io.element.android.features.analytics.api.Config import io.element.android.appconfig.AnalyticsConfig
import io.element.android.compound.theme.ElementTheme
import io.element.android.libraries.androidutils.browser.openUrlInChromeCustomTab import io.element.android.libraries.androidutils.browser.openUrlInChromeCustomTab
import io.element.android.libraries.di.AppScope import io.element.android.libraries.di.AppScope
@ -39,13 +39,13 @@ class AnalyticsOptInNode @AssistedInject constructor(
) : Node(buildContext, plugins = plugins) { ) : Node(buildContext, plugins = plugins) {
private fun onClickTerms(activity: Activity, darkTheme: Boolean) { private fun onClickTerms(activity: Activity, darkTheme: Boolean) {
activity.openUrlInChromeCustomTab(null, darkTheme, Config.POLICY_LINK) activity.openUrlInChromeCustomTab(null, darkTheme, AnalyticsConfig.POLICY_LINK)
} }
@Composable @Composable
override fun View(modifier: Modifier) { override fun View(modifier: Modifier) {
val activity = LocalContext.current as Activity val activity = LocalContext.current as Activity
val isDark = MaterialTheme.colors.isLight.not() val isDark = ElementTheme.isLightTheme.not()
val state = presenter.present() val state = presenter.present()
AnalyticsOptInView( AnalyticsOptInView(
state = state, state = state,

View file

@ -40,24 +40,24 @@ import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.text.style.TextAlign
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.appconfig.AnalyticsConfig
import io.element.android.compound.theme.ElementTheme
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.features.analytics.api.Config
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.InfoListItem
import io.element.android.libraries.designsystem.atomic.organisms.InfoListOrganism 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.preview.PreviewsDayNight
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.text.buildAnnotatedStringWithStyledPart import io.element.android.libraries.designsystem.text.buildAnnotatedStringWithStyledPart
import io.element.android.libraries.designsystem.theme.components.Button import io.element.android.libraries.designsystem.theme.components.Button
import io.element.android.libraries.designsystem.theme.components.ButtonSize import io.element.android.libraries.designsystem.theme.components.ButtonSize
import io.element.android.libraries.designsystem.theme.components.Icon import io.element.android.libraries.designsystem.theme.components.Icon
import io.element.android.libraries.designsystem.theme.components.TextButton import io.element.android.libraries.designsystem.theme.components.TextButton
import io.element.android.libraries.designsystem.theme.temporaryColorBgSpecial import io.element.android.libraries.designsystem.theme.temporaryColorBgSpecial
import io.element.android.libraries.designsystem.utils.CommonDrawables
import io.element.android.libraries.designsystem.utils.LogCompositions import io.element.android.libraries.designsystem.utils.LogCompositions
import io.element.android.libraries.theme.ElementTheme
import io.element.android.libraries.ui.strings.CommonStrings import io.element.android.libraries.ui.strings.CommonStrings
import kotlinx.collections.immutable.persistentListOf import kotlinx.collections.immutable.persistentListOf
@ -119,7 +119,7 @@ private fun AnalyticsOptInHeader(
color = Color.Unspecified, color = Color.Unspecified,
underline = false, underline = false,
bold = true, bold = true,
tagAndLink = LINK_TAG to Config.POLICY_LINK, tagAndLink = LINK_TAG to AnalyticsConfig.POLICY_LINK,
) )
ClickableText( ClickableText(
text = text, text = text,
@ -147,7 +147,7 @@ private fun CheckIcon(modifier: Modifier = Modifier) {
.size(20.dp) .size(20.dp)
.background(color = MaterialTheme.colorScheme.background, shape = CircleShape) .background(color = MaterialTheme.colorScheme.background, shape = CircleShape)
.padding(2.dp), .padding(2.dp),
resourceId = CommonDrawables.ic_compound_check, imageVector = CompoundIcons.Check,
contentDescription = null, contentDescription = null,
tint = ElementTheme.colors.textActionAccent, tint = ElementTheme.colors.textActionAccent,
) )

View file

@ -20,8 +20,8 @@ import androidx.compose.runtime.Composable
import androidx.compose.runtime.collectAsState import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.runtime.rememberCoroutineScope
import com.squareup.anvil.annotations.ContributesBinding import com.squareup.anvil.annotations.ContributesBinding
import io.element.android.appconfig.AnalyticsConfig
import io.element.android.features.analytics.api.AnalyticsOptInEvents import io.element.android.features.analytics.api.AnalyticsOptInEvents
import io.element.android.features.analytics.api.Config
import io.element.android.features.analytics.api.preferences.AnalyticsPreferencesPresenter import io.element.android.features.analytics.api.preferences.AnalyticsPreferencesPresenter
import io.element.android.features.analytics.api.preferences.AnalyticsPreferencesState import io.element.android.features.analytics.api.preferences.AnalyticsPreferencesState
import io.element.android.libraries.core.meta.BuildMeta import io.element.android.libraries.core.meta.BuildMeta
@ -52,7 +52,7 @@ class DefaultAnalyticsPreferencesPresenter @Inject constructor(
return AnalyticsPreferencesState( return AnalyticsPreferencesState(
applicationName = buildMeta.applicationName, applicationName = buildMeta.applicationName,
isEnabled = isEnabled.value, isEnabled = isEnabled.value,
policyUrl = Config.POLICY_LINK, policyUrl = AnalyticsConfig.POLICY_LINK,
eventSink = ::handleEvents eventSink = ::handleEvents
) )
} }

View file

@ -0,0 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="screen_analytics_prompt_data_usage">"Nem rögzítünk vagy profilozunk személyes adatokat"</string>
<string name="screen_analytics_prompt_help_us_improve">"Anonim használati adatok megosztása a problémák azonosítása érdekében."</string>
<string name="screen_analytics_prompt_read_terms">"%1$s olvashatja el a feltételeinket."</string>
<string name="screen_analytics_prompt_read_terms_content_link">"Itt"</string>
<string name="screen_analytics_prompt_settings">"Ezt bármikor kikapcsolhatja"</string>
<string name="screen_analytics_prompt_third_party_sharing">"Adatait nem osztjuk meg harmadik felekkel"</string>
<string name="screen_analytics_prompt_title">"Segítsen az %1$s fejlesztésében"</string>
</resources>

View file

@ -0,0 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="screen_analytics_prompt_data_usage">"Kami tidak akan merekam atau memprofil data pribadi apa pun"</string>
<string name="screen_analytics_prompt_help_us_improve">"Bagikan data penggunaan anonim untuk membantu kami mengidentifikasi masalah."</string>
<string name="screen_analytics_prompt_read_terms">"Anda dapat membaca semua persyaratan kami %1$s."</string>
<string name="screen_analytics_prompt_read_terms_content_link">"di sini"</string>
<string name="screen_analytics_prompt_settings">"Anda dapat mematikan ini kapan saja"</string>
<string name="screen_analytics_prompt_third_party_sharing">"Kami tidak akan membagikan data Anda dengan pihak ketiga"</string>
<string name="screen_analytics_prompt_title">"Bantu sempurnakan %1$s"</string>
</resources>

View file

@ -16,7 +16,7 @@
package io.element.android.features.cachecleaner.impl package io.element.android.features.cachecleaner.impl
import com.google.common.truth.Truth import com.google.common.truth.Truth.assertThat
import io.element.android.tests.testutils.testCoroutineDispatchers import io.element.android.tests.testutils.testCoroutineDispatchers
import kotlinx.coroutines.test.TestScope import kotlinx.coroutines.test.TestScope
import kotlinx.coroutines.test.runTest import kotlinx.coroutines.test.runTest
@ -46,9 +46,9 @@ class DefaultCacheCleanerTest {
// Check the files are gone but the sub dirs are not. // Check the files are gone but the sub dirs are not.
DefaultCacheCleaner.SUBDIRS_TO_CLEANUP.forEach { DefaultCacheCleaner.SUBDIRS_TO_CLEANUP.forEach {
File(temporaryFolder.root, it).apply { File(temporaryFolder.root, it).apply {
Truth.assertThat(exists()).isTrue() assertThat(exists()).isTrue()
Truth.assertThat(isDirectory).isTrue() assertThat(isDirectory).isTrue()
Truth.assertThat(listFiles()).isEmpty() assertThat(listFiles()).isEmpty()
} }
} }
} }

View file

@ -33,6 +33,7 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalInspectionMode import androidx.compose.ui.platform.LocalInspectionMode
import androidx.compose.ui.res.stringResource import androidx.compose.ui.res.stringResource
import androidx.compose.ui.viewinterop.AndroidView import androidx.compose.ui.viewinterop.AndroidView
import io.element.android.compound.tokens.generated.CompoundIcons
import io.element.android.features.call.R import io.element.android.features.call.R
import io.element.android.features.call.utils.WebViewWidgetMessageInterceptor import io.element.android.features.call.utils.WebViewWidgetMessageInterceptor
import io.element.android.libraries.architecture.Async import io.element.android.libraries.architecture.Async
@ -42,7 +43,6 @@ import io.element.android.libraries.designsystem.preview.PreviewsDayNight
import io.element.android.libraries.designsystem.theme.components.Scaffold import io.element.android.libraries.designsystem.theme.components.Scaffold
import io.element.android.libraries.designsystem.theme.components.Text import io.element.android.libraries.designsystem.theme.components.Text
import io.element.android.libraries.designsystem.theme.components.TopAppBar import io.element.android.libraries.designsystem.theme.components.TopAppBar
import io.element.android.libraries.designsystem.utils.CommonDrawables
typealias RequestPermissionCallback = (Array<String>) -> Unit typealias RequestPermissionCallback = (Array<String>) -> Unit
@ -64,7 +64,7 @@ internal fun CallScreenView(
title = { Text(stringResource(R.string.element_call)) }, title = { Text(stringResource(R.string.element_call)) },
navigationIcon = { navigationIcon = {
BackButton( BackButton(
resourceId = CommonDrawables.ic_compound_close, imageVector = CompoundIcons.Close,
onClick = { state.eventSink(CallScreenEvents.Hangup) } onClick = { state.eventSink(CallScreenEvents.Hangup) }
) )
} }

View file

@ -37,16 +37,16 @@ import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember import androidx.compose.runtime.remember
import androidx.core.content.IntentCompat import androidx.core.content.IntentCompat
import com.bumble.appyx.core.integrationpoint.NodeComponentActivity import com.bumble.appyx.core.integrationpoint.NodeComponentActivity
import io.element.android.compound.theme.ElementTheme
import io.element.android.compound.theme.Theme
import io.element.android.compound.theme.isDark
import io.element.android.compound.theme.mapToTheme
import io.element.android.features.call.CallForegroundService import io.element.android.features.call.CallForegroundService
import io.element.android.features.call.CallType import io.element.android.features.call.CallType
import io.element.android.features.call.di.CallBindings import io.element.android.features.call.di.CallBindings
import io.element.android.features.call.utils.CallIntentDataParser import io.element.android.features.call.utils.CallIntentDataParser
import io.element.android.features.preferences.api.store.PreferencesStore import io.element.android.features.preferences.api.store.PreferencesStore
import io.element.android.libraries.architecture.bindings import io.element.android.libraries.architecture.bindings
import io.element.android.libraries.theme.ElementTheme
import io.element.android.libraries.theme.theme.Theme
import io.element.android.libraries.theme.theme.isDark
import io.element.android.libraries.theme.theme.mapToTheme
import javax.inject.Inject import javax.inject.Inject
class ElementCallActivity : NodeComponentActivity(), CallScreenNavigator { class ElementCallActivity : NodeComponentActivity(), CallScreenNavigator {

View file

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="call_foreground_service_channel_title_android">"Folyamatban lévő hívás"</string>
<string name="call_foreground_service_message_android">"Koppintson a híváshoz való visszatéréshez"</string>
<string name="call_foreground_service_title_android">"☎️ Hívás folyamatban"</string>
</resources>

View file

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="call_foreground_service_channel_title_android">"Panggilan berlangsung"</string>
<string name="call_foreground_service_message_android">"Ketuk untuk kembali ke panggilan"</string>
<string name="call_foreground_service_title_android">"☎️ Panggilan sedang berlangsung"</string>
</resources>

View file

@ -39,7 +39,6 @@ class MapWebkitPermissionsTest {
@Test @Test
fun `given any other permission, it returns nothing`() { fun `given any other permission, it returns nothing`() {
val permission = mapWebkitPermissions(arrayOf(PermissionRequest.RESOURCE_PROTECTED_MEDIA_ID)) val permission = mapWebkitPermissions(arrayOf(PermissionRequest.RESOURCE_PROTECTED_MEDIA_ID))
assertThat(permission).isEqualTo(emptyList<String>()) assertThat(permission).isEmpty()
} }
} }

View file

@ -0,0 +1,31 @@
/*
* Copyright (c) 2023 New Vector Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.element.android.features.createroom.api
import androidx.compose.runtime.MutableState
import io.element.android.libraries.architecture.Async
import io.element.android.libraries.matrix.api.core.RoomId
import io.element.android.libraries.matrix.api.core.UserId
interface StartDMAction {
/**
* Try to find an existing DM with the given user, or create one if none exists.
* @param userId The user to start a DM with.
* @param actionState The state to update with the result of the action.
*/
suspend fun execute(userId: UserId, actionState: MutableState<Async<RoomId>>)
}

View file

@ -67,6 +67,7 @@ dependencies {
testImplementation(projects.libraries.mediaupload.test) testImplementation(projects.libraries.mediaupload.test)
testImplementation(projects.libraries.permissions.test) testImplementation(projects.libraries.permissions.test)
testImplementation(projects.libraries.usersearch.test) testImplementation(projects.libraries.usersearch.test)
testImplementation(projects.features.createroom.test)
testImplementation(projects.tests.testutils) testImplementation(projects.tests.testutils)
ksp(libs.showkase.processor) ksp(libs.showkase.processor)

View file

@ -19,7 +19,6 @@ package io.element.android.features.createroom.impl
import android.os.Parcelable import android.os.Parcelable
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import com.bumble.appyx.core.composable.Children
import com.bumble.appyx.core.modality.BuildContext import com.bumble.appyx.core.modality.BuildContext
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
@ -32,8 +31,8 @@ import io.element.android.anvilannotations.ContributesNode
import io.element.android.features.createroom.impl.addpeople.AddPeopleNode import io.element.android.features.createroom.impl.addpeople.AddPeopleNode
import io.element.android.features.createroom.impl.configureroom.ConfigureRoomNode import io.element.android.features.createroom.impl.configureroom.ConfigureRoomNode
import io.element.android.features.createroom.impl.di.CreateRoomComponent import io.element.android.features.createroom.impl.di.CreateRoomComponent
import io.element.android.libraries.architecture.BackstackNode import io.element.android.libraries.architecture.BackstackView
import io.element.android.libraries.architecture.animation.rememberDefaultTransitionHandler import io.element.android.libraries.architecture.BaseFlowNode
import io.element.android.libraries.architecture.bindings import io.element.android.libraries.architecture.bindings
import io.element.android.libraries.architecture.createNode import io.element.android.libraries.architecture.createNode
import io.element.android.libraries.di.DaggerComponentOwner import io.element.android.libraries.di.DaggerComponentOwner
@ -45,7 +44,7 @@ class ConfigureRoomFlowNode @AssistedInject constructor(
@Assisted buildContext: BuildContext, @Assisted buildContext: BuildContext,
@Assisted plugins: List<Plugin>, @Assisted plugins: List<Plugin>,
) : DaggerComponentOwner, ) : DaggerComponentOwner,
BackstackNode<ConfigureRoomFlowNode.NavTarget>( BaseFlowNode<ConfigureRoomFlowNode.NavTarget>(
backstack = BackStack( backstack = BackStack(
initialElement = NavTarget.Root, initialElement = NavTarget.Root,
savedStateMap = buildContext.savedStateMap, savedStateMap = buildContext.savedStateMap,
@ -77,21 +76,17 @@ class ConfigureRoomFlowNode @AssistedInject constructor(
backstack.push(NavTarget.ConfigureRoom) backstack.push(NavTarget.ConfigureRoom)
} }
} }
createNode<AddPeopleNode>(context = buildContext, plugins = listOf(callback)) createNode<AddPeopleNode>(buildContext = buildContext, plugins = listOf(callback))
} }
NavTarget.ConfigureRoom -> { NavTarget.ConfigureRoom -> {
val callbacks = plugins<ConfigureRoomNode.Callback>() val callbacks = plugins<ConfigureRoomNode.Callback>()
createNode<ConfigureRoomNode>(context = buildContext, plugins = callbacks) createNode<ConfigureRoomNode>(buildContext = buildContext, plugins = callbacks)
} }
} }
} }
@Composable @Composable
override fun View(modifier: Modifier) { override fun View(modifier: Modifier) {
Children( BackstackView()
navModel = backstack,
modifier = modifier,
transitionHandler = rememberDefaultTransitionHandler()
)
} }
} }

View file

@ -19,7 +19,6 @@ package io.element.android.features.createroom.impl
import android.os.Parcelable import android.os.Parcelable
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import com.bumble.appyx.core.composable.Children
import com.bumble.appyx.core.modality.BuildContext import com.bumble.appyx.core.modality.BuildContext
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
@ -32,8 +31,8 @@ import io.element.android.anvilannotations.ContributesNode
import io.element.android.features.createroom.api.CreateRoomEntryPoint import io.element.android.features.createroom.api.CreateRoomEntryPoint
import io.element.android.features.createroom.impl.configureroom.ConfigureRoomNode import io.element.android.features.createroom.impl.configureroom.ConfigureRoomNode
import io.element.android.features.createroom.impl.root.CreateRoomRootNode import io.element.android.features.createroom.impl.root.CreateRoomRootNode
import io.element.android.libraries.architecture.BackstackNode import io.element.android.libraries.architecture.BackstackView
import io.element.android.libraries.architecture.animation.rememberDefaultTransitionHandler import io.element.android.libraries.architecture.BaseFlowNode
import io.element.android.libraries.architecture.createNode import io.element.android.libraries.architecture.createNode
import io.element.android.libraries.di.SessionScope import io.element.android.libraries.di.SessionScope
import io.element.android.libraries.matrix.api.core.RoomId import io.element.android.libraries.matrix.api.core.RoomId
@ -43,7 +42,7 @@ import kotlinx.parcelize.Parcelize
class CreateRoomFlowNode @AssistedInject constructor( class CreateRoomFlowNode @AssistedInject constructor(
@Assisted buildContext: BuildContext, @Assisted buildContext: BuildContext,
@Assisted plugins: List<Plugin>, @Assisted plugins: List<Plugin>,
) : BackstackNode<CreateRoomFlowNode.NavTarget>( ) : BaseFlowNode<CreateRoomFlowNode.NavTarget>(
backstack = BackStack( backstack = BackStack(
initialElement = NavTarget.Root, initialElement = NavTarget.Root,
savedStateMap = buildContext.savedStateMap, savedStateMap = buildContext.savedStateMap,
@ -72,7 +71,7 @@ class CreateRoomFlowNode @AssistedInject constructor(
plugins<CreateRoomEntryPoint.Callback>().forEach { it.onSuccess(roomId) } plugins<CreateRoomEntryPoint.Callback>().forEach { it.onSuccess(roomId) }
} }
} }
createNode<CreateRoomRootNode>(context = buildContext, plugins = listOf(callback)) createNode<CreateRoomRootNode>(buildContext = buildContext, plugins = listOf(callback))
} }
NavTarget.NewRoom -> { NavTarget.NewRoom -> {
val callback = object : ConfigureRoomNode.Callback { val callback = object : ConfigureRoomNode.Callback {
@ -80,17 +79,13 @@ class CreateRoomFlowNode @AssistedInject constructor(
plugins<CreateRoomEntryPoint.Callback>().forEach { it.onSuccess(roomId) } plugins<CreateRoomEntryPoint.Callback>().forEach { it.onSuccess(roomId) }
} }
} }
createNode<ConfigureRoomFlowNode>(context = buildContext, plugins = listOf(callback)) createNode<ConfigureRoomFlowNode>(buildContext = buildContext, plugins = listOf(callback))
} }
} }
} }
@Composable @Composable
override fun View(modifier: Modifier) { override fun View(modifier: Modifier) {
Children( BackstackView()
navModel = backstack,
modifier = modifier,
transitionHandler = rememberDefaultTransitionHandler()
)
} }
} }

View file

@ -0,0 +1,53 @@
/*
* Copyright (c) 2023 New Vector Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.element.android.features.createroom.impl
import androidx.compose.runtime.MutableState
import com.squareup.anvil.annotations.ContributesBinding
import im.vector.app.features.analytics.plan.CreatedRoom
import io.element.android.features.createroom.api.StartDMAction
import io.element.android.libraries.architecture.Async
import io.element.android.libraries.di.SessionScope
import io.element.android.libraries.matrix.api.MatrixClient
import io.element.android.libraries.matrix.api.core.RoomId
import io.element.android.libraries.matrix.api.core.UserId
import io.element.android.libraries.matrix.api.room.StartDMResult
import io.element.android.libraries.matrix.api.room.startDM
import io.element.android.services.analytics.api.AnalyticsService
import javax.inject.Inject
@ContributesBinding(SessionScope::class)
class DefaultStartDMAction @Inject constructor(
private val matrixClient: MatrixClient,
private val analyticsService: AnalyticsService,
) : StartDMAction {
override suspend fun execute(userId: UserId, actionState: MutableState<Async<RoomId>>) {
actionState.value = Async.Loading()
when (val result = matrixClient.startDM(userId)) {
is StartDMResult.Success -> {
if (result.isNew) {
analyticsService.capture(CreatedRoom(isDM = true))
}
actionState.value = Async.Success(result.roomId)
}
is StartDMResult.Failure -> {
actionState.value = Async.Failure(result.throwable)
}
}
}
}

View file

@ -32,23 +32,23 @@ import io.element.android.features.createroom.impl.components.UserListView
import io.element.android.features.createroom.impl.userlist.UserListEvents import io.element.android.features.createroom.impl.userlist.UserListEvents
import io.element.android.features.createroom.impl.userlist.UserListState import io.element.android.features.createroom.impl.userlist.UserListState
import io.element.android.libraries.designsystem.components.button.BackButton import io.element.android.libraries.designsystem.components.button.BackButton
import io.element.android.libraries.designsystem.preview.PreviewsDayNight
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.theme.aliasScreenTitle import io.element.android.libraries.designsystem.theme.aliasScreenTitle
import io.element.android.libraries.designsystem.theme.components.Scaffold import io.element.android.libraries.designsystem.theme.components.Scaffold
import io.element.android.libraries.designsystem.theme.components.Text import io.element.android.libraries.designsystem.theme.components.Text
import io.element.android.libraries.designsystem.theme.components.TextButton import io.element.android.libraries.designsystem.theme.components.TextButton
import io.element.android.libraries.designsystem.theme.components.TopAppBar import io.element.android.libraries.designsystem.theme.components.TopAppBar
import io.element.android.libraries.theme.ElementTheme import io.element.android.compound.theme.ElementTheme
import io.element.android.libraries.ui.strings.CommonStrings import io.element.android.libraries.ui.strings.CommonStrings
@OptIn(ExperimentalLayoutApi::class) @OptIn(ExperimentalLayoutApi::class)
@Composable @Composable
fun AddPeopleView( fun AddPeopleView(
state: UserListState, state: UserListState,
onBackPressed: () -> Unit,
onNextPressed: () -> Unit,
modifier: Modifier = Modifier, modifier: Modifier = Modifier,
onBackPressed: () -> Unit = {},
onNextPressed: () -> Unit = {},
) { ) {
Scaffold( Scaffold(
modifier = modifier, modifier = modifier,
@ -77,6 +77,8 @@ fun AddPeopleView(
.fillMaxWidth(), .fillMaxWidth(),
state = state, state = state,
showBackButton = false, showBackButton = false,
onUserSelected = { },
onUserDeselected = {},
) )
} }
} }
@ -86,9 +88,9 @@ fun AddPeopleView(
@Composable @Composable
private fun AddPeopleViewTopBar( private fun AddPeopleViewTopBar(
hasSelectedUsers: Boolean, hasSelectedUsers: Boolean,
onBackPressed: () -> Unit,
onNextPressed: () -> Unit,
modifier: Modifier = Modifier, modifier: Modifier = Modifier,
onBackPressed: () -> Unit = {},
onNextPressed: () -> Unit = {},
) { ) {
TopAppBar( TopAppBar(
modifier = modifier, modifier = modifier,
@ -112,5 +114,9 @@ private fun AddPeopleViewTopBar(
@PreviewsDayNight @PreviewsDayNight
@Composable @Composable
internal fun AddPeopleViewPreview(@PreviewParameter(AddPeopleUserListStateProvider::class) state: UserListState) = ElementPreview { internal fun AddPeopleViewPreview(@PreviewParameter(AddPeopleUserListStateProvider::class) state: UserListState) = ElementPreview {
AddPeopleView(state = state) AddPeopleView(
state = state,
onBackPressed = {},
onNextPressed = {},
)
} }

View file

@ -36,14 +36,14 @@ import io.element.android.libraries.designsystem.preview.ElementPreview
import io.element.android.libraries.designsystem.theme.components.Icon import io.element.android.libraries.designsystem.theme.components.Icon
import io.element.android.libraries.designsystem.theme.components.RadioButton import io.element.android.libraries.designsystem.theme.components.RadioButton
import io.element.android.libraries.designsystem.theme.components.Text import io.element.android.libraries.designsystem.theme.components.Text
import io.element.android.libraries.theme.ElementTheme import io.element.android.compound.theme.ElementTheme
@Composable @Composable
fun RoomPrivacyOption( fun RoomPrivacyOption(
roomPrivacyItem: RoomPrivacyItem, roomPrivacyItem: RoomPrivacyItem,
onOptionSelected: (RoomPrivacyItem) -> Unit,
modifier: Modifier = Modifier, modifier: Modifier = Modifier,
isSelected: Boolean = false, isSelected: Boolean = false,
onOptionSelected: (RoomPrivacyItem) -> Unit = {},
) { ) {
Row( Row(
modifier modifier
@ -58,7 +58,7 @@ fun RoomPrivacyOption(
Icon( Icon(
modifier = Modifier.padding(horizontal = 8.dp), modifier = Modifier.padding(horizontal = 8.dp),
resourceId = roomPrivacyItem.icon, resourceId = roomPrivacyItem.icon,
contentDescription = "", contentDescription = null,
tint = MaterialTheme.colorScheme.secondary, tint = MaterialTheme.colorScheme.secondary,
) )
@ -97,10 +97,12 @@ internal fun RoomPrivacyOptionPreview() = ElementPreview {
Column { Column {
RoomPrivacyOption( RoomPrivacyOption(
roomPrivacyItem = aRoomPrivacyItem, roomPrivacyItem = aRoomPrivacyItem,
onOptionSelected = {},
isSelected = true, isSelected = true,
) )
RoomPrivacyOption( RoomPrivacyOption(
roomPrivacyItem = aRoomPrivacyItem, roomPrivacyItem = aRoomPrivacyItem,
onOptionSelected = {},
isSelected = false, isSelected = false,
) )
} }

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