Browse Source

Merge branch 'release/0.4.16' into main

main v0.4.16
ganfra 4 months ago
parent
commit
92dc7a307b
  1. 2
      .github/pull_request_template.md
  2. 34
      .github/release.yml
  3. 2
      .github/renovate.json
  4. 2
      .github/workflows/build.yml
  5. 69
      .github/workflows/build_enterprise.yml
  6. 9
      .github/workflows/danger.yml
  7. 2
      .github/workflows/fork-pr-notice.yml
  8. 9
      .github/workflows/nightly.yml
  9. 48
      .github/workflows/nightly_enterprise.yml
  10. 44
      .github/workflows/quality.yml
  11. 34
      .github/workflows/release.yml
  12. 2
      .github/workflows/scripts/recordScreenshots.sh
  13. 1
      .github/workflows/sync-localazy.yml
  14. 1
      .github/workflows/sync-sas-strings.yml
  15. 7
      .github/workflows/tests.yml
  16. 1
      .gitignore
  17. 3
      .gitmodules
  18. 6
      .idea/copyright/Element_Enterprise.xml
  19. 6
      .idea/copyright/Element_FOSS.xml
  20. 6
      .idea/copyright/NewVector.xml
  21. 6
      .idea/copyright/profiles_settings.xml
  22. 3
      .idea/scopes/Enterprise.xml
  23. 14
      CONTRIBUTING.md
  24. 44
      app/build.gradle.kts
  25. 8
      app/src/main/AndroidManifest.xml
  26. 8
      app/src/main/kotlin/io/element/android/x/di/AppModule.kt
  27. 70
      app/src/main/kotlin/io/element/android/x/icon/IconPreview.kt
  28. 1
      app/src/main/res/xml/locales_config.xml
  29. 2
      appconfig/build.gradle.kts
  30. 12
      appconfig/src/main/kotlin/io/element/android/appconfig/AuthenticationConfig.kt
  31. 6
      appconfig/src/main/kotlin/io/element/android/appconfig/NotificationConfig.kt
  32. 2
      appconfig/src/main/kotlin/io/element/android/appconfig/OnBoardingConfig.kt
  33. 26
      appicon/element/build.gradle.kts
  34. 0
      appicon/element/src/debug/res/drawable/ic_launcher_background.xml
  35. 0
      appicon/element/src/main/ic_launcher-playstore.png
  36. 69
      appicon/element/src/main/kotlin/io/element/android/appicon/element/IconPreview.kt
  37. 0
      appicon/element/src/main/res/mipmap-anydpi-v26/ic_launcher.xml
  38. 0
      appicon/element/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml
  39. 0
      appicon/element/src/main/res/mipmap-hdpi/ic_launcher.webp
  40. 0
      appicon/element/src/main/res/mipmap-hdpi/ic_launcher_background.webp
  41. 0
      appicon/element/src/main/res/mipmap-hdpi/ic_launcher_foreground.webp
  42. 0
      appicon/element/src/main/res/mipmap-hdpi/ic_launcher_monochrome.webp
  43. 0
      appicon/element/src/main/res/mipmap-hdpi/ic_launcher_round.webp
  44. 0
      appicon/element/src/main/res/mipmap-mdpi/ic_launcher.webp
  45. 0
      appicon/element/src/main/res/mipmap-mdpi/ic_launcher_background.webp
  46. 0
      appicon/element/src/main/res/mipmap-mdpi/ic_launcher_foreground.webp
  47. 0
      appicon/element/src/main/res/mipmap-mdpi/ic_launcher_monochrome.webp
  48. 0
      appicon/element/src/main/res/mipmap-mdpi/ic_launcher_round.webp
  49. 0
      appicon/element/src/main/res/mipmap-xhdpi/ic_launcher.webp
  50. 0
      appicon/element/src/main/res/mipmap-xhdpi/ic_launcher_background.webp
  51. 0
      appicon/element/src/main/res/mipmap-xhdpi/ic_launcher_foreground.webp
  52. 0
      appicon/element/src/main/res/mipmap-xhdpi/ic_launcher_monochrome.webp
  53. 0
      appicon/element/src/main/res/mipmap-xhdpi/ic_launcher_round.webp
  54. 0
      appicon/element/src/main/res/mipmap-xxhdpi/ic_launcher.webp
  55. 0
      appicon/element/src/main/res/mipmap-xxhdpi/ic_launcher_background.webp
  56. 0
      appicon/element/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.webp
  57. 0
      appicon/element/src/main/res/mipmap-xxhdpi/ic_launcher_monochrome.webp
  58. 0
      appicon/element/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp
  59. 0
      appicon/element/src/main/res/mipmap-xxxhdpi/ic_launcher.webp
  60. 0
      appicon/element/src/main/res/mipmap-xxxhdpi/ic_launcher_background.webp
  61. 0
      appicon/element/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.webp
  62. 0
      appicon/element/src/main/res/mipmap-xxxhdpi/ic_launcher_monochrome.webp
  63. 0
      appicon/element/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp
  64. 0
      appicon/element/src/nightly/res/drawable/ic_launcher_background.xml
  65. 0
      appicon/element/src/release/res/drawable/ic_launcher_background.xml
  66. 26
      appicon/enterprise/build.gradle.kts
  67. 10
      appicon/enterprise/src/debug/res/drawable/ic_launcher_background_enterprise.xml
  68. 53
      appicon/enterprise/src/main/kotlin/io/element/android/appicon/enterprise/IconPreview.kt
  69. 21
      appicon/enterprise/src/main/res/mipmap-anydpi/ic_launcher.xml
  70. 21
      appicon/enterprise/src/main/res/mipmap-anydpi/ic_launcher_round.xml
  71. BIN
      appicon/enterprise/src/main/res/mipmap-hdpi/ic_launcher_background_enterprise.webp
  72. BIN
      appicon/enterprise/src/main/res/mipmap-mdpi/ic_launcher_background_enterprise.webp
  73. BIN
      appicon/enterprise/src/main/res/mipmap-xhdpi/ic_launcher_background_enterprise.webp
  74. BIN
      appicon/enterprise/src/main/res/mipmap-xxhdpi/ic_launcher_background_enterprise.webp
  75. BIN
      appicon/enterprise/src/main/res/mipmap-xxhdpi/ic_launcher_foreground_enterprise.webp
  76. BIN
      appicon/enterprise/src/main/res/mipmap-xxxhdpi/ic_launcher_background_enterprise.webp
  77. 10
      appicon/enterprise/src/nightly/res/drawable/ic_launcher_background_enterprise.xml
  78. 2
      appicon/enterprise/src/release/res/drawable/ic_launcher_background_enterprise.xml
  79. 3
      appnav/build.gradle.kts
  80. 16
      appnav/src/main/kotlin/io/element/android/appnav/loggedin/SendQueues.kt
  81. 4
      appnav/src/main/kotlin/io/element/android/appnav/root/RootNavStateFlowFactory.kt
  82. 11
      appnav/src/test/kotlin/io/element/android/appnav/loggedin/SendQueuesTest.kt
  83. 10
      build.gradle.kts
  84. 1
      changelog.d/2869.feature
  85. 1
      changelog.d/2916.misc
  86. 1
      changelog.d/3051.misc
  87. 1
      changelog.d/3053.misc
  88. 1
      changelog.d/3068.misc
  89. 1
      changelog.d/3073.bugfix
  90. 1
      changelog.d/3081.bugfix
  91. 1
      changelog.d/3082.bugfix
  92. 1
      changelog.d/3083.bugfix
  93. 1
      changelog.d/3085.bugfix
  94. 1
      changelog.d/3086.bugfix
  95. 2
      docs/danger.md
  96. 6
      docs/nightly_build.md
  97. 2
      docs/screenshot_testing.md
  98. 1
      enterprise
  99. 2
      fastlane/metadata/android/en-US/changelogs/40004160.txt
  100. 3
      features/analytics/api/build.gradle.kts
  101. Some files were not shown because too many files have changed in this diff Show More

2
.github/pull_request_template.md

@ -55,7 +55,7 @@ Uncomment this markdown table below and edit the last line `|||`:
- [ ] UI change has been tested on both light and dark themes - [ ] UI change has been tested on both light and dark themes
- [ ] Accessibility has been taken into account. See https://github.com/element-hq/element-x-android/blob/develop/CONTRIBUTING.md#accessibility - [ ] Accessibility has been taken into account. See https://github.com/element-hq/element-x-android/blob/develop/CONTRIBUTING.md#accessibility
- [ ] Pull request is based on the develop branch - [ ] Pull request is based on the develop branch
- [ ] Pull request includes a new file under ./changelog.d. See https://github.com/element-hq/element-x-android/blob/develop/CONTRIBUTING.md#changelog - [ ] Pull request title will be used in the release note, it clearly define what will change for the user
- [ ] Pull request includes screenshots or videos if containing UI changes - [ ] Pull request includes screenshots or videos if containing UI changes
- [ ] Pull request includes a [sign off](https://matrix-org.github.io/synapse/latest/development/contributing_guide.html#sign-off) - [ ] Pull request includes a [sign off](https://matrix-org.github.io/synapse/latest/development/contributing_guide.html#sign-off)
- [ ] You've made a self review of your PR - [ ] You've made a self review of your PR

34
.github/release.yml

@ -0,0 +1,34 @@
changelog:
categories:
- title: ✨ Features
labels:
- PR-Feature
- title: 🙌 Improvements
labels:
- PR-Change
- title: 🐛 Bugfixes
labels:
- PR-Bugfix
- title: API Changes
labels:
- PR-Api
- title: 🗣 Translations
labels:
- PR-i18n
- title: 🧱 Build
labels:
- PR-Build
- title: 📄 Documentation
labels:
- PR-Doc
- title: 🚧 In development 🚧
labels:
- PR-Wip
- title: Dependency upgrades
labels:
- PR-Dependencies
- title: Others
labels:
- PR-misc
- "*"

2
.github/renovate.json

@ -4,7 +4,7 @@
"config:base" "config:base"
], ],
"labels" : [ "labels" : [
"dependencies" "PR-Dependencies"
], ],
"ignoreDeps" : [ "ignoreDeps" : [
"string:app_name" "string:app_name"

2
.github/workflows/build.yml

@ -16,8 +16,6 @@ jobs:
debug: debug:
name: Build APKs name: Build APKs
runs-on: ubuntu-latest runs-on: ubuntu-latest
# Skip for `main`
if: github.ref != 'refs/heads/main'
strategy: strategy:
matrix: matrix:
variant: [debug, release, nightly, samples] variant: [debug, release, nightly, samples]

69
.github/workflows/build_enterprise.yml

@ -0,0 +1,69 @@
name: Enterprise APK Build
on:
workflow_dispatch:
pull_request:
merge_group:
push:
branches: [ develop ]
# Enrich gradle.properties for CI/CD
env:
GRADLE_OPTS: -Dorg.gradle.jvmargs="-Xmx7g -XX:MaxMetaspaceSize=512m -Dfile.encoding=UTF-8 -XX:+HeapDumpOnOutOfMemoryError" -Dkotlin.incremental=false -XX:+UseG1GC
CI_GRADLE_ARG_PROPERTIES: --stacktrace -Dsonar.gradle.skipCompile=true
jobs:
build:
name: Build Enterprise APKs
runs-on: ubuntu-latest
# Skip in forks
if: github.repository == 'element-hq/element-x-android'
strategy:
matrix:
variant: [debug, release, nightly]
fail-fast: false
# Allow all jobs on develop. Just one per PR.
concurrency:
group: ${{ github.ref == 'refs/heads/develop' && format('build-develop-enterprise-{0}-{1}', matrix.variant, github.sha) || format('build-enterprise-{0}-{1}', matrix.variant, github.ref) }}
cancel-in-progress: true
steps:
- uses: actions/checkout@v4
with:
# Ensure we are building the branch and not the branch after being merged on develop
# https://github.com/actions/checkout/issues/881
ref: ${{ github.event_name == 'pull_request' && github.event.pull_request.head.sha || github.ref }}
- name: Add SSH private keys for submodule repositories
uses: webfactory/ssh-agent@v0.9.0
with:
ssh-private-key: ${{ secrets.ELEMENT_ENTERPRISE_DEPLOY_KEY }}
- name: Clone submodules
run: git submodule update --init --recursive
- name: Use JDK 17
uses: actions/setup-java@v4
with:
distribution: 'temurin' # See 'Supported distributions' for available options
java-version: '17'
- name: Configure gradle
uses: gradle/actions/setup-gradle@v3
with:
cache-read-only: ${{ github.ref != 'refs/heads/develop' }}
- name: Assemble debug Gplay Enterprise APK
if: ${{ matrix.variant == 'debug' }}
env:
ELEMENT_ANDROID_MAPTILER_API_KEY: ${{ secrets.MAPTILER_KEY }}
ELEMENT_ANDROID_MAPTILER_LIGHT_MAP_ID: ${{ secrets.MAPTILER_LIGHT_MAP_ID }}
ELEMENT_ANDROID_MAPTILER_DARK_MAP_ID: ${{ secrets.MAPTILER_DARK_MAP_ID }}
run: ./gradlew :app:assembleGplayDebug -PallWarningsAsErrors=true $CI_GRADLE_ARG_PROPERTIES
- name: Upload debug Enterprise APKs
if: ${{ matrix.variant == 'debug' }}
uses: actions/upload-artifact@v4
with:
name: elementx-enterprise-debug
path: |
app/build/outputs/apk/gplay/debug/*-universal-debug.apk
- name: Compile release sources
if: ${{ matrix.variant == 'release' }}
run: ./gradlew compileReleaseSources -PallWarningsAsErrors=true $CI_GRADLE_ARG_PROPERTIES
- name: Compile nightly sources
if: ${{ matrix.variant == 'nightly' }}
run: ./gradlew compileGplayNightlySources -PallWarningsAsErrors=true $CI_GRADLE_ARG_PROPERTIES

9
.github/workflows/danger.yml

@ -8,10 +8,17 @@ jobs:
name: Danger main check name: Danger main check
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
- name: Add SSH private keys for submodule repositories
uses: webfactory/ssh-agent@v0.9.0
with:
ssh-private-key: ${{ secrets.ELEMENT_ENTERPRISE_DEPLOY_KEY }}
- name: Clone submodules
if: github.repository == 'element-hq/element-x-android'
run: git submodule update --init --recursive
- run: | - run: |
npm install --save-dev @babel/plugin-transform-flow-strip-types npm install --save-dev @babel/plugin-transform-flow-strip-types
- name: Danger - name: Danger
uses: danger/danger-js@12.3.2 uses: danger/danger-js@12.3.3
with: with:
args: "--dangerfile ./tools/danger/dangerfile.js" args: "--dangerfile ./tools/danger/dangerfile.js"
env: env:

2
.github/workflows/fork-pr-notice.yml

@ -25,7 +25,7 @@ jobs:
body: `Thank you for your contribution! Here are a few things to check in the PR to ensure it's reviewed as quickly as possible: body: `Thank you for your contribution! Here are a few things to check in the PR to ensure it's reviewed as quickly as possible:
- Your branch should be based on \`origin/develop\`, at least when it was created. - Your branch should be based on \`origin/develop\`, at least when it was created.
- There is a changelog entry in the \`changelog.d\` folder with [the Towncrier format](https://towncrier.readthedocs.io/en/latest/tutorial.html#creating-news-fragments). - The title of the PR will be used for release notes, so it needs to describe the change visible to the user.
- The test pass locally running \`./gradlew test\`. - The test pass locally running \`./gradlew test\`.
- The code quality check suite pass locally running \`./gradlew runQualityChecks\`. - The code quality check suite pass locally running \`./gradlew runQualityChecks\`.
- If you modified anything related to the UI, including previews, you'll have to run the \`Record screenshots\` GH action in your forked repo: that will generate compatible new screenshots. However, given Github Actions limitations, **it will prevent the CI from running temporarily**, until you upload a new commit after that one. To do so, just pull the latest changes and push [an empty commit](https://coderwall.com/p/vkdekq/git-commit-allow-empty).` - If you modified anything related to the UI, including previews, you'll have to run the \`Record screenshots\` GH action in your forked repo: that will generate compatible new screenshots. However, given Github Actions limitations, **it will prevent the CI from running temporarily**, until you upload a new commit after that one. To do so, just pull the latest changes and push [an empty commit](https://coderwall.com/p/vkdekq/git-commit-allow-empty).`

9
.github/workflows/nightly.yml

@ -22,15 +22,6 @@ jobs:
with: with:
distribution: 'temurin' # See 'Supported distributions' for available options distribution: 'temurin' # See 'Supported distributions' for available options
java-version: '17' java-version: '17'
- name: Install towncrier
run: |
python3 -m pip install towncrier
- name: Prepare changelog file
run: |
mv towncrier.toml towncrier.toml.bak
sed 's/CHANGES\.md/CHANGES_NIGHTLY\.md/' towncrier.toml.bak > towncrier.toml
rm towncrier.toml.bak
yes n | towncrier build --version nightly
- name: Build and upload Nightly application - name: Build and upload Nightly application
run: | run: |
./gradlew assembleGplayNightly appDistributionUploadGplayNightly $CI_GRADLE_ARG_PROPERTIES ./gradlew assembleGplayNightly appDistributionUploadGplayNightly $CI_GRADLE_ARG_PROPERTIES

48
.github/workflows/nightly_enterprise.yml

@ -0,0 +1,48 @@
name: Build and release Enterprise nightly application
on:
workflow_dispatch:
schedule:
# Every nights at 4
- cron: "0 4 * * *"
env:
GRADLE_OPTS: -Dorg.gradle.jvmargs="-Xmx6g -XX:MaxMetaspaceSize=512m -Dfile.encoding=UTF-8 -XX:+HeapDumpOnOutOfMemoryError" -Dkotlin.incremental=false -XX:+UseG1GC
CI_GRADLE_ARG_PROPERTIES: --stacktrace --no-daemon -Dsonar.gradle.skipCompile=true
jobs:
nightly:
name: Build and publish Enterprise nightly bundle to Firebase
runs-on: ubuntu-latest
if: ${{ github.repository == 'element-hq/element-x-android' }}
steps:
- uses: actions/checkout@v4
- name: Add SSH private keys for submodule repositories
uses: webfactory/ssh-agent@v0.9.0
with:
ssh-private-key: ${{ secrets.ELEMENT_ENTERPRISE_DEPLOY_KEY }}
- name: Clone submodules
run: git submodule update --init --recursive
- name: Use JDK 17
uses: actions/setup-java@v4
with:
distribution: 'temurin' # See 'Supported distributions' for available options
java-version: '17'
- name: Build and upload Nightly application
run: |
./gradlew assembleGplayNightly appDistributionUploadGplayNightly $CI_GRADLE_ARG_PROPERTIES
env:
ELEMENT_ANDROID_MAPTILER_API_KEY: ${{ secrets.MAPTILER_KEY }}
ELEMENT_ANDROID_MAPTILER_LIGHT_MAP_ID: ${{ secrets.MAPTILER_LIGHT_MAP_ID }}
ELEMENT_ANDROID_MAPTILER_DARK_MAP_ID: ${{ secrets.MAPTILER_DARK_MAP_ID }}
ELEMENT_ANDROID_NIGHTLY_KEYID: ${{ secrets.ELEMENT_ANDROID_NIGHTLY_KEYID }}
ELEMENT_ANDROID_NIGHTLY_KEYPASSWORD: ${{ secrets.ELEMENT_ANDROID_NIGHTLY_KEYPASSWORD }}
ELEMENT_ANDROID_NIGHTLY_STOREPASSWORD: ${{ secrets.ELEMENT_ANDROID_NIGHTLY_STOREPASSWORD }}
FIREBASE_TOKEN: ${{ secrets.ELEMENT_ANDROID_NIGHTLY_FIREBASE_TOKEN }}
- name: Additionally upload Nightly APK to browserstack for testing
continue-on-error: true # don't block anything by this upload failing (for now)
run: |
curl -u "$BROWSERSTACK_USERNAME:$BROWSERSTACK_PASSWORD" -X POST "https://api-cloud.browserstack.com/app-automate/upload" -F "file=@app/build/outputs/apk/gplay/nightly/app-gplay-universal-nightly.apk" -F "custom_id=element-x-android-nightly"
env:
BROWSERSTACK_USERNAME: ${{ secrets.ELEMENT_ANDROID_BROWSERSTACK_USERNAME }}
BROWSERSTACK_PASSWORD: ${{ secrets.ELEMENT_ANDROID_BROWSERSTACK_ACCESS_KEY }}

44
.github/workflows/quality.yml

@ -18,6 +18,13 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
- name: Add SSH private keys for submodule repositories
uses: webfactory/ssh-agent@v0.9.0
with:
ssh-private-key: ${{ secrets.ELEMENT_ENTERPRISE_DEPLOY_KEY }}
- name: Clone submodules
if: github.repository == 'element-hq/element-x-android'
run: git submodule update --init --recursive
- name: Run code quality check suite - name: Run code quality check suite
run: ./tools/check/check_code_quality.sh run: ./tools/check/check_code_quality.sh
@ -68,6 +75,13 @@ jobs:
# Ensure we are building the branch and not the branch after being merged on develop # Ensure we are building the branch and not the branch after being merged on develop
# https://github.com/actions/checkout/issues/881 # https://github.com/actions/checkout/issues/881
ref: ${{ github.event_name == 'pull_request' && github.event.pull_request.head.sha || github.ref }} ref: ${{ github.event_name == 'pull_request' && github.event.pull_request.head.sha || github.ref }}
- name: Add SSH private keys for submodule repositories
uses: webfactory/ssh-agent@v0.9.0
with:
ssh-private-key: ${{ secrets.ELEMENT_ENTERPRISE_DEPLOY_KEY }}
- name: Clone submodules
if: github.repository == 'element-hq/element-x-android'
run: git submodule update --init --recursive
- name: Use JDK 17 - name: Use JDK 17
uses: actions/setup-java@v4 uses: actions/setup-java@v4
with: with:
@ -100,6 +114,13 @@ jobs:
# Ensure we are building the branch and not the branch after being merged on develop # Ensure we are building the branch and not the branch after being merged on develop
# https://github.com/actions/checkout/issues/881 # https://github.com/actions/checkout/issues/881
ref: ${{ github.event_name == 'pull_request' && github.event.pull_request.head.sha || github.ref }} ref: ${{ github.event_name == 'pull_request' && github.event.pull_request.head.sha || github.ref }}
- name: Add SSH private keys for submodule repositories
uses: webfactory/ssh-agent@v0.9.0
with:
ssh-private-key: ${{ secrets.ELEMENT_ENTERPRISE_DEPLOY_KEY }}
- name: Clone submodules
if: github.repository == 'element-hq/element-x-android'
run: git submodule update --init --recursive
- name: Use JDK 17 - name: Use JDK 17
uses: actions/setup-java@v4 uses: actions/setup-java@v4
with: with:
@ -136,6 +157,13 @@ jobs:
# Ensure we are building the branch and not the branch after being merged on develop # Ensure we are building the branch and not the branch after being merged on develop
# https://github.com/actions/checkout/issues/881 # https://github.com/actions/checkout/issues/881
ref: ${{ github.event_name == 'pull_request' && github.event.pull_request.head.sha || github.ref }} ref: ${{ github.event_name == 'pull_request' && github.event.pull_request.head.sha || github.ref }}
- name: Add SSH private keys for submodule repositories
uses: webfactory/ssh-agent@v0.9.0
with:
ssh-private-key: ${{ secrets.ELEMENT_ENTERPRISE_DEPLOY_KEY }}
- name: Clone submodules
if: github.repository == 'element-hq/element-x-android'
run: git submodule update --init --recursive
- name: Use JDK 17 - name: Use JDK 17
uses: actions/setup-java@v4 uses: actions/setup-java@v4
with: with:
@ -168,6 +196,13 @@ jobs:
# Ensure we are building the branch and not the branch after being merged on develop # Ensure we are building the branch and not the branch after being merged on develop
# https://github.com/actions/checkout/issues/881 # https://github.com/actions/checkout/issues/881
ref: ${{ github.event_name == 'pull_request' && github.event.pull_request.head.sha || github.ref }} ref: ${{ github.event_name == 'pull_request' && github.event.pull_request.head.sha || github.ref }}
- name: Add SSH private keys for submodule repositories
uses: webfactory/ssh-agent@v0.9.0
with:
ssh-private-key: ${{ secrets.ELEMENT_ENTERPRISE_DEPLOY_KEY }}
- name: Clone submodules
if: github.repository == 'element-hq/element-x-android'
run: git submodule update --init --recursive
- name: Use JDK 17 - name: Use JDK 17
uses: actions/setup-java@v4 uses: actions/setup-java@v4
with: with:
@ -200,6 +235,13 @@ jobs:
# Ensure we are building the branch and not the branch after being merged on develop # Ensure we are building the branch and not the branch after being merged on develop
# https://github.com/actions/checkout/issues/881 # https://github.com/actions/checkout/issues/881
ref: ${{ github.event_name == 'pull_request' && github.event.pull_request.head.sha || github.ref }} ref: ${{ github.event_name == 'pull_request' && github.event.pull_request.head.sha || github.ref }}
- name: Add SSH private keys for submodule repositories
uses: webfactory/ssh-agent@v0.9.0
with:
ssh-private-key: ${{ secrets.ELEMENT_ENTERPRISE_DEPLOY_KEY }}
- name: Clone submodules
if: github.repository == 'element-hq/element-x-android'
run: git submodule update --init --recursive
- name: Use JDK 17 - name: Use JDK 17
uses: actions/setup-java@v4 uses: actions/setup-java@v4
with: with:
@ -245,7 +287,7 @@ jobs:
yarn add danger-plugin-lint-report --dev yarn add danger-plugin-lint-report --dev
- name: Danger lint - name: Danger lint
if: always() if: always()
uses: danger/danger-js@12.3.2 uses: danger/danger-js@12.3.3
with: with:
args: "--dangerfile ./tools/danger/dangerfile-lint.js" args: "--dangerfile ./tools/danger/dangerfile-lint.js"
env: env:

34
.github/workflows/release.yml

@ -39,6 +39,40 @@ jobs:
path: | path: |
app/build/outputs/bundle/gplayRelease/app-gplay-release.aab app/build/outputs/bundle/gplayRelease/app-gplay-release.aab
enterprise:
name: Create App Bundle Enterprise
runs-on: ubuntu-latest
concurrency:
group: ${{ format('build-release-main-gplay-{0}', github.sha) }}
cancel-in-progress: true
steps:
- uses: actions/checkout@v4
- name: Add SSH private keys for submodule repositories
uses: webfactory/ssh-agent@v0.9.0
with:
ssh-private-key: ${{ secrets.ELEMENT_ENTERPRISE_DEPLOY_KEY }}
- name: Clone submodules
run: git submodule update --init --recursive
- name: Use JDK 17
uses: actions/setup-java@v4
with:
distribution: 'temurin' # See 'Supported distributions' for available options
java-version: '17'
- name: Configure gradle
uses: gradle/actions/setup-gradle@v3
- name: Create Enterprise app bundle
env:
ELEMENT_ANDROID_MAPTILER_API_KEY: ${{ secrets.MAPTILER_KEY }}
ELEMENT_ANDROID_MAPTILER_LIGHT_MAP_ID: ${{ secrets.MAPTILER_LIGHT_MAP_ID }}
ELEMENT_ANDROID_MAPTILER_DARK_MAP_ID: ${{ secrets.MAPTILER_DARK_MAP_ID }}
run: ./gradlew bundleGplayRelease $CI_GRADLE_ARG_PROPERTIES
- name: Upload bundle as artifact
uses: actions/upload-artifact@v4
with:
name: elementx-enterprise-app-gplay-bundle-unsigned
path: |
app/build/outputs/bundle/gplayRelease/app-gplay-release.aab
fdroid: fdroid:
name: Create APKs (FDroid) name: Create APKs (FDroid)
runs-on: ubuntu-latest runs-on: ubuntu-latest

2
.github/workflows/scripts/recordScreenshots.sh

@ -65,7 +65,7 @@ echo "Deleting previous screenshots"
./gradlew removeOldSnapshots --stacktrace --warn ./gradlew removeOldSnapshots --stacktrace --warn
echo "Record screenshots" echo "Record screenshots"
./gradlew recordPaparazziDebug --stacktrace --warn ./gradlew recordPaparazziDebug --stacktrace
echo "Committing changes" echo "Committing changes"
git config http.sslVerify false git config http.sslVerify false

1
.github/workflows/sync-localazy.yml

@ -45,3 +45,4 @@ jobs:
- Update Strings from Localazy - Update Strings from Localazy
branch: sync-localazy branch: sync-localazy
base: develop base: develop
labels: PR-i18n

1
.github/workflows/sync-sas-strings.yml

@ -31,5 +31,6 @@ jobs:
- Update SAS Strings from matrix-doc. - Update SAS Strings from matrix-doc.
branch: sync-sas-strings branch: sync-sas-strings
base: develop base: develop
labels: PR-Misc

7
.github/workflows/tests.yml

@ -38,6 +38,13 @@ jobs:
# Ensure we are building the branch and not the branch after being merged on develop # Ensure we are building the branch and not the branch after being merged on develop
# https://github.com/actions/checkout/issues/881 # https://github.com/actions/checkout/issues/881
ref: ${{ github.event_name == 'pull_request' && github.event.pull_request.head.sha || github.ref }} ref: ${{ github.event_name == 'pull_request' && github.event.pull_request.head.sha || github.ref }}
- name: Add SSH private keys for submodule repositories
uses: webfactory/ssh-agent@v0.9.0
with:
ssh-private-key: ${{ secrets.ELEMENT_ENTERPRISE_DEPLOY_KEY }}
- name: Clone submodules
if: github.repository == 'element-hq/element-x-android'
run: git submodule update --init --recursive
- name: Use JDK 17 - name: Use JDK 17
uses: actions/setup-java@v4 uses: actions/setup-java@v4
with: with:

1
.gitignore vendored

@ -52,6 +52,7 @@ captures/
.idea/modules.xml .idea/modules.xml
# Comment next line if keeping position of elements in Navigation Editor is relevant for you # Comment next line if keeping position of elements in Navigation Editor is relevant for you
.idea/navEditor.xml .idea/navEditor.xml
.idea/other.xml
.idea/tasks.xml .idea/tasks.xml
.idea/workspace.xml .idea/workspace.xml
.idea/libraries .idea/libraries

3
.gitmodules vendored

@ -0,0 +1,3 @@
[submodule "enterprise"]
path = enterprise
url = git@github.com:element-hq/element-android-enterprise.git

6
.idea/copyright/Element_Enterprise.xml

@ -0,0 +1,6 @@
<component name="CopyrightManager">
<copyright>
<option name="notice" value="© &amp;#36;today.year New Vector Limited, Element Software SARL, Element Software Inc.,&#10;and Element Software GmbH (the &quot;Element Group&quot;) only make this file available&#10;under a proprietary license model.&#10;&#10;Without a proprietary license with us, you cannot use this file. The terms of&#10;the proprietary license agreement between you and any member of the Element Group&#10;shall always apply to your use of this file. Unauthorised use, copying, distribution,&#10;or modification of this file, via any medium, is strictly prohibited.&#10;&#10;For details about the licensing terms, you must either visit our website or contact&#10;a member of our sales team." />
<option name="myName" value="Element Enterprise" />
</copyright>
</component>

6
.idea/copyright/Element_FOSS.xml

@ -0,0 +1,6 @@
<component name="CopyrightManager">
<copyright>
<option name="notice" value="Copyright (c) &amp;#36;today.year New Vector Ltd&#10;&#10;Licensed under the Apache License, Version 2.0 (the &quot;License&quot;);&#10;you may not use this file except in compliance with the License.&#10;You may obtain a copy of the License at&#10;&#10; https://www.apache.org/licenses/LICENSE-2.0&#10;&#10;Unless required by applicable law or agreed to in writing, software&#10;distributed under the License is distributed on an &quot;AS IS&quot; BASIS,&#10;WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.&#10;See the License for the specific language governing permissions and&#10;limitations under the License." />
<option name="myName" value="Element FOSS" />
</copyright>
</component>

6
.idea/copyright/NewVector.xml

@ -1,6 +0,0 @@
<component name="CopyrightManager">
<copyright>
<option name="notice" value="Copyright (c) &amp;#36;today.year New Vector Ltd&#10;&#10;Licensed under the Apache License, Version 2.0 (the &quot;License&quot;);&#10;you may not use this file except in compliance with the License.&#10;You may obtain a copy of the License at&#10;&#10; http://www.apache.org/licenses/LICENSE-2.0&#10;&#10;Unless required by applicable law or agreed to in writing, software&#10;distributed under the License is distributed on an &quot;AS IS&quot; BASIS,&#10;WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.&#10;See the License for the specific language governing permissions and&#10;limitations under the License." />
<option name="myName" value="NewVector" />
</copyright>
</component>

6
.idea/copyright/profiles_settings.xml

@ -1,3 +1,7 @@
<component name="CopyrightManager"> <component name="CopyrightManager">
<settings default="NewVector" /> <settings default="Element FOSS">
<module2copyright>
<element module="Enterprise" copyright="Element Enterprise" />
</module2copyright>
</settings>
</component> </component>

3
.idea/scopes/Enterprise.xml

@ -0,0 +1,3 @@
<component name="DependencyValidationManager">
<scope name="Enterprise" pattern="file://*||file[ElementX.enterprise*]:*//*" />
</component>

14
CONTRIBUTING.md

@ -91,19 +91,9 @@ This project is full Kotlin. Please do not write Java classes.
### Changelog ### Changelog
Please create at least one file under ./changelog.d containing details about your change. Towncrier will be used when preparing the release. The release notes are generated from the pull request titles and labels. If possible, the title must describe best what will be the user facing change.
Towncrier says to use the PR number for the filename, but the issue number is also fine. You will also need to add a label starting by `PR-` to you Pull Request to help categorize the release note. The label should be added by the PR author, but can be added by the reviewer if the submitter does not have right to add label. Also note that the label can be added after the PR has been merged, as soon as the release is not done yet.
Supported filename extensions are:
- ``.feature``: Signifying a new feature in Element Android or in the Matrix SDK.
- ``.bugfix``: Signifying a bug fix.
- ``.wip``: Signifying a work in progress change, typically a component of a larger feature which will be enabled once all tasks are complete.
- ``.doc``: Signifying a documentation improvement.
- ``.misc``: Any other changes.
See https://github.com/twisted/towncrier#news-fragments if you need more details.
### Code quality ### Code quality

44
app/build.gradle.kts

@ -17,6 +17,7 @@
@file:Suppress("UnstableApiUsage") @file:Suppress("UnstableApiUsage")
import com.android.build.api.variant.FilterConfiguration.FilterType.ABI import com.android.build.api.variant.FilterConfiguration.FilterType.ABI
import extension.allEnterpriseImpl
import extension.allFeaturesImpl import extension.allFeaturesImpl
import extension.allLibrariesImpl import extension.allLibrariesImpl
import extension.allServicesImpl import extension.allServicesImpl
@ -30,7 +31,6 @@ plugins {
id("io.element.android-compose-application") id("io.element.android-compose-application")
alias(libs.plugins.kotlin.android) alias(libs.plugins.kotlin.android)
alias(libs.plugins.anvil) alias(libs.plugins.anvil)
alias(libs.plugins.ksp)
alias(libs.plugins.kapt) alias(libs.plugins.kapt)
// When using precompiled plugins, we need to apply the firebase plugin like this // When using precompiled plugins, we need to apply the firebase plugin like this
id(libs.plugins.firebaseAppDistribution.get().pluginId) id(libs.plugins.firebaseAppDistribution.get().pluginId)
@ -46,7 +46,11 @@ android {
namespace = "io.element.android.x" namespace = "io.element.android.x"
defaultConfig { defaultConfig {
applicationId = "io.element.android.x" applicationId = if (isEnterpriseBuild) {
"io.element.enterprise"
} else {
"io.element.android.x"
}
targetSdk = Versions.targetSdk targetSdk = Versions.targetSdk
versionCode = Versions.versionCode versionCode = Versions.versionCode
versionName = Versions.versionName versionName = Versions.versionName
@ -99,15 +103,22 @@ android {
} }
} }
val baseAppName = if (isEnterpriseBuild) {
"Element Enterprise"
} else {
"Element X"
}
logger.warnInBox("Building $baseAppName")
buildTypes { buildTypes {
getByName("debug") { getByName("debug") {
resValue("string", "app_name", "Element X dbg") resValue("string", "app_name", "$baseAppName dbg")
applicationIdSuffix = ".debug" applicationIdSuffix = ".debug"
signingConfig = signingConfigs.getByName("debug") signingConfig = signingConfigs.getByName("debug")
} }
getByName("release") { getByName("release") {
resValue("string", "app_name", "Element X") resValue("string", "app_name", baseAppName)
signingConfig = signingConfigs.getByName("debug") signingConfig = signingConfigs.getByName("debug")
postprocessing { postprocessing {
@ -124,7 +135,7 @@ android {
initWith(release) initWith(release)
applicationIdSuffix = ".nightly" applicationIdSuffix = ".nightly"
versionNameSuffix = "-nightly" versionNameSuffix = "-nightly"
resValue("string", "app_name", "Element X nightly") resValue("string", "app_name", "$baseAppName nightly")
matchingFallbacks += listOf("release") matchingFallbacks += listOf("release")
signingConfig = signingConfigs.getByName("nightly") signingConfig = signingConfigs.getByName("nightly")
@ -140,12 +151,19 @@ android {
artifactPath = "$rootDir/app/build/outputs/apk/gplay/nightly/app-gplay-universal-nightly.apk" artifactPath = "$rootDir/app/build/outputs/apk/gplay/nightly/app-gplay-universal-nightly.apk"
// artifactType = "AAB" // artifactType = "AAB"
// artifactPath = "$rootDir/app/build/outputs/bundle/nightly/app-nightly.aab" // artifactPath = "$rootDir/app/build/outputs/bundle/nightly/app-nightly.aab"
// This file will be generated by the GitHub action releaseNotesFile = "tools/release/ReleaseNotesNightly.md"
releaseNotesFile = "CHANGES_NIGHTLY.md" groups = if (isEnterpriseBuild) {
groups = "external-testers" "enterprise-testers"
} else {
"external-testers"
}
// This should not be required, but if I do not add the appId, I get this error: // This should not be required, but if I do not add the appId, I get this error:
// "App Distribution halted because it had a problem uploading the APK: [404] Requested entity was not found." // "App Distribution halted because it had a problem uploading the APK: [404] Requested entity was not found."
appId = "1:912726360885:android:e17435e0beb0303000427c" appId = if (isEnterpriseBuild) {
"1:912726360885:android:3f7e1fe644d99d5a00427c"
} else {
"1:912726360885:android:e17435e0beb0303000427c"
}
} }
} }
} }
@ -213,7 +231,6 @@ knit {
exclude( exclude(
"**/build/**", "**/build/**",
"*/.gradle/**", "*/.gradle/**",
"*/towncrier/template.md",
"**/CHANGES.md", "**/CHANGES.md",
) )
} }
@ -222,6 +239,12 @@ knit {
dependencies { dependencies {
allLibrariesImpl() allLibrariesImpl()
allServicesImpl() allServicesImpl()
if (isEnterpriseBuild) {
allEnterpriseImpl(rootDir, logger)
implementation(projects.appicon.enterprise)
} else {
implementation(projects.appicon.element)
}
allFeaturesImpl(rootDir, logger) allFeaturesImpl(rootDir, logger)
implementation(projects.features.migration.api) implementation(projects.features.migration.api)
implementation(projects.anvilannotations) implementation(projects.anvilannotations)
@ -262,6 +285,5 @@ dependencies {
testImplementation(libs.test.turbine) testImplementation(libs.test.turbine)
testImplementation(projects.libraries.matrix.test) testImplementation(projects.libraries.matrix.test)
ksp(libs.showkase.processor)
koverDependencies() koverDependencies()
} }

8
app/src/main/AndroidManifest.xml

@ -40,11 +40,9 @@
android:name="androidx.startup.InitializationProvider" android:name="androidx.startup.InitializationProvider"
android:authorities="${applicationId}.androidx-startup" android:authorities="${applicationId}.androidx-startup"
android:exported="false"> android:exported="false">
<meta-data <meta-data
android:name='androidx.lifecycle.ProcessLifecycleInitializer' android:name='androidx.lifecycle.ProcessLifecycleInitializer'
android:value='androidx.startup' /> android:value='androidx.startup' />
</provider> </provider>
<activity <activity
@ -146,12 +144,6 @@
</intent-filter> </intent-filter>
</activity-alias> </activity-alias>
<provider
android:name="androidx.startup.InitializationProvider"
android:authorities="${applicationId}.androidx-startup"
android:exported="false"
tools:node="remove" />
<provider <provider
android:name="androidx.core.content.FileProvider" android:name="androidx.core.content.FileProvider"
android:authorities="${applicationId}.fileprovider" android:authorities="${applicationId}.fileprovider"

8
app/src/main/kotlin/io/element/android/x/di/AppModule.kt

@ -24,6 +24,7 @@ import com.squareup.anvil.annotations.ContributesTo
import dagger.Module import dagger.Module
import dagger.Provides import dagger.Provides
import io.element.android.appconfig.ApplicationConfig import io.element.android.appconfig.ApplicationConfig
import io.element.android.features.enterprise.api.EnterpriseService
import io.element.android.features.messages.impl.timeline.components.customreaction.DefaultEmojibaseProvider import io.element.android.features.messages.impl.timeline.components.customreaction.DefaultEmojibaseProvider
import io.element.android.features.messages.impl.timeline.components.customreaction.EmojibaseProvider import io.element.android.features.messages.impl.timeline.components.customreaction.EmojibaseProvider
import io.element.android.libraries.androidutils.system.getVersionCodeFromManifest import io.element.android.libraries.androidutils.system.getVersionCodeFromManifest
@ -77,13 +78,18 @@ object AppModule {
@Provides @Provides
@SingleIn(AppScope::class) @SingleIn(AppScope::class)
fun providesBuildMeta(@ApplicationContext context: Context, buildType: BuildType) = BuildMeta( fun providesBuildMeta(
@ApplicationContext context: Context,
buildType: BuildType,
enterpriseService: EnterpriseService,
) = BuildMeta(
isDebuggable = BuildConfig.DEBUG, isDebuggable = BuildConfig.DEBUG,
buildType = buildType, buildType = buildType,
applicationName = ApplicationConfig.APPLICATION_NAME.takeIf { it.isNotEmpty() } ?: context.getString(R.string.app_name), applicationName = ApplicationConfig.APPLICATION_NAME.takeIf { it.isNotEmpty() } ?: context.getString(R.string.app_name),
productionApplicationName = ApplicationConfig.PRODUCTION_APPLICATION_NAME, productionApplicationName = ApplicationConfig.PRODUCTION_APPLICATION_NAME,
desktopApplicationName = ApplicationConfig.DESKTOP_APPLICATION_NAME, desktopApplicationName = ApplicationConfig.DESKTOP_APPLICATION_NAME,
applicationId = BuildConfig.APPLICATION_ID, applicationId = BuildConfig.APPLICATION_ID,
isEnterpriseBuild = enterpriseService.isEnterpriseBuild,
// TODO EAx Config.LOW_PRIVACY_LOG_ENABLE, // TODO EAx Config.LOW_PRIVACY_LOG_ENABLE,
lowPrivacyLoggingEnabled = false, lowPrivacyLoggingEnabled = false,
versionName = BuildConfig.VERSION_NAME, versionName = BuildConfig.VERSION_NAME,

70
app/src/main/kotlin/io/element/android/x/icon/IconPreview.kt

@ -1,70 +0,0 @@
/*
* 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.icon
import androidx.compose.foundation.Image
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.shape.CircleShape
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.ColorFilter
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import io.element.android.x.R
@Preview
@Composable
internal fun IconPreview() {
Box {
Image(painter = painterResource(id = R.mipmap.ic_launcher_background), contentDescription = null)
Image(painter = painterResource(id = R.mipmap.ic_launcher_foreground), contentDescription = null)
}
}
@Preview
@Composable
internal fun RoundIconPreview() {
Box(modifier = Modifier.clip(shape = CircleShape)) {
Image(painter = painterResource(id = R.mipmap.ic_launcher_background), contentDescription = null)
Image(painter = painterResource(id = R.mipmap.ic_launcher_foreground), contentDescription = null)
}
}
@Preview
@Composable
internal fun MonochromeIconPreview() {
Box(
modifier = Modifier
.size(108.dp)
.background(Color(0xFF2F3133))
.clip(shape = RoundedCornerShape(32.dp)),
contentAlignment = Alignment.Center
) {
Image(
painter = painterResource(id = R.mipmap.ic_launcher_monochrome),
colorFilter = ColorFilter.tint(Color(0xFFC3E0F6)),
contentDescription = null
)
}
}

1
app/src/main/res/xml/locales_config.xml

@ -4,6 +4,7 @@
<locale android:name="bg"/> <locale android:name="bg"/>
<locale android:name="cs"/> <locale android:name="cs"/>
<locale android:name="de"/> <locale android:name="de"/>
<locale android:name="el"/>
<locale android:name="en"/> <locale android:name="en"/>
<locale android:name="es"/> <locale android:name="es"/>
<locale android:name="et"/> <locale android:name="et"/>

2
appconfig/build.gradle.kts

@ -16,7 +16,6 @@
plugins { plugins {
id("io.element.android-library") id("io.element.android-library")
alias(libs.plugins.anvil) alias(libs.plugins.anvil)
alias(libs.plugins.ksp)
} }
android { android {
@ -28,6 +27,7 @@ anvil {
} }
dependencies { dependencies {
implementation(libs.androidx.annotationjvm)
implementation(libs.dagger) implementation(libs.dagger)
implementation(projects.libraries.di) implementation(projects.libraries.di)
implementation(projects.libraries.matrix.api) implementation(projects.libraries.matrix.api)

12
appconfig/src/main/kotlin/io/element/android/appconfig/AuthenticationConfig.kt

@ -19,6 +19,18 @@ package io.element.android.appconfig
object AuthenticationConfig { object AuthenticationConfig {
const val MATRIX_ORG_URL = "https://matrix.org" const val MATRIX_ORG_URL = "https://matrix.org"
/**
* Default homeserver url to sign in with, unless the user selects a different one.
*/
const val DEFAULT_HOMESERVER_URL = MATRIX_ORG_URL const val DEFAULT_HOMESERVER_URL = MATRIX_ORG_URL
/**
* URL with some docs that explain what's sliding sync and how to add it to your home server.
*/
const val SLIDING_SYNC_READ_MORE_URL = "https://github.com/matrix-org/sliding-sync/blob/main/docs/Landing.md" const val SLIDING_SYNC_READ_MORE_URL = "https://github.com/matrix-org/sliding-sync/blob/main/docs/Landing.md"
/**
* Force a sliding sync proxy url, if not null, the proxy url in the .well-known file will be ignored.
*/
val SLIDING_SYNC_PROXY_URL: String? = null
} }

6
appconfig/src/main/kotlin/io/element/android/appconfig/NotificationConfig.kt

@ -16,6 +16,9 @@
package io.element.android.appconfig package io.element.android.appconfig
import android.graphics.Color
import androidx.annotation.ColorInt
object NotificationConfig { object NotificationConfig {
// TODO EAx Implement and set to true at some point // TODO EAx Implement and set to true at some point
const val SUPPORT_MARK_AS_READ_ACTION = false const val SUPPORT_MARK_AS_READ_ACTION = false
@ -25,4 +28,7 @@ object NotificationConfig {
// TODO EAx Implement and set to true at some point // TODO EAx Implement and set to true at some point
const val SUPPORT_QUICK_REPLY_ACTION = false const val SUPPORT_QUICK_REPLY_ACTION = false
@ColorInt
val NOTIFICATION_ACCENT_COLOR: Int = Color.parseColor("#FF0DBD8B")
} }

2
appconfig/src/main/kotlin/io/element/android/appconfig/OnBoardingConfig.kt

@ -18,7 +18,7 @@ package io.element.android.appconfig
object OnBoardingConfig { object OnBoardingConfig {
/** Whether the user can use QR code login. */ /** Whether the user can use QR code login. */
const val CAN_LOGIN_WITH_QR_CODE = false const val CAN_LOGIN_WITH_QR_CODE = true
/** Whether the user can create an account using the app. */ /** Whether the user can create an account using the app. */
const val CAN_CREATE_ACCOUNT = false const val CAN_CREATE_ACCOUNT = false

26
appicon/element/build.gradle.kts

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

0
app/src/debug/res/drawable/ic_launcher_background.xml → appicon/element/src/debug/res/drawable/ic_launcher_background.xml

0
app/src/main/ic_launcher-playstore.png → appicon/element/src/main/ic_launcher-playstore.png

Before

Width:  |  Height:  |  Size: 263 KiB

After

Width:  |  Height:  |  Size: 263 KiB

69
appicon/element/src/main/kotlin/io/element/android/appicon/element/IconPreview.kt

@ -0,0 +1,69 @@
/*
* 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.appicon.element
import androidx.compose.foundation.Image
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.shape.CircleShape
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.ColorFilter
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
@Preview
@Composable
internal fun IconPreview() {
Box {
Image(painter = painterResource(id = R.mipmap.ic_launcher_background), contentDescription = null)
Image(painter = painterResource(id = R.mipmap.ic_launcher_foreground), contentDescription = null)
}
}
@Preview
@Composable
internal fun RoundIconPreview() {
Box(modifier = Modifier.clip(shape = CircleShape)) {
Image(painter = painterResource(id = R.mipmap.ic_launcher_background), contentDescription = null)
Image(painter = painterResource(id = R.mipmap.ic_launcher_foreground), contentDescription = null)
}
}
@Preview
@Composable
internal fun MonochromeIconPreview() {
Box(
modifier = Modifier
.size(108.dp)
.background(Color(0xFF2F3133))
.clip(shape = RoundedCornerShape(32.dp)),
contentAlignment = Alignment.Center
) {
Image(
painter = painterResource(id = R.mipmap.ic_launcher_monochrome),
colorFilter = ColorFilter.tint(Color(0xFFC3E0F6)),
contentDescription = null
)
}
}

0
app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml → appicon/element/src/main/res/mipmap-anydpi-v26/ic_launcher.xml

0
app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml → appicon/element/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml

0
app/src/main/res/mipmap-hdpi/ic_launcher.webp → appicon/element/src/main/res/mipmap-hdpi/ic_launcher.webp

Before

Width:  |  Height:  |  Size: 4.0 KiB

After

Width:  |  Height:  |  Size: 4.0 KiB

0
app/src/main/res/mipmap-hdpi/ic_launcher_background.webp → appicon/element/src/main/res/mipmap-hdpi/ic_launcher_background.webp

Before

Width:  |  Height:  |  Size: 10 KiB

After

Width:  |  Height:  |  Size: 10 KiB

0
app/src/main/res/mipmap-hdpi/ic_launcher_foreground.webp → appicon/element/src/main/res/mipmap-hdpi/ic_launcher_foreground.webp

Before

Width:  |  Height:  |  Size: 8.1 KiB

After

Width:  |  Height:  |  Size: 8.1 KiB

0
app/src/main/res/mipmap-hdpi/ic_launcher_monochrome.webp → appicon/element/src/main/res/mipmap-hdpi/ic_launcher_monochrome.webp

Before

Width:  |  Height:  |  Size: 1.4 KiB

After

Width:  |  Height:  |  Size: 1.4 KiB

0
app/src/main/res/mipmap-hdpi/ic_launcher_round.webp → appicon/element/src/main/res/mipmap-hdpi/ic_launcher_round.webp

Before

Width:  |  Height:  |  Size: 5.5 KiB

After

Width:  |  Height:  |  Size: 5.5 KiB

0
app/src/main/res/mipmap-mdpi/ic_launcher.webp → appicon/element/src/main/res/mipmap-mdpi/ic_launcher.webp

Before

Width:  |  Height:  |  Size: 2.6 KiB

After

Width:  |  Height:  |  Size: 2.6 KiB

0
app/src/main/res/mipmap-mdpi/ic_launcher_background.webp → appicon/element/src/main/res/mipmap-mdpi/ic_launcher_background.webp

Before

Width:  |  Height:  |  Size: 4.7 KiB

After

Width:  |  Height:  |  Size: 4.7 KiB

0
app/src/main/res/mipmap-mdpi/ic_launcher_foreground.webp → appicon/element/src/main/res/mipmap-mdpi/ic_launcher_foreground.webp

Before

Width:  |  Height:  |  Size: 4.7 KiB

After

Width:  |  Height:  |  Size: 4.7 KiB

0
app/src/main/res/mipmap-mdpi/ic_launcher_monochrome.webp → appicon/element/src/main/res/mipmap-mdpi/ic_launcher_monochrome.webp

Before

Width:  |  Height:  |  Size: 946 B

After

Width:  |  Height:  |  Size: 946 B

0
app/src/main/res/mipmap-mdpi/ic_launcher_round.webp → appicon/element/src/main/res/mipmap-mdpi/ic_launcher_round.webp

Before

Width:  |  Height:  |  Size: 3.2 KiB

After

Width:  |  Height:  |  Size: 3.2 KiB

0
app/src/main/res/mipmap-xhdpi/ic_launcher.webp → appicon/element/src/main/res/mipmap-xhdpi/ic_launcher.webp

Before

Width:  |  Height:  |  Size: 6.0 KiB

After

Width:  |  Height:  |  Size: 6.0 KiB

0
app/src/main/res/mipmap-xhdpi/ic_launcher_background.webp → appicon/element/src/main/res/mipmap-xhdpi/ic_launcher_background.webp

Before

Width:  |  Height:  |  Size: 19 KiB

After

Width:  |  Height:  |  Size: 19 KiB

0
app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.webp → appicon/element/src/main/res/mipmap-xhdpi/ic_launcher_foreground.webp

Before

Width:  |  Height:  |  Size: 13 KiB

After

Width:  |  Height:  |  Size: 13 KiB

0
app/src/main/res/mipmap-xhdpi/ic_launcher_monochrome.webp → appicon/element/src/main/res/mipmap-xhdpi/ic_launcher_monochrome.webp

Before

Width:  |  Height:  |  Size: 1.9 KiB

After

Width:  |  Height:  |  Size: 1.9 KiB

0
app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp → appicon/element/src/main/res/mipmap-xhdpi/ic_launcher_round.webp

Before

Width:  |  Height:  |  Size: 8.1 KiB

After

Width:  |  Height:  |  Size: 8.1 KiB

0
app/src/main/res/mipmap-xxhdpi/ic_launcher.webp → appicon/element/src/main/res/mipmap-xxhdpi/ic_launcher.webp

Before

Width:  |  Height:  |  Size: 10 KiB

After

Width:  |  Height:  |  Size: 10 KiB

0
app/src/main/res/mipmap-xxhdpi/ic_launcher_background.webp → appicon/element/src/main/res/mipmap-xxhdpi/ic_launcher_background.webp

Before

Width:  |  Height:  |  Size: 46 KiB

After

Width:  |  Height:  |  Size: 46 KiB

0
app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.webp → appicon/element/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.webp

Before

Width:  |  Height:  |  Size: 26 KiB

After

Width:  |  Height:  |  Size: 26 KiB

0
app/src/main/res/mipmap-xxhdpi/ic_launcher_monochrome.webp → appicon/element/src/main/res/mipmap-xxhdpi/ic_launcher_monochrome.webp

Before

Width:  |  Height:  |  Size: 3.3 KiB

After

Width:  |  Height:  |  Size: 3.3 KiB

0
app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp → appicon/element/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp

Before

Width:  |  Height:  |  Size: 14 KiB

After

Width:  |  Height:  |  Size: 14 KiB

0
app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp → appicon/element/src/main/res/mipmap-xxxhdpi/ic_launcher.webp

Before

Width:  |  Height:  |  Size: 16 KiB

After

Width:  |  Height:  |  Size: 16 KiB

0
app/src/main/res/mipmap-xxxhdpi/ic_launcher_background.webp → appicon/element/src/main/res/mipmap-xxxhdpi/ic_launcher_background.webp

Before

Width:  |  Height:  |  Size: 84 KiB

After

Width:  |  Height:  |  Size: 84 KiB

0
app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.webp → appicon/element/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.webp

Before

Width:  |  Height:  |  Size: 45 KiB

After

Width:  |  Height:  |  Size: 45 KiB

0
app/src/main/res/mipmap-xxxhdpi/ic_launcher_monochrome.webp → appicon/element/src/main/res/mipmap-xxxhdpi/ic_launcher_monochrome.webp

Before

Width:  |  Height:  |  Size: 4.6 KiB

After

Width:  |  Height:  |  Size: 4.6 KiB

0
app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp → appicon/element/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp

Before

Width:  |  Height:  |  Size: 22 KiB

After

Width:  |  Height:  |  Size: 22 KiB

0
app/src/nightly/res/drawable/ic_launcher_background.xml → appicon/element/src/nightly/res/drawable/ic_launcher_background.xml

0
app/src/release/res/drawable/ic_launcher_background.xml → appicon/element/src/release/res/drawable/ic_launcher_background.xml

26
appicon/enterprise/build.gradle.kts

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

10
appicon/enterprise/src/debug/res/drawable/ic_launcher_background_enterprise.xml

@ -0,0 +1,10 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="108dp"
android:height="108dp"
android:viewportWidth="108"
android:viewportHeight="108">
<path
android:fillColor="#F7F07E"
android:fillType="evenOdd"
android:pathData="m0,0h108v108h-108z" />
</vector>

53
appicon/enterprise/src/main/kotlin/io/element/android/appicon/enterprise/IconPreview.kt

@ -0,0 +1,53 @@
/*
* Copyright (c) 2024 New Vector Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://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.appicon.enterprise
import androidx.compose.foundation.Image
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.shape.CircleShape
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.tooling.preview.Preview
@Preview
@Composable
internal fun IconPreview() {
Box {
Image(painter = painterResource(id = R.mipmap.ic_launcher_background_enterprise), contentDescription = null)
Image(
modifier = Modifier.align(Alignment.Center),
painter = painterResource(id = R.mipmap.ic_launcher_foreground_enterprise),
contentDescription = null,
)
}
}
@Preview
@Composable
internal fun RoundIconPreview() {
Box(modifier = Modifier.clip(shape = CircleShape)) {
Image(painter = painterResource(id = R.mipmap.ic_launcher_background_enterprise), contentDescription = null)
Image(
modifier = Modifier.align(Alignment.Center),
painter = painterResource(id = R.mipmap.ic_launcher_foreground_enterprise),
contentDescription = null,
)
}
}

21
appicon/enterprise/src/main/res/mipmap-anydpi/ic_launcher.xml

@ -0,0 +1,21 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
~ Copyright (c) 2024 New Vector Ltd
~
~ Licensed under the Apache License, Version 2.0 (the "License");
~ you may not use this file except in compliance with the License.
~ You may obtain a copy of the License at
~
~ http://www.apache.org/licenses/LICENSE-2.0
~
~ Unless required by applicable law or agreed to in writing, software
~ distributed under the License is distributed on an "AS IS" BASIS,
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
~ See the License for the specific language governing permissions and
~ limitations under the License.
-->
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
<background android:drawable="@drawable/ic_launcher_background_enterprise"/>
<foreground android:drawable="@mipmap/ic_launcher_foreground_enterprise"/>
</adaptive-icon>

21
appicon/enterprise/src/main/res/mipmap-anydpi/ic_launcher_round.xml

@ -0,0 +1,21 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
~ Copyright (c) 2024 New Vector Ltd
~
~ Licensed under the Apache License, Version 2.0 (the "License");
~ you may not use this file except in compliance with the License.
~ You may obtain a copy of the License at
~
~ http://www.apache.org/licenses/LICENSE-2.0
~
~ Unless required by applicable law or agreed to in writing, software
~ distributed under the License is distributed on an "AS IS" BASIS,
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
~ See the License for the specific language governing permissions and
~ limitations under the License.
-->
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
<background android:drawable="@drawable/ic_launcher_background_enterprise" />
<foreground android:drawable="@mipmap/ic_launcher_foreground_enterprise" />
</adaptive-icon>

BIN
appicon/enterprise/src/main/res/mipmap-hdpi/ic_launcher_background_enterprise.webp

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

BIN
appicon/enterprise/src/main/res/mipmap-mdpi/ic_launcher_background_enterprise.webp

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.7 KiB

BIN
appicon/enterprise/src/main/res/mipmap-xhdpi/ic_launcher_background_enterprise.webp

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

BIN
appicon/enterprise/src/main/res/mipmap-xxhdpi/ic_launcher_background_enterprise.webp

Binary file not shown.

After

Width:  |  Height:  |  Size: 46 KiB

BIN
appicon/enterprise/src/main/res/mipmap-xxhdpi/ic_launcher_foreground_enterprise.webp

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

BIN
appicon/enterprise/src/main/res/mipmap-xxxhdpi/ic_launcher_background_enterprise.webp

Binary file not shown.

After

Width:  |  Height:  |  Size: 84 KiB

10
appicon/enterprise/src/nightly/res/drawable/ic_launcher_background_enterprise.xml

@ -0,0 +1,10 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="108dp"
android:height="108dp"
android:viewportWidth="108"
android:viewportHeight="108">
<path
android:fillColor="#07007E"
android:fillType="evenOdd"
android:pathData="m0,0h108v108h-108z" />
</vector>

2
appicon/enterprise/src/release/res/drawable/ic_launcher_background_enterprise.xml

@ -0,0 +1,2 @@
<bitmap xmlns:android="http://schemas.android.com/apk/res/android"
android:src="@mipmap/ic_launcher_background_enterprise" />

3
appnav/build.gradle.kts

@ -21,7 +21,6 @@ import extension.allFeaturesApi
plugins { plugins {
id("io.element.android-compose-library") id("io.element.android-compose-library")
alias(libs.plugins.anvil) alias(libs.plugins.anvil)
alias(libs.plugins.ksp)
alias(libs.plugins.kapt) alias(libs.plugins.kapt)
id("kotlin-parcelize") id("kotlin-parcelize")
} }
@ -78,6 +77,4 @@ dependencies {
testImplementation(projects.services.analytics.test) testImplementation(projects.services.analytics.test)
testImplementation(libs.test.appyx.junit) testImplementation(libs.test.appyx.junit)
testImplementation(libs.test.arch.core) testImplementation(libs.test.arch.core)
ksp(libs.showkase.processor)
} }

16
appnav/src/main/kotlin/io/element/android/appnav/loggedin/SendQueues.kt

@ -24,14 +24,14 @@ import io.element.android.libraries.di.SingleIn
import io.element.android.libraries.matrix.api.MatrixClient 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.RoomId
import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.delay import kotlinx.coroutines.FlowPreview
import kotlinx.coroutines.flow.debounce
import kotlinx.coroutines.flow.launchIn import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach import kotlinx.coroutines.flow.onEach
import timber.log.Timber
import javax.inject.Inject import javax.inject.Inject
@VisibleForTesting @VisibleForTesting
const val SEND_QUEUES_RETRY_DELAY_MILLIS = 1500L const val SEND_QUEUES_RETRY_DELAY_MILLIS = 500L
@SingleIn(SessionScope::class) @SingleIn(SessionScope::class)
class SendQueues @Inject constructor( class SendQueues @Inject constructor(
@ -45,14 +45,12 @@ class SendQueues @Inject constructor(
} }
.launchIn(coroutineScope) .launchIn(coroutineScope)
@OptIn(FlowPreview::class)
matrixClient.sendQueueDisabledFlow() matrixClient.sendQueueDisabledFlow()
.onEach { roomId: RoomId -> .debounce(SEND_QUEUES_RETRY_DELAY_MILLIS)
Timber.d("Send queue disabled for room $roomId") .onEach { _: RoomId ->
if (networkMonitor.connectivity.value == NetworkStatus.Online) { if (networkMonitor.connectivity.value == NetworkStatus.Online) {
delay(SEND_QUEUES_RETRY_DELAY_MILLIS) matrixClient.setAllSendQueuesEnabled(enabled = true)
matrixClient.getRoom(roomId)?.use { room ->
room.setSendQueueEnabled(enabled = true)
}
} }
} }
.launchIn(coroutineScope) .launchIn(coroutineScope)

4
appnav/src/main/kotlin/io/element/android/appnav/root/RootNavStateFlowFactory.kt

@ -22,6 +22,7 @@ import io.element.android.appnav.di.MatrixClientsHolder
import io.element.android.features.login.api.LoginUserStory import io.element.android.features.login.api.LoginUserStory
import io.element.android.features.preferences.api.CacheService import io.element.android.features.preferences.api.CacheService
import io.element.android.libraries.matrix.api.auth.MatrixAuthenticationService import io.element.android.libraries.matrix.api.auth.MatrixAuthenticationService
import io.element.android.libraries.matrix.ui.media.ImageLoaderHolder
import io.element.android.libraries.sessionstorage.api.LoggedInState import io.element.android.libraries.sessionstorage.api.LoggedInState
import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.combine
@ -39,6 +40,7 @@ class RootNavStateFlowFactory @Inject constructor(
private val authenticationService: MatrixAuthenticationService, private val authenticationService: MatrixAuthenticationService,
private val cacheService: CacheService, private val cacheService: CacheService,
private val matrixClientsHolder: MatrixClientsHolder, private val matrixClientsHolder: MatrixClientsHolder,
private val imageLoaderHolder: ImageLoaderHolder,
private val loginUserStory: LoginUserStory, private val loginUserStory: LoginUserStory,
) { ) {
private var currentCacheIndex = 0 private var currentCacheIndex = 0
@ -69,6 +71,8 @@ class RootNavStateFlowFactory @Inject constructor(
return cacheService.clearedCacheEventFlow return cacheService.clearedCacheEventFlow
.onEach { sessionId -> .onEach { sessionId ->
matrixClientsHolder.remove(sessionId) matrixClientsHolder.remove(sessionId)
// Ensure image loader will be recreated with the new MatrixClient
imageLoaderHolder.remove(sessionId)
} }
.toIndexFlow(initialCacheIndex) .toIndexFlow(initialCacheIndex)
.onEach { cacheIndex -> .onEach { cacheIndex ->

11
appnav/src/test/kotlin/io/element/android/appnav/loggedin/SendQueuesTest.kt

@ -55,12 +55,13 @@ import org.junit.Test
runCurrent() runCurrent()
assert(setAllSendQueuesEnabledLambda) assert(setAllSendQueuesEnabledLambda)
.isCalledOnce() .isCalledExactly(2)
.with(value(true)) .withSequence(
listOf(value(true)),
listOf(value(true)),
)
assert(setRoomSendQueueEnabledLambda) assert(setRoomSendQueueEnabledLambda).isNeverCalled()
.isCalledOnce()
.with(value(true))
} }
@Test @Test

10
build.gradle.kts

@ -60,7 +60,7 @@ allprojects {
config.from(files("$rootDir/tools/detekt/detekt.yml")) config.from(files("$rootDir/tools/detekt/detekt.yml"))
} }
dependencies { dependencies {
detektPlugins("io.nlopez.compose.rules:detekt:0.4.4") detektPlugins("io.nlopez.compose.rules:detekt:0.4.5")
} }
// KtLint // KtLint
@ -160,15 +160,15 @@ allprojects {
// Record all the languages? // Record all the languages?
if (project.hasProperty("allLanguagesNoEnglish")) { if (project.hasProperty("allLanguagesNoEnglish")) {
// Do not record English language // Do not record English language
exclude("ui/S.class") exclude("ui/*.class")
} else if (project.hasProperty("allLanguages").not()) { } else if (project.hasProperty("allLanguages").not()) {
// Do not record other languages // Do not record other languages
exclude("ui/T.class") exclude("translations/*.class")
} }
} else { } else {
// Disable screenshot tests by default // Disable screenshot tests by default
exclude("ui/S.class") exclude("ui/*.class")
exclude("ui/T.class") exclude("translations/*.class")
} }
} }
} }

1
changelog.d/2869.feature

@ -0,0 +1 @@
Store and restore drafts for each room.

1
changelog.d/2916.misc

@ -0,0 +1 @@
Use a more natural date format for day dividers in the timeline. Also improve the time format for last messages in the room list.

1
changelog.d/3051.misc

@ -0,0 +1 @@
Resolve display names in mentions in real time, also send mentions with user ids as the fallback text for the link representation of the mentions.

1
changelog.d/3053.misc

@ -0,0 +1 @@
Alert for incoming call even if notifications are disabled

1
changelog.d/3068.misc

@ -0,0 +1 @@
Updated Rust SDK to `v0.2.28`. Fixed incompatibilities.

1
changelog.d/3073.bugfix

@ -0,0 +1 @@
Fix feature flags not being able to be toggle in developer settings in release builds.

1
changelog.d/3081.bugfix

@ -0,0 +1 @@
Let roles and permissions screens work for invited room members too.

1
changelog.d/3082.bugfix

@ -0,0 +1 @@
Fix image rendering after clear cache

1
changelog.d/3083.bugfix

@ -0,0 +1 @@
Improve room filters behavior

1
changelog.d/3085.bugfix

@ -0,0 +1 @@
Make sure we replace the 'answer call' pending intent on ringing call notifications.

1
changelog.d/3086.bugfix

@ -0,0 +1 @@
Make sure we don't use the main dispatcher while closing the bug report request, as it can lead to crashes in strict mode.

2
docs/danger.md

@ -22,7 +22,7 @@ Here are the checks that Danger does so far:
- PR description is not empty - PR description is not empty
- Big PR got a warning to recommend to split - Big PR got a warning to recommend to split
- PR contains a file for towncrier and extension is checked - PR contains a correct title and a label to categorize the release note
- PR does not modify frozen classes - PR does not modify frozen classes
- PR contains a Sign-Off, with exception for Element employee contributors - PR contains a Sign-Off, with exception for Element employee contributors
- PR with change on layout should include screenshot in the description (TODO Not supported yet!) - PR with change on layout should include screenshot in the description (TODO Not supported yet!)

6
docs/nightly_build.md

@ -42,11 +42,7 @@ Then you can run the following commands (which are also used in the file for [th
```sh ```sh
git checkout develop git checkout develop
mv towncrier.toml towncrier.toml.bak ./gradlew assembleGplayNightly appDistributionUploadGplayNightly
sed 's/CHANGES\.md/CHANGES_NIGHTLY\.md/' towncrier.toml.bak > towncrier.toml
rm towncrier.toml.bak
yes n | towncrier build --version nightly
./gradlew assembleGplayNightly appDistributionUploadGplayNightly $CI_GRADLE_ARG_PROPERTIES
``` ```
Then you can reset the change on the codebase. Then you can reset the change on the codebase.

2
docs/screenshot_testing.md

@ -13,7 +13,7 @@
## Overview ## Overview
- Screenshot tests are tests which record the content of a rendered screen and verify subsequent runs to check if the screen renders differently. - Screenshot tests are tests which record the content of a rendered screen and verify subsequent runs to check if the screen renders differently.
- Element X uses [Paparazzi](https://github.com/cashapp/paparazzi) to render, record and verify Composable. All Composable Preview will be use to make screenshot test, thanks to the usage of [Showkase](https://github.com/airbnb/Showkase). - Element X uses [Paparazzi](https://github.com/cashapp/paparazzi) to render, record and verify Composables. All internal/public Composable Preview will be used for screenshot tests, thanks to the usage of [ComposablePreviewScanner](https://github.com/sergio-sastre/ComposablePreviewScanner).
- The screenshot verification occurs on every pull request as part of the `tests.yml` workflow. - The screenshot verification occurs on every pull request as part of the `tests.yml` workflow.
## Setup ## Setup

1
enterprise

@ -0,0 +1 @@
Subproject commit ceb65e32d95052c028a37654a4a0410639f69053

2
fastlane/metadata/android/en-US/changelogs/40004160.txt

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

3
features/analytics/api/build.gradle.kts

@ -15,7 +15,6 @@
*/ */
plugins { plugins {
id("io.element.android-compose-library") id("io.element.android-compose-library")
alias(libs.plugins.ksp)
} }
android { android {
@ -27,6 +26,4 @@ dependencies {
implementation(projects.libraries.designsystem) implementation(projects.libraries.designsystem)
implementation(projects.libraries.androidutils) implementation(projects.libraries.androidutils)
implementation(projects.libraries.uiStrings) implementation(projects.libraries.uiStrings)
ksp(libs.showkase.processor)
} }

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

Loading…
Cancel
Save