Merge branch 'release/0.4.0'

This commit is contained in:
Jorge Martín 2023-12-22 13:23:18 +01:00
commit 48d53d7439
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
**/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
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]
body:
- type: markdown

View file

@ -5,7 +5,7 @@ body:
- type: markdown
attributes:
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
id: usecase
attributes:

View file

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

View file

@ -33,12 +33,12 @@ jobs:
# https://github.com/actions/checkout/issues/881
ref: ${{ github.event_name == 'pull_request' && github.event.pull_request.head.sha || github.ref }}
- name: Use JDK 17
uses: actions/setup-java@v3
uses: actions/setup-java@v4
with:
distribution: 'temurin' # See 'Supported distributions' for available options
java-version: '17'
- name: Configure gradle
uses: gradle/gradle-build-action@v2.9.0
uses: gradle/gradle-build-action@v2.11.1
with:
cache-read-only: ${{ github.ref != 'refs/heads/develop' }}
- name: Assemble debug APK
@ -50,7 +50,7 @@ jobs:
run: ./gradlew :app:assembleDebug -PallWarningsAsErrors=true $CI_GRADLE_ARG_PROPERTIES
- name: Upload APK APKs
if: ${{ matrix.variant == 'debug' }}
uses: actions/upload-artifact@v3
uses: actions/upload-artifact@v4
with:
name: elementx-debug
path: |

View file

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

View file

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

View file

@ -1,11 +1,10 @@
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.
# https://docs.github.com/en/actions/using-workflows/events-that-trigger-workflows#running-a-workflow-when-a-pull-request-is-approved
# 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.
on:
workflow_dispatch:
pull_request_review:
types: [submitted]
pull_request:
types: [labeled]
# Enrich gradle.properties for CI/CD
env:
@ -16,7 +15,7 @@ jobs:
maestro-cloud:
name: Maestro test suite
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:
fail-fast: false
# Allow one per PR.
@ -24,12 +23,17 @@ jobs:
group: ${{ format('maestro-{0}', github.ref) }}
cancel-in-progress: true
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
with:
# Ensure we are building the branch and not the branch after being merged on develop
# https://github.com/actions/checkout/issues/881
ref: ${{ github.event_name == 'pull_request' && github.event.pull_request.head.sha || github.ref }}
- uses: actions/setup-java@v3
- uses: actions/setup-java@v4
name: Use JDK 17
with:
distribution: 'temurin' # See 'Supported distributions' for available options

View file

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

View file

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

View file

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

View file

@ -2,6 +2,8 @@ name: Record screenshots
on:
workflow_dispatch:
pull_request:
types: [ labeled ]
# Enrich gradle.properties for CI/CD
env:
@ -9,26 +11,39 @@ env:
jobs:
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
if: github.event_name == 'workflow_dispatch' || github.event.label.name == 'Record-Screenshots'
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
with:
persist-credentials: false
- name: ☕️ Use JDK 17
uses: actions/setup-java@v3
uses: actions/setup-java@v4
with:
distribution: 'temurin' # See 'Supported distributions' for available options
java-version: '17'
# Add gradle cache, this should speed up the process
- name: Configure gradle
uses: gradle/gradle-build-action@v2.9.0
uses: gradle/gradle-build-action@v2.11.1
with:
cache-read-only: ${{ github.ref != 'refs/heads/develop' }}
- name: Record screenshots
run: "./.github/workflows/scripts/recordScreenshots.sh"
run: ./.github/workflows/scripts/recordScreenshots.sh
env:
GITHUB_TOKEN: ${{ secrets.DANGER_GITHUB_API_TOKEN }}
GITHUB_REPOSITORY: ${{ secrets.GITHUB_REPOSITORY }}

View file

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

View file

@ -48,6 +48,9 @@ do
esac
done
BRANCH=$(git rev-parse --abbrev-ref HEAD)
echo Branch used: $BRANCH
if [[ -z ${TOKEN} ]]; then
echo "No token specified, either set the env var GITHUB_TOKEN or use the --token option"
exit 1
@ -70,8 +73,6 @@ git config user.email "benoitm+elementbot@element.io"
git add -A
git commit -m "Update screenshots"
BRANCH=$(git rev-parse --abbrev-ref HEAD)
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!"

View file

@ -27,12 +27,12 @@ jobs:
# https://github.com/actions/checkout/issues/881
ref: ${{ github.event_name == 'pull_request' && github.event.pull_request.head.sha || github.ref }}
- name: Use JDK 17
uses: actions/setup-java@v3
uses: actions/setup-java@v4
with:
distribution: 'temurin' # See 'Supported distributions' for available options
java-version: '17'
- name: Configure gradle
uses: gradle/gradle-build-action@v2.9.0
uses: gradle/gradle-build-action@v2.11.1
with:
cache-read-only: ${{ github.ref != 'refs/heads/develop' }}
- name: 🔊 Publish results to Sonar

View file

@ -9,11 +9,11 @@ jobs:
sync-localazy:
runs-on: ubuntu-latest
# Skip in forks
if: github.repository == 'vector-im/element-x-android'
if: github.repository == 'element-hq/element-x-android'
steps:
- uses: actions/checkout@v4
- name: Set up Python 3.9
uses: actions/setup-python@v4
uses: actions/setup-python@v5
with:
python-version: 3.9
- 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
ref: ${{ github.event_name == 'pull_request' && github.event.pull_request.head.sha || github.ref }}
- name: ☕️ Use JDK 17
uses: actions/setup-java@v3
uses: actions/setup-java@v4
with:
distribution: 'temurin' # See 'Supported distributions' for available options
java-version: '17'
- name: Configure gradle
uses: gradle/gradle-build-action@v2.9.0
uses: gradle/gradle-build-action@v2.11.1
with:
cache-read-only: ${{ github.ref != 'refs/heads/develop' }}
@ -59,7 +59,7 @@ jobs:
- name: 🚫 Upload kover failed coverage reports
if: failure()
uses: actions/upload-artifact@v3
uses: actions/upload-artifact@v4
with:
name: kover-error-report
path: |
@ -71,7 +71,7 @@ jobs:
- name: 🚫 Upload test results on error
if: failure()
uses: actions/upload-artifact@v3
uses: actions/upload-artifact@v4
with:
name: tests-and-screenshot-tests-results
path: |

View file

@ -10,5 +10,5 @@ jobs:
steps:
- uses: actions/add-to-project@main
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 }}

View file

@ -10,11 +10,11 @@ jobs:
runs-on: ubuntu-latest
# Skip in forks
if: >
github.repository == 'vector-im/element-x-android'
github.repository == 'element-hq/element-x-android'
steps:
- uses: actions/add-to-project@main
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 }}
move_needs_info:
@ -24,7 +24,7 @@ jobs:
- uses: actions/add-to-project@main
id: addItem
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 }}
labeled: X-Needs-Info
- name: Print itemId
@ -32,7 +32,7 @@ jobs:
- uses: kalgurn/update-project-item-status@main
if: ${{ steps.addItem.outputs.itemId }}
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 }}
item-id: ${{ steps.addItem.outputs.itemId }}
status: "Needs info"
@ -45,7 +45,7 @@ jobs:
steps:
- uses: actions/add-to-project@main
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 }}
verticals_feature:
@ -56,7 +56,7 @@ jobs:
steps:
- uses: actions/add-to-project@main
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 }}
qa:
@ -68,7 +68,7 @@ jobs:
steps:
- uses: actions/add-to-project@main
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 }}
signoff:
@ -79,5 +79,5 @@ jobs:
steps:
- uses: actions/add-to-project@main
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 }}

2
.gitignore vendored
View file

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

View file

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

2
.idea/kotlinc.xml generated
View file

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="KotlinJpsPluginSettings">
<option name="version" value="1.9.20" />
<option name="version" value="1.9.21" />
</component>
</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:
id: "change_server-server"
# Test server that does not support sliding sync.
- inputText: "https://kieranml.ems-support.element.dev"
- inputText: "element"
- hideKeyboard
- tapOn: "kieranml.ems-support.element.dev"
- extendedWaitUntil:
visible: "This server currently doesnt support sliding sync."
timeout: 10000
- tapOn: "Cancel"
- back
- back
- tapOn: "element.io"
# Revert to matrix.org
- tapOn:
id: "login-change_server"
- tapOn: "matrix.org"

View file

@ -23,7 +23,7 @@ appId: ${APP_ID}
- tapOn:
text: ${INVITEE2_MXID}
index: 1
- tapOn: "Send"
- tapOn: "Invite"
- tapOn: "Back"
- tapOn: "aRoomName"
- 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:

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)
========================================
Features ✨
----------
- Add ongoing call indicator to rooms lists items. ([#1158](https://github.com/vector-im/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 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))
- 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))
- Add ongoing call indicator to rooms lists items. ([#1158](https://github.com/element-hq/element-x-android/issues/1158))
- Add support for typing mentions in the message composer. ([#1453](https://github.com/element-hq/element-x-android/issues/1453))
- Add intentional mentions to messages. This needs to be enabled in developer options since it's disabled by default. ([#1591](https://github.com/element-hq/element-x-android/issues/1591))
- Update voice message recording behaviour. Instead of holding the record button, users can now tap the record button to start recording and tap again to stop recording. ([#1784](https://github.com/element-hq/element-x-android/issues/1784))
Bugfixes 🐛
----------
- Always ensure media temp dir exists ([#1790](https://github.com/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
-------------
- Update icons and move away from `PreferenceText` components. ([#1718](https://github.com/vector-im/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))
- LockScreen : rework LoggedInFlowNode and back management when locked. ([#1806](https://github.com/vector-im/element-x-android/issues/1806))
- Suppress usage of removeTimeline method. ([#1824](https://github.com/vector-im/element-x-android/issues/1824))
- Update icons and move away from `PreferenceText` components. ([#1718](https://github.com/element-hq/element-x-android/issues/1718))
- Add item "This is the beginning of..." at the beginning of the timeline. ([#1801](https://github.com/element-hq/element-x-android/issues/1801))
- LockScreen : rework LoggedInFlowNode and back management when locked. ([#1806](https://github.com/element-hq/element-x-android/issues/1806))
- Suppress usage of removeTimeline method. ([#1824](https://github.com/element-hq/element-x-android/issues/1824))
- Remove Element Call feature flag, it's now always enabled.
- Reverted the EC base URL to `https://call.element.io`.
- Moved the option to override this URL to developer settings from advanced settings.
@ -28,16 +79,16 @@ Changes in Element X v0.3.1 (2023-11-09)
Features ✨
----------
- Chat backup is still under a feature flag, but when enabled, user can enter their recovery key (it's also possible to input a passphrase) to unlock the encrypted room history. ([#1770](https://github.com/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 🐛
----------
- Improve confusing text in the 'ready to start verification' screen. ([#879](https://github.com/vector-im/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))
- Improve confusing text in the 'ready to start verification' screen. ([#879](https://github.com/element-hq/element-x-android/issues/879))
- Message composer wasn't resized when selecting a several lines message to reply to, then a single line one. ([#1560](https://github.com/element-hq/element-x-android/issues/1560))
Other changes
-------------
- PIN: Set lock grace period to 0. ([#1732](https://github.com/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)
@ -45,24 +96,24 @@ Changes in Element X v0.3.0 (2023-10-31)
Features ✨
----------
- Element Call: change the 'join call' button in a chat room when there's an active call. ([#1158](https://github.com/vector-im/element-x-android/issues/1158))
- Mentions: add mentions suggestion view in RTE ([#1452](https://github.com/vector-im/element-x-android/issues/1452))
- Record and send voice messages ([#1596](https://github.com/vector-im/element-x-android/issues/1596))
- Enable voice messages for all users ([#1669](https://github.com/vector-im/element-x-android/issues/1669))
- Receive and play a voice message ([#2084](https://github.com/vector-im/element-x-android/issues/2084))
- Element Call: change the 'join call' button in a chat room when there's an active call. ([#1158](https://github.com/element-hq/element-x-android/issues/1158))
- Mentions: add mentions suggestion view in RTE ([#1452](https://github.com/element-hq/element-x-android/issues/1452))
- Record and send voice messages ([#1596](https://github.com/element-hq/element-x-android/issues/1596))
- Enable voice messages for all users ([#1669](https://github.com/element-hq/element-x-android/issues/1669))
- Receive and play a voice message ([#2084](https://github.com/element-hq/element-x-android/issues/2084))
- Enable Element Call integration in rooms by default, fix several issues when creating or joining calls.
Bugfixes 🐛
----------
- Group fallback notification to avoid having plenty of them displayed. ([#994](https://github.com/vector-im/element-x-android/issues/994))
- Hide keyboard when exiting the chat room screen. ([#1375](https://github.com/vector-im/element-x-android/issues/1375))
- Always register the pusher when application starts ([#1481](https://github.com/vector-im/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))
- Fix issue where text is cleared when cancelling a reply ([#1617](https://github.com/vector-im/element-x-android/issues/1617))
- Group fallback notification to avoid having plenty of them displayed. ([#994](https://github.com/element-hq/element-x-android/issues/994))
- Hide keyboard when exiting the chat room screen. ([#1375](https://github.com/element-hq/element-x-android/issues/1375))
- Always register the pusher when application starts ([#1481](https://github.com/element-hq/element-x-android/issues/1481))
- Ensure screen does not turn off when playing a video ([#1519](https://github.com/element-hq/element-x-android/issues/1519))
- Fix issue where text is cleared when cancelling a reply ([#1617](https://github.com/element-hq/element-x-android/issues/1617))
Other changes
-------------
- Remove usage of blocking methods. ([#1563](https://github.com/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)
@ -70,20 +121,20 @@ Changes in Element X v0.2.4 (2023-10-12)
Features ✨
----------
- [Rich text editor] Add full screen mode ([#1447](https://github.com/vector-im/element-x-android/issues/1447))
- Improve rendering of m.emote. ([#1497](https://github.com/vector-im/element-x-android/issues/1497))
- Improve deleted session behavior. ([#1520](https://github.com/vector-im/element-x-android/issues/1520))
- [Rich text editor] Add full screen mode ([#1447](https://github.com/element-hq/element-x-android/issues/1447))
- Improve rendering of m.emote. ([#1497](https://github.com/element-hq/element-x-android/issues/1497))
- Improve deleted session behavior. ([#1520](https://github.com/element-hq/element-x-android/issues/1520))
Bugfixes 🐛
----------
- WebP images can't be sent as media. ([#1483](https://github.com/vector-im/element-x-android/issues/1483))
- Fix back button not working in bottom sheets. ([#1517](https://github.com/vector-im/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))
- WebP images can't be sent as media. ([#1483](https://github.com/element-hq/element-x-android/issues/1483))
- Fix back button not working in bottom sheets. ([#1517](https://github.com/element-hq/element-x-android/issues/1517))
- Render body of unknown msgtype in the timeline and in the room list ([#1539](https://github.com/element-hq/element-x-android/issues/1539))
Other changes
-------------
- Room : makes subscribeToSync/unsubscribeFromSync suspendable. ([#1457](https://github.com/vector-im/element-x-android/issues/1457))
- Add some Konsist tests. ([#1526](https://github.com/vector-im/element-x-android/issues/1526))
- Room : makes subscribeToSync/unsubscribeFromSync suspendable. ([#1457](https://github.com/element-hq/element-x-android/issues/1457))
- Add some Konsist tests. ([#1526](https://github.com/element-hq/element-x-android/issues/1526))
Changes in Element X v0.2.3 (2023-09-27)
@ -91,12 +142,12 @@ Changes in Element X v0.2.3 (2023-09-27)
Features ✨
----------
- Handle installation of Apks from the media viewer. ([#1432](https://github.com/vector-im/element-x-android/pull/1432))
- Integrate SDK 0.1.58 ([#1437](https://github.com/vector-im/element-x-android/pull/1437))
- Handle installation of Apks from the media viewer. ([#1432](https://github.com/element-hq/element-x-android/pull/1432))
- Integrate SDK 0.1.58 ([#1437](https://github.com/element-hq/element-x-android/pull/1437))
Other changes
-------------
- Element call: add custom parameters to Element Call urls. ([#1434](https://github.com/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)
@ -104,8 +155,8 @@ Changes in Element X v0.2.2 (2023-09-21)
Bugfixes 🐛
----------
- Add animation when rendering the timeline to avoid glitches. ([#1323](https://github.com/vector-im/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))
- Add animation when rendering the timeline to avoid glitches. ([#1323](https://github.com/element-hq/element-x-android/issues/1323))
- Fix crash when trying to take a photo or record a video. ([#1395](https://github.com/element-hq/element-x-android/issues/1395))
Changes in Element X v0.2.1 (2023-09-20)
@ -114,18 +165,18 @@ Changes in Element X v0.2.1 (2023-09-20)
Features ✨
----------
- Bump Rust SDK to `v0.1.56`
- [Rich text editor] Add link support to rich text editor ([#1309](https://github.com/vector-im/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))
- [Rich text editor] Add link support to rich text editor ([#1309](https://github.com/element-hq/element-x-android/issues/1309))
- Let the SDK figure the best scheme given an homeserver URL (thus allowing HTTP homeservers) ([#1382](https://github.com/element-hq/element-x-android/issues/1382))
Bugfixes 🐛
----------
- Fix ANR on RoomList when notification settings change. ([#1370](https://github.com/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
-------------
- Element Call: support scheme `io.element.call` ([#1377](https://github.com/vector-im/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))
- 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))
- Element Call: support scheme `io.element.call` ([#1377](https://github.com/element-hq/element-x-android/issues/1377))
- [DI] Rework how dagger components are created and provided. ([#1378](https://github.com/element-hq/element-x-android/issues/1378))
- Remove usage of async-uniffi as it leads to a deadlocks and memory leaks. ([#1381](https://github.com/element-hq/element-x-android/issues/1381))
Changes in Element X v0.2.0 (2023-09-18)
@ -134,37 +185,37 @@ Changes in Element X v0.2.0 (2023-09-18)
Features ✨
----------
- Bump Rust SDK to `v0.1.54`
- Add a "Mute" shortcut icon and a "Notifications" section in the room details screen ([#506](https://github.com/vector-im/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))
- Integrate Element Call into EX by embedding a call in a WebView. ([#1300](https://github.com/vector-im/element-x-android/issues/1300))
- Implement Bloom effect modifier. ([#1217](https://github.com/vector-im/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))
- 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))
- [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] Add formatting menu (accessible via the '+' button) ([#1261](https://github.com/vector-im/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] Update design ([#1332](https://github.com/vector-im/element-x-android/issues/1332))
- Add a "Mute" shortcut icon and a "Notifications" section in the room details screen ([#506](https://github.com/element-hq/element-x-android/issues/506))
- Add a notification permission screen to the initial flow. ([#897](https://github.com/element-hq/element-x-android/issues/897))
- Integrate Element Call into EX by embedding a call in a WebView. ([#1300](https://github.com/element-hq/element-x-android/issues/1300))
- Implement Bloom effect modifier. ([#1217](https://github.com/element-hq/element-x-android/issues/1217))
- Set color on display name and default avatar in the timeline. ([#1224](https://github.com/element-hq/element-x-android/issues/1224))
- Display a thread decorator in timeline so we know when a message is coming from a thread. ([#1236](https://github.com/element-hq/element-x-android/issues/1236))
- [Rich text editor] Integrate rich text editor library. Note that markdown is now not supported and further formatting support will be introduced through the rich text editor. ([#1172](https://github.com/element-hq/element-x-android/issues/1172))
- [Rich text editor] Add formatting menu (accessible via the '+' button) ([#1261](https://github.com/element-hq/element-x-android/issues/1261))
- [Rich text editor] Add feature flag for rich text editor. Markdown support can now be enabled by disabling the rich text editor. ([#1289](https://github.com/element-hq/element-x-android/issues/1289))
- [Rich text editor] Update design ([#1332](https://github.com/element-hq/element-x-android/issues/1332))
Bugfixes 🐛
----------
- Make links in room topic clickable ([#612](https://github.com/vector-im/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))
- Fix system bar color after login on light theme. ([#1222](https://github.com/vector-im/element-x-android/issues/1222))
- Fix long click on simple formatted messages ([#1232](https://github.com/vector-im/element-x-android/issues/1232))
- Enable polls in release build. ([#1241](https://github.com/vector-im/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))
- [Rich text editor] Fix 'text formatting' option only partially visible ([#1335](https://github.com/vector-im/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] Fix placeholder spilling onto multiple lines ([#1347](https://github.com/vector-im/element-x-android/issues/1347))
- Make links in room topic clickable ([#612](https://github.com/element-hq/element-x-android/issues/612))
- Reply action: harmonize conditions in bottom sheet and swipe to reply. ([#1173](https://github.com/element-hq/element-x-android/issues/1173))
- Fix system bar color after login on light theme. ([#1222](https://github.com/element-hq/element-x-android/issues/1222))
- Fix long click on simple formatted messages ([#1232](https://github.com/element-hq/element-x-android/issues/1232))
- Enable polls in release build. ([#1241](https://github.com/element-hq/element-x-android/issues/1241))
- Fix top padding in room list when app is opened in offline mode. ([#1297](https://github.com/element-hq/element-x-android/issues/1297))
- [Rich text editor] Fix 'text formatting' option only partially visible ([#1335](https://github.com/element-hq/element-x-android/issues/1335))
- [Rich text editor] Ensure keyboard opens for reply and text formatting modes ([#1337](https://github.com/element-hq/element-x-android/issues/1337))
- [Rich text editor] Fix placeholder spilling onto multiple lines ([#1347](https://github.com/element-hq/element-x-android/issues/1347))
Other changes
-------------
- Add a sub-screen "Notifications" in the existing application Settings ([#510](https://github.com/vector-im/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))
- Use the new SyncIndicator API. ([#1244](https://github.com/vector-im/element-x-android/issues/1244))
- Improve RoomSummary mapping by using RoomInfo. ([#1251](https://github.com/vector-im/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))
- New app icon, with monochrome support. ([#1363](https://github.com/vector-im/element-x-android/issues/1363))
- Add a sub-screen "Notifications" in the existing application Settings ([#510](https://github.com/element-hq/element-x-android/issues/510))
- Exclude some groups related to analytics to be included. ([#1191](https://github.com/element-hq/element-x-android/issues/1191))
- Use the new SyncIndicator API. ([#1244](https://github.com/element-hq/element-x-android/issues/1244))
- Improve RoomSummary mapping by using RoomInfo. ([#1251](https://github.com/element-hq/element-x-android/issues/1251))
- Ensure Posthog data are sent to "https://posthog.element.io" ([#1269](https://github.com/element-hq/element-x-android/issues/1269))
- New app icon, with monochrome support. ([#1363](https://github.com/element-hq/element-x-android/issues/1363))
Changes in Element X v0.1.6 (2023-09-04)
@ -172,22 +223,22 @@ Changes in Element X v0.1.6 (2023-09-04)
Features ✨
----------
- Enable the Polls feature. Allows to create, view, vote and end polls. ([#1196](https://github.com/vector-im/element-x-android/issues/1196))
- Create poll. ([#1143](https://github.com/vector-im/element-x-android/issues/1143))
- Enable the Polls feature. Allows to create, view, vote and end polls. ([#1196](https://github.com/element-hq/element-x-android/issues/1196))
- Create poll. ([#1143](https://github.com/element-hq/element-x-android/issues/1143))
Bugfixes 🐛
----------
- Ensure notification for Event from encrypted room get decrypted content. ([#1178](https://github.com/vector-im/element-x-android/issues/1178))
- Make sure Snackbars are only displayed once. ([#928](https://github.com/vector-im/element-x-android/issues/928))
- Fix the orientation of sent images. ([#1135](https://github.com/vector-im/element-x-android/issues/1135))
- Bug reporter crashes when 'send logs' is disabled. ([#1168](https://github.com/vector-im/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))
- Re-enable `SyncService.withEncryptionSync` to improve decryption of notifications. ([#1198](https://github.com/vector-im/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))
- Ensure notification for Event from encrypted room get decrypted content. ([#1178](https://github.com/element-hq/element-x-android/issues/1178))
- Make sure Snackbars are only displayed once. ([#928](https://github.com/element-hq/element-x-android/issues/928))
- Fix the orientation of sent images. ([#1135](https://github.com/element-hq/element-x-android/issues/1135))
- Bug reporter crashes when 'send logs' is disabled. ([#1168](https://github.com/element-hq/element-x-android/issues/1168))
- Add missing link to the terms on the analytics setting screen. ([#1177](https://github.com/element-hq/element-x-android/issues/1177))
- Re-enable `SyncService.withEncryptionSync` to improve decryption of notifications. ([#1198](https://github.com/element-hq/element-x-android/issues/1198))
- Crash with `aspectRatio` modifier when `Float.NaN` was used as input. ([#1995](https://github.com/element-hq/element-x-android/issues/1995))
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)
@ -195,7 +246,7 @@ Changes in Element X v0.1.5 (2023-08-28)
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)
@ -203,32 +254,32 @@ Changes in Element X v0.1.4 (2023-08-28)
Features ✨
----------
- Allow cancelling media upload ([#769](https://github.com/vector-im/element-x-android/issues/769))
- Enable OIDC support. ([#1127](https://github.com/vector-im/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))
- Allow cancelling media upload ([#769](https://github.com/element-hq/element-x-android/issues/769))
- Enable OIDC support. ([#1127](https://github.com/element-hq/element-x-android/issues/1127))
- Add a "Setting up account" screen, displayed the first time the user logs in to the app (per account). ([#1149](https://github.com/element-hq/element-x-android/issues/1149))
Bugfixes 🐛
----------
- Videos sent from the app were cropped in some cases. ([#862](https://github.com/vector-im/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))
- Fix `TextButtons` being displayed in black. ([#1077](https://github.com/vector-im/element-x-android/issues/1077))
- Linkify links in HTML contents. ([#1079](https://github.com/vector-im/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 rendering of inline elements in list items. ([#1090](https://github.com/vector-im/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))
- Make links in messages clickable again. ([#1111](https://github.com/vector-im/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))
- Only display verification prompt after initial sync is done. ([#1131](https://github.com/vector-im/element-x-android/issues/1131))
- Videos sent from the app were cropped in some cases. ([#862](https://github.com/element-hq/element-x-android/issues/862))
- Timeline: sender names are now displayed in one single line. ([#1033](https://github.com/element-hq/element-x-android/issues/1033))
- Fix `TextButtons` being displayed in black. ([#1077](https://github.com/element-hq/element-x-android/issues/1077))
- Linkify links in HTML contents. ([#1079](https://github.com/element-hq/element-x-android/issues/1079))
- Fix bug reporter failing after not finding some log files. ([#1082](https://github.com/element-hq/element-x-android/issues/1082))
- Fix rendering of inline elements in list items. ([#1090](https://github.com/element-hq/element-x-android/issues/1090))
- Fix crash RuntimeException "No matching key found for the ciphertext in the stream" ([#1101](https://github.com/element-hq/element-x-android/issues/1101))
- Make links in messages clickable again. ([#1111](https://github.com/element-hq/element-x-android/issues/1111))
- When event has no id, just cancel parsing the latest room message for a room. ([#1125](https://github.com/element-hq/element-x-android/issues/1125))
- Only display verification prompt after initial sync is done. ([#1131](https://github.com/element-hq/element-x-android/issues/1131))
In development 🚧
----------------
- [Poll] Add feature flag in developer options ([#1064](https://github.com/vector-im/element-x-android/issues/1064))
- [Polls] Improve UI and render ended state ([#1113](https://github.com/vector-im/element-x-android/issues/1113))
- [Poll] Add feature flag in developer options ([#1064](https://github.com/element-hq/element-x-android/issues/1064))
- [Polls] Improve UI and render ended state ([#1113](https://github.com/element-hq/element-x-android/issues/1113))
Other changes
-------------
- Compound: add `ListItem` and `ListSectionHeader` components. ([#990](https://github.com/vector-im/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))
- Compound: add `ListItem` and `ListSectionHeader` components. ([#990](https://github.com/element-hq/element-x-android/issues/990))
- Migrate `object` to `data object` in sealed interface / class #1135 ([#1135](https://github.com/element-hq/element-x-android/issues/1135))
Changes in Element X v0.1.2 (2023-08-16)
@ -236,20 +287,20 @@ Changes in Element X v0.1.2 (2023-08-16)
Bugfixes 🐛
----------
- Filter push notifications using push rules. ([#640](https://github.com/vector-im/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))
- Filter push notifications using push rules. ([#640](https://github.com/element-hq/element-x-android/issues/640))
- Use `for` instead of `forEach` in `DefaultDiffCacheInvalidator` to improve performance. ([#1035](https://github.com/element-hq/element-x-android/issues/1035))
In development 🚧
----------------
- [Poll] Render start event in the timeline ([#1031](https://github.com/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
-------------
- Add Button component based on Compound designs ([#1021](https://github.com/vector-im/element-x-android/issues/1021))
- Compound: implement dialogs. ([#1043](https://github.com/vector-im/element-x-android/issues/1043))
- Compound: customise `IconButton` component. ([#1049](https://github.com/vector-im/element-x-android/issues/1049))
- Compound: implement `DropdownMenu` customisations. ([#1050](https://github.com/vector-im/element-x-android/issues/1050))
- Compound: implement Snackbar component. ([#1054](https://github.com/vector-im/element-x-android/issues/1054))
- Add Button component based on Compound designs ([#1021](https://github.com/element-hq/element-x-android/issues/1021))
- Compound: implement dialogs. ([#1043](https://github.com/element-hq/element-x-android/issues/1043))
- Compound: customise `IconButton` component. ([#1049](https://github.com/element-hq/element-x-android/issues/1049))
- Compound: implement `DropdownMenu` customisations. ([#1050](https://github.com/element-hq/element-x-android/issues/1050))
- Compound: implement Snackbar component. ([#1054](https://github.com/element-hq/element-x-android/issues/1054))
Changes in Element X v0.1.0 (2023-07-19)

View file

@ -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

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)
[![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)
[![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)
[![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.
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/).
@ -58,11 +58,11 @@ We're doing this as a way to share code between platforms and while we've seen p
## 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
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.
@ -75,7 +75,7 @@ Makes sure to select the `app` configuration when building (as we also have samp
## 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).
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)
testImplementation(libs.test.junit)
testImplementation(libs.test.robolectric)
testImplementation(libs.coroutines.test)
testImplementation(libs.molecule.runtime)
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.integrationpoint.NodeActivity
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.isLocked
import io.element.android.libraries.architecture.bindings
import io.element.android.libraries.core.log.logger.LoggerTag
import io.element.android.libraries.designsystem.utils.snackbar.LocalSnackbarDispatcher
import io.element.android.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.intent.SafeUriHandler
import timber.log.Timber

View file

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

View file

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

View file

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

View file

@ -14,7 +14,7 @@
* limitations under the License.
*/
package io.element.android.libraries.push.impl
package io.element.android.appconfig
object NotificationConfig {
// 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)
testImplementation(libs.test.junit)
testImplementation(libs.test.robolectric)
testImplementation(libs.coroutines.test)
testImplementation(libs.molecule.runtime)
testImplementation(libs.test.truth)
testImplementation(libs.test.turbine)
testImplementation(projects.libraries.matrix.test)
testImplementation(projects.features.networkmonitor.test)
testImplementation(projects.features.login.impl)
testImplementation(projects.tests.testutils)
testImplementation(projects.features.rageshake.test)
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.appnav.di.SessionComponentFactory
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.inputs
import io.element.android.libraries.di.AppScope
import io.element.android.libraries.di.DaggerComponentOwner
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
/**
@ -52,6 +51,7 @@ class LoggedInAppScopeFlowNode @AssistedInject constructor(
@Assisted buildContext: BuildContext,
@Assisted plugins: List<Plugin>,
sessionComponentFactory: SessionComponentFactory,
private val imageLoaderHolder: ImageLoaderHolder,
) : ParentNode<LoggedInAppScopeFlowNode.NavTarget>(
navModel = PermanentNavModel(
navTargets = setOf(NavTarget),
@ -78,8 +78,7 @@ class LoggedInAppScopeFlowNode @AssistedInject constructor(
super.onBuilt()
lifecycle.subscribe(
onCreate = {
val imageLoaderFactory = bindings<MatrixUIBindings>().loggedInImageLoaderFactory()
Coil.setImageLoader(imageLoaderFactory)
Coil.setImageLoader(imageLoaderHolder.get(inputs.matrixClient))
},
)
}

View file

@ -25,7 +25,6 @@ import androidx.compose.ui.Modifier
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.lifecycleScope
import androidx.lifecycle.repeatOnLifecycle
import com.bumble.appyx.core.composable.Children
import com.bumble.appyx.core.composable.PermanentChild
import com.bumble.appyx.core.lifecycle.subscribe
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.securebackup.api.SecureBackupEntryPoint
import io.element.android.features.verifysession.api.VerifySessionEntryPoint
import io.element.android.libraries.architecture.BackstackNode
import io.element.android.libraries.architecture.animation.rememberDefaultTransitionHandler
import io.element.android.libraries.architecture.BackstackView
import io.element.android.libraries.architecture.BaseFlowNode
import io.element.android.libraries.architecture.createNode
import io.element.android.libraries.architecture.waitForChildAttached
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.core.MAIN_SPACE
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.push.api.notifications.NotificationDrawerManager
import io.element.android.services.appnavstate.api.AppNavigationStateService
@ -99,7 +99,7 @@ class LoggedInFlowNode @AssistedInject constructor(
private val lockScreenStateService: LockScreenService,
private val matrixClient: MatrixClient,
snackbarDispatcher: SnackbarDispatcher,
) : BackstackNode<LoggedInFlowNode.NavTarget>(
) : BaseFlowNode<LoggedInFlowNode.NavTarget>(
backstack = BackStack(
initialElement = NavTarget.RoomList,
savedStateMap = buildContext.savedStateMap,
@ -149,6 +149,23 @@ class LoggedInFlowNode @AssistedInject constructor(
}
)
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)
@ -256,6 +273,10 @@ class LoggedInFlowNode @AssistedInject constructor(
}
is NavTarget.Room -> {
val callback = object : RoomLoadedFlowNode.Callback {
override fun onOpenRoom(roomId: RoomId) {
backstack.push(NavTarget.Room(roomId))
}
override fun onForwardedToSingleRoom(roomId: RoomId) {
coroutineScope.launch { attachRoom(roomId) }
}
@ -362,12 +383,7 @@ class LoggedInFlowNode @AssistedInject constructor(
override fun View(modifier: Modifier) {
Box(modifier = modifier) {
val lockScreenState by lockScreenStateService.lockState.collectAsState()
Children(
navModel = backstack,
modifier = Modifier,
// Animate navigation to settings and to a room
transitionHandler = rememberDefaultTransitionHandler(),
)
BackstackView()
val isFtueDisplayed by ftueState.shouldDisplayFlow.collectAsState()
if (!isFtueDisplayed) {
PermanentChild(permanentNavModel = permanentNavModel, navTarget = NavTarget.LoggedInPermanent)

View file

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

View file

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

View file

@ -34,6 +34,8 @@ class IntentResolver @Inject constructor(
private val oidcIntentResolver: OidcIntentResolver
) {
fun resolve(intent: Intent): ResolvedIntent? {
if (intent.canBeIgnored()) return null
val deepLinkData = deeplinkParser.getFromIntent(intent)
if (deepLinkData != null) return ResolvedIntent.Navigation(deepLinkData)
@ -45,3 +47,8 @@ class IntentResolver @Inject constructor(
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.tooling.preview.PreviewParameter
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.PreviewsDayNight
@Composable
fun LoggedInView(

View file

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

View file

@ -30,17 +30,17 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.tooling.preview.PreviewParameter
import androidx.compose.ui.unit.dp
import io.element.android.compound.theme.ElementTheme
import io.element.android.features.networkmonitor.api.ui.ConnectivityIndicatorView
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.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.PreviewsDayNight
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.Text
import io.element.android.libraries.designsystem.theme.components.TopAppBar
import io.element.android.libraries.theme.ElementTheme
import io.element.android.libraries.ui.strings.CommonStrings
@OptIn(ExperimentalLayoutApi::class)

View file

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

View file

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

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.detection.RageshakeDetectionEvents
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.PreviewsDayNight
import io.element.android.libraries.designsystem.theme.components.Text
import io.element.android.services.apperror.impl.AppErrorView
@Composable
fun RootView(
state: RootState,
onOpenBugReport: () -> Unit,
modifier: Modifier = Modifier,
onOpenBugReport: () -> Unit = {},
children: @Composable BoxScope.() -> Unit,
) {
Box(
@ -69,7 +69,10 @@ fun RootView(
@PreviewsDayNight
@Composable
internal fun RootPreview(@PreviewParameter(RootStateProvider::class) rootState: RootState) = ElementPreview {
RootView(rootState) {
RootView(
state = rootState,
onOpenBugReport = {},
) {
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.testing.junit4.util.MainDispatcherRule
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.room.RoomLoadedFlowNode
import io.element.android.features.messages.api.MessagesEntryPoint
@ -83,7 +83,7 @@ class RoomFlowNodeTest {
}
override fun build(): Node {
return node(buildContext) {}.also {
return node(buildContext) {}.also {
nodeId = it.id
}
}
@ -122,10 +122,10 @@ class RoomFlowNodeTest {
val roomFlowNodeTestHelper = roomFlowNode.parentNodeTestHelper()
// 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)
val messagesNode = roomFlowNode.childNode(RoomLoadedFlowNode.NavTarget.Messages)!!
Truth.assertThat(messagesNode.id).isEqualTo(fakeMessagesEntryPoint.nodeId)
assertThat(messagesNode.id).isEqualTo(fakeMessagesEntryPoint.nodeId)
}
@Test
@ -147,6 +147,6 @@ class RoomFlowNodeTest {
// THEN
roomFlowNodeTestHelper.assertChildHasLifecycle(RoomLoadedFlowNode.NavTarget.RoomDetails, Lifecycle.State.CREATED)
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 {
val initialState = awaitItem()
assertThat(initialState.showSyncSpinner).isFalse()
roomListService.postSyncIndicator(RoomListService.SyncIndicator.Show)
consumeItemsUntilPredicate { it.showSyncSpinner }
roomListService.postState(RoomListService.State.Running)
roomListService.postSyncIndicator(RoomListService.SyncIndicator.Hide)
consumeItemsUntilPredicate { !it.showSyncSpinner }
}
}

View file

@ -17,7 +17,7 @@
package io.element.android.appnav.room
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.test.A_ROOM_ID
import io.element.android.libraries.matrix.test.A_SESSION_ID
@ -39,8 +39,8 @@ class LoadingRoomStateFlowFactoryTest {
flowFactory
.create(this, A_ROOM_ID)
.test {
Truth.assertThat(awaitItem()).isEqualTo(LoadingRoomState.Loading)
Truth.assertThat(awaitItem()).isEqualTo(LoadingRoomState.Loaded(room))
assertThat(awaitItem()).isEqualTo(LoadingRoomState.Loading)
assertThat(awaitItem()).isEqualTo(LoadingRoomState.Loaded(room))
}
}
@ -53,10 +53,10 @@ class LoadingRoomStateFlowFactoryTest {
flowFactory
.create(this, A_ROOM_ID)
.test {
Truth.assertThat(awaitItem()).isEqualTo(LoadingRoomState.Loading)
assertThat(awaitItem()).isEqualTo(LoadingRoomState.Loading)
matrixClient.givenGetRoomResult(A_ROOM_ID, room)
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
.create(this, A_ROOM_ID)
.test {
Truth.assertThat(awaitItem()).isEqualTo(LoadingRoomState.Loading)
assertThat(awaitItem()).isEqualTo(LoadingRoomState.Loading)
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"))
}
dependencies {
detektPlugins("io.nlopez.compose.rules:detekt:0.3.3")
detektPlugins("io.nlopez.compose.rules:detekt:0.3.8")
}
// KtLint
@ -130,10 +130,10 @@ sonar {
property("sonar.host.url", "https://sonarcloud.io")
property("sonar.projectVersion", "1.0") // TODO project(":app").android.defaultConfig.versionName)
property("sonar.sourceEncoding", "UTF-8")
property("sonar.links.homepage", "https://github.com/vector-im/element-x-android/")
property("sonar.links.ci", "https://github.com/vector-im/element-x-android/actions")
property("sonar.links.scm", "https://github.com/vector-im/element-x-android/")
property("sonar.links.issue", "https://github.com/vector-im/element-x-android/issues")
property("sonar.links.homepage", "https://github.com/element-hq/element-x-android/")
property("sonar.links.ci", "https://github.com/element-hq/element-x-android/actions")
property("sonar.links.scm", "https://github.com/element-hq/element-x-android/")
property("sonar.links.issue", "https://github.com/element-hq/element-x-android/issues")
property("sonar.organization", "new_vector_ltd_organization")
property("sonar.login", if (project.hasProperty("SONAR_LOGIN")) project.property("SONAR_LOGIN")!! else "invalid")
@ -236,11 +236,11 @@ koverMerged {
name = "Global minimum code coverage."
target = kotlinx.kover.api.VerificationTarget.ALL
bound {
minValue = 60
minValue = 65
// 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
// minValue to 25 and maxValue to 35.
maxValue = 70
maxValue = 75
counter = kotlinx.kover.api.CounterType.INSTRUCTION
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
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:
@ -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.
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

View file

@ -63,7 +63,7 @@ bundle exec danger pr <PR_URL> --dangerfile=./tools/danger/dangerfile.js
For instance:
```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:
@ -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:
- login: ElementBot
- 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.

View file

@ -8,15 +8,15 @@
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) 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) Open the emulator Chrome browser app
1) Go to the url `mitm.it`
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) Go to the `RustMatrixClientFactory.create()` method.
1) Add `.disableSslVerification()` in the `ClientBuilder` method chain.
1) Build and run the Element X app.
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)
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)

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:
```bash
git clone git@github.com:vector-im/element-x-android.git
git clone git@github.com:element-hq/element-x-android.git
```
or
```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:
@ -33,7 +33,7 @@ brew install bundletool
## 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`
3. Navigate to the folder where you cloned the project and run the following command:
```bash

View file

@ -1,14 +1,14 @@
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
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,
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.
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.
- 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).
- 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

View file

@ -30,7 +30,7 @@ If installed correctly, `git push` and `git pull` will now include LFS content.
## 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.

View file

@ -1,2 +1,2 @@
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.
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.
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.
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
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
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
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.
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.
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.
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.
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.
- 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.
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)
api(projects.features.analytics.api)
api(projects.services.analytics.api)
implementation(projects.appconfig)
implementation(libs.androidx.datastore.preferences)
implementation(libs.androidx.browser)
ksp(libs.showkase.processor)

View file

@ -17,7 +17,6 @@
package io.element.android.features.analytics.impl
import android.app.Activity
import androidx.compose.material.MaterialTheme
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext
@ -27,7 +26,8 @@ import com.bumble.appyx.core.plugin.Plugin
import dagger.assisted.Assisted
import dagger.assisted.AssistedInject
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.di.AppScope
@ -39,13 +39,13 @@ class AnalyticsOptInNode @AssistedInject constructor(
) : Node(buildContext, plugins = plugins) {
private fun onClickTerms(activity: Activity, darkTheme: Boolean) {
activity.openUrlInChromeCustomTab(null, darkTheme, Config.POLICY_LINK)
activity.openUrlInChromeCustomTab(null, darkTheme, AnalyticsConfig.POLICY_LINK)
}
@Composable
override fun View(modifier: Modifier) {
val activity = LocalContext.current as Activity
val isDark = MaterialTheme.colors.isLight.not()
val isDark = ElementTheme.isLightTheme.not()
val state = presenter.present()
AnalyticsOptInView(
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.tooling.preview.PreviewParameter
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.Config
import io.element.android.libraries.designsystem.atomic.molecules.ButtonColumnMolecule
import io.element.android.libraries.designsystem.atomic.molecules.IconTitleSubtitleMolecule
import io.element.android.libraries.designsystem.atomic.organisms.InfoListItem
import io.element.android.libraries.designsystem.atomic.organisms.InfoListOrganism
import io.element.android.libraries.designsystem.atomic.pages.HeaderFooterPage
import io.element.android.libraries.designsystem.preview.PreviewsDayNight
import io.element.android.libraries.designsystem.preview.ElementPreview
import io.element.android.libraries.designsystem.preview.PreviewsDayNight
import io.element.android.libraries.designsystem.text.buildAnnotatedStringWithStyledPart
import io.element.android.libraries.designsystem.theme.components.Button
import io.element.android.libraries.designsystem.theme.components.ButtonSize
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.temporaryColorBgSpecial
import io.element.android.libraries.designsystem.utils.CommonDrawables
import io.element.android.libraries.designsystem.utils.LogCompositions
import io.element.android.libraries.theme.ElementTheme
import io.element.android.libraries.ui.strings.CommonStrings
import kotlinx.collections.immutable.persistentListOf
@ -119,7 +119,7 @@ private fun AnalyticsOptInHeader(
color = Color.Unspecified,
underline = false,
bold = true,
tagAndLink = LINK_TAG to Config.POLICY_LINK,
tagAndLink = LINK_TAG to AnalyticsConfig.POLICY_LINK,
)
ClickableText(
text = text,
@ -147,7 +147,7 @@ private fun CheckIcon(modifier: Modifier = Modifier) {
.size(20.dp)
.background(color = MaterialTheme.colorScheme.background, shape = CircleShape)
.padding(2.dp),
resourceId = CommonDrawables.ic_compound_check,
imageVector = CompoundIcons.Check,
contentDescription = null,
tint = ElementTheme.colors.textActionAccent,
)

View file

@ -20,8 +20,8 @@ import androidx.compose.runtime.Composable
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.rememberCoroutineScope
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.Config
import io.element.android.features.analytics.api.preferences.AnalyticsPreferencesPresenter
import io.element.android.features.analytics.api.preferences.AnalyticsPreferencesState
import io.element.android.libraries.core.meta.BuildMeta
@ -52,7 +52,7 @@ class DefaultAnalyticsPreferencesPresenter @Inject constructor(
return AnalyticsPreferencesState(
applicationName = buildMeta.applicationName,
isEnabled = isEnabled.value,
policyUrl = Config.POLICY_LINK,
policyUrl = AnalyticsConfig.POLICY_LINK,
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
import com.google.common.truth.Truth
import com.google.common.truth.Truth.assertThat
import io.element.android.tests.testutils.testCoroutineDispatchers
import kotlinx.coroutines.test.TestScope
import kotlinx.coroutines.test.runTest
@ -46,9 +46,9 @@ class DefaultCacheCleanerTest {
// Check the files are gone but the sub dirs are not.
DefaultCacheCleaner.SUBDIRS_TO_CLEANUP.forEach {
File(temporaryFolder.root, it).apply {
Truth.assertThat(exists()).isTrue()
Truth.assertThat(isDirectory).isTrue()
Truth.assertThat(listFiles()).isEmpty()
assertThat(exists()).isTrue()
assertThat(isDirectory).isTrue()
assertThat(listFiles()).isEmpty()
}
}
}

View file

@ -33,6 +33,7 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalInspectionMode
import androidx.compose.ui.res.stringResource
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.utils.WebViewWidgetMessageInterceptor
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.Text
import io.element.android.libraries.designsystem.theme.components.TopAppBar
import io.element.android.libraries.designsystem.utils.CommonDrawables
typealias RequestPermissionCallback = (Array<String>) -> Unit
@ -64,7 +64,7 @@ internal fun CallScreenView(
title = { Text(stringResource(R.string.element_call)) },
navigationIcon = {
BackButton(
resourceId = CommonDrawables.ic_compound_close,
imageVector = CompoundIcons.Close,
onClick = { state.eventSink(CallScreenEvents.Hangup) }
)
}

View file

@ -37,16 +37,16 @@ import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.core.content.IntentCompat
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.CallType
import io.element.android.features.call.di.CallBindings
import io.element.android.features.call.utils.CallIntentDataParser
import io.element.android.features.preferences.api.store.PreferencesStore
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
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
fun `given any other permission, it returns nothing`() {
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.permissions.test)
testImplementation(projects.libraries.usersearch.test)
testImplementation(projects.features.createroom.test)
testImplementation(projects.tests.testutils)
ksp(libs.showkase.processor)

View file

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

View file

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

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.UserListState
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.PreviewsDayNight
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.Text
import io.element.android.libraries.designsystem.theme.components.TextButton
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
@OptIn(ExperimentalLayoutApi::class)
@Composable
fun AddPeopleView(
state: UserListState,
onBackPressed: () -> Unit,
onNextPressed: () -> Unit,
modifier: Modifier = Modifier,
onBackPressed: () -> Unit = {},
onNextPressed: () -> Unit = {},
) {
Scaffold(
modifier = modifier,
@ -77,6 +77,8 @@ fun AddPeopleView(
.fillMaxWidth(),
state = state,
showBackButton = false,
onUserSelected = { },
onUserDeselected = {},
)
}
}
@ -86,9 +88,9 @@ fun AddPeopleView(
@Composable
private fun AddPeopleViewTopBar(
hasSelectedUsers: Boolean,
onBackPressed: () -> Unit,
onNextPressed: () -> Unit,
modifier: Modifier = Modifier,
onBackPressed: () -> Unit = {},
onNextPressed: () -> Unit = {},
) {
TopAppBar(
modifier = modifier,
@ -112,5 +114,9 @@ private fun AddPeopleViewTopBar(
@PreviewsDayNight
@Composable
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.RadioButton
import io.element.android.libraries.designsystem.theme.components.Text
import io.element.android.libraries.theme.ElementTheme
import io.element.android.compound.theme.ElementTheme
@Composable
fun RoomPrivacyOption(
roomPrivacyItem: RoomPrivacyItem,
onOptionSelected: (RoomPrivacyItem) -> Unit,
modifier: Modifier = Modifier,
isSelected: Boolean = false,
onOptionSelected: (RoomPrivacyItem) -> Unit = {},
) {
Row(
modifier
@ -58,7 +58,7 @@ fun RoomPrivacyOption(
Icon(
modifier = Modifier.padding(horizontal = 8.dp),
resourceId = roomPrivacyItem.icon,
contentDescription = "",
contentDescription = null,
tint = MaterialTheme.colorScheme.secondary,
)
@ -97,10 +97,12 @@ internal fun RoomPrivacyOptionPreview() = ElementPreview {
Column {
RoomPrivacyOption(
roomPrivacyItem = aRoomPrivacyItem,
onOptionSelected = {},
isSelected = true,
)
RoomPrivacyOption(
roomPrivacyItem = aRoomPrivacyItem,
onOptionSelected = {},
isSelected = false,
)
}

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