Merge branch 'release/0.4.16' into main

This commit is contained in:
ganfra 2024-07-04 17:57:47 +02:00
commit 92dc7a307b
3323 changed files with 9310 additions and 4674 deletions

View file

@ -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
- [ ] 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/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 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

34
.github/release.yml vendored Normal file
View file

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

View file

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

View file

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

69
.github/workflows/build_enterprise.yml vendored Normal file
View file

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

View file

@ -8,10 +8,17 @@ jobs:
name: Danger main check
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
if: github.repository == 'element-hq/element-x-android'
run: git submodule update --init --recursive
- run: |
npm install --save-dev @babel/plugin-transform-flow-strip-types
- name: Danger
uses: danger/danger-js@12.3.2
uses: danger/danger-js@12.3.3
with:
args: "--dangerfile ./tools/danger/dangerfile.js"
env:

View file

@ -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:
- 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 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).`

View file

@ -22,15 +22,6 @@ jobs:
with:
distribution: 'temurin' # See 'Supported distributions' for available options
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
run: |
./gradlew assembleGplayNightly appDistributionUploadGplayNightly $CI_GRADLE_ARG_PROPERTIES

View file

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

View file

@ -18,6 +18,13 @@ jobs:
runs-on: ubuntu-latest
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
if: github.repository == 'element-hq/element-x-android'
run: git submodule update --init --recursive
- name: Run code quality check suite
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
# 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
if: github.repository == 'element-hq/element-x-android'
run: git submodule update --init --recursive
- name: Use JDK 17
uses: actions/setup-java@v4
with:
@ -100,6 +114,13 @@ jobs:
# 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
if: github.repository == 'element-hq/element-x-android'
run: git submodule update --init --recursive
- name: Use JDK 17
uses: actions/setup-java@v4
with:
@ -136,6 +157,13 @@ jobs:
# 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
if: github.repository == 'element-hq/element-x-android'
run: git submodule update --init --recursive
- name: Use JDK 17
uses: actions/setup-java@v4
with:
@ -168,6 +196,13 @@ jobs:
# 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
if: github.repository == 'element-hq/element-x-android'
run: git submodule update --init --recursive
- name: Use JDK 17
uses: actions/setup-java@v4
with:
@ -200,6 +235,13 @@ jobs:
# 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
if: github.repository == 'element-hq/element-x-android'
run: git submodule update --init --recursive
- name: Use JDK 17
uses: actions/setup-java@v4
with:
@ -245,7 +287,7 @@ jobs:
yarn add danger-plugin-lint-report --dev
- name: Danger lint
if: always()
uses: danger/danger-js@12.3.2
uses: danger/danger-js@12.3.3
with:
args: "--dangerfile ./tools/danger/dangerfile-lint.js"
env:

View file

@ -39,6 +39,40 @@ jobs:
path: |
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:
name: Create APKs (FDroid)
runs-on: ubuntu-latest

View file

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

View file

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

View file

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

View file

@ -38,6 +38,13 @@ jobs:
# 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
if: github.repository == 'element-hq/element-x-android'
run: git submodule update --init --recursive
- name: ☕️ Use JDK 17
uses: actions/setup-java@v4
with:

1
.gitignore vendored
View file

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

3
.gitmodules vendored Normal file
View file

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

6
.idea/copyright/Element_Enterprise.xml generated Normal file
View file

@ -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 generated Normal file
View file

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

View file

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

View file

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

3
.idea/scopes/Enterprise.xml generated Normal file
View file

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

View file

@ -91,19 +91,9 @@ This project is full Kotlin. Please do not write Java classes.
### 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.
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.
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.
### Code quality

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -19,6 +19,18 @@ package io.element.android.appconfig
object AuthenticationConfig {
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
/**
* 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"
/**
* 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
}

View file

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

View file

@ -18,7 +18,7 @@ package io.element.android.appconfig
object OnBoardingConfig {
/** 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. */
const val CAN_CREATE_ACCOUNT = false

View file

@ -13,12 +13,14 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.element.android.features.call.impl.wellknown
import retrofit2.http.GET
internal interface CallWellknownAPI {
@GET(".well-known/element/call.json")
suspend fun getCallWellKnown(): CallWellKnown
plugins {
id("io.element.android-compose-library")
}
android {
namespace = "io.element.android.appicon.element"
buildTypes {
register("nightly")
}
}

View file

Before

Width:  |  Height:  |  Size: 263 KiB

After

Width:  |  Height:  |  Size: 263 KiB

Before After
Before After

View file

@ -14,7 +14,7 @@
* limitations under the License.
*/
package io.element.android.x.icon
package io.element.android.appicon.element
import androidx.compose.foundation.Image
import androidx.compose.foundation.background
@ -31,7 +31,6 @@ 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

View file

Before

Width:  |  Height:  |  Size: 4 KiB

After

Width:  |  Height:  |  Size: 4 KiB

Before After
Before After

View file

Before

Width:  |  Height:  |  Size: 10 KiB

After

Width:  |  Height:  |  Size: 10 KiB

Before After
Before After

View file

Before

Width:  |  Height:  |  Size: 8.1 KiB

After

Width:  |  Height:  |  Size: 8.1 KiB

Before After
Before After

View file

Before

Width:  |  Height:  |  Size: 1.4 KiB

After

Width:  |  Height:  |  Size: 1.4 KiB

Before After
Before After

View file

Before

Width:  |  Height:  |  Size: 5.5 KiB

After

Width:  |  Height:  |  Size: 5.5 KiB

Before After
Before After

View file

Before

Width:  |  Height:  |  Size: 2.6 KiB

After

Width:  |  Height:  |  Size: 2.6 KiB

Before After
Before After

View file

Before

Width:  |  Height:  |  Size: 4.7 KiB

After

Width:  |  Height:  |  Size: 4.7 KiB

Before After
Before After

View file

Before

Width:  |  Height:  |  Size: 4.7 KiB

After

Width:  |  Height:  |  Size: 4.7 KiB

Before After
Before After

View file

Before

Width:  |  Height:  |  Size: 946 B

After

Width:  |  Height:  |  Size: 946 B

Before After
Before After

View file

Before

Width:  |  Height:  |  Size: 3.2 KiB

After

Width:  |  Height:  |  Size: 3.2 KiB

Before After
Before After

View file

Before

Width:  |  Height:  |  Size: 6 KiB

After

Width:  |  Height:  |  Size: 6 KiB

Before After
Before After

View file

Before

Width:  |  Height:  |  Size: 19 KiB

After

Width:  |  Height:  |  Size: 19 KiB

Before After
Before After

View file

Before

Width:  |  Height:  |  Size: 13 KiB

After

Width:  |  Height:  |  Size: 13 KiB

Before After
Before After

View file

Before

Width:  |  Height:  |  Size: 1.9 KiB

After

Width:  |  Height:  |  Size: 1.9 KiB

Before After
Before After

View file

Before

Width:  |  Height:  |  Size: 8.1 KiB

After

Width:  |  Height:  |  Size: 8.1 KiB

Before After
Before After

View file

Before

Width:  |  Height:  |  Size: 10 KiB

After

Width:  |  Height:  |  Size: 10 KiB

Before After
Before After

View file

Before

Width:  |  Height:  |  Size: 46 KiB

After

Width:  |  Height:  |  Size: 46 KiB

Before After
Before After

View file

Before

Width:  |  Height:  |  Size: 26 KiB

After

Width:  |  Height:  |  Size: 26 KiB

Before After
Before After

View file

Before

Width:  |  Height:  |  Size: 3.3 KiB

After

Width:  |  Height:  |  Size: 3.3 KiB

Before After
Before After

View file

Before

Width:  |  Height:  |  Size: 14 KiB

After

Width:  |  Height:  |  Size: 14 KiB

Before After
Before After

View file

Before

Width:  |  Height:  |  Size: 16 KiB

After

Width:  |  Height:  |  Size: 16 KiB

Before After
Before After

View file

Before

Width:  |  Height:  |  Size: 84 KiB

After

Width:  |  Height:  |  Size: 84 KiB

Before After
Before After

View file

Before

Width:  |  Height:  |  Size: 45 KiB

After

Width:  |  Height:  |  Size: 45 KiB

Before After
Before After

View file

Before

Width:  |  Height:  |  Size: 4.6 KiB

After

Width:  |  Height:  |  Size: 4.6 KiB

Before After
Before After

View file

Before

Width:  |  Height:  |  Size: 22 KiB

After

Width:  |  Height:  |  Size: 22 KiB

Before After
Before After

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2022 New Vector Ltd
* 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.
@ -13,11 +13,14 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
plugins {
id("io.element.android-compose-library")
}
package ui
android {
namespace = "io.element.android.appicon.enterprise"
import com.airbnb.android.showkase.annotation.ShowkaseRoot
import com.airbnb.android.showkase.annotation.ShowkaseRootModule
@ShowkaseRoot
class ElementXShowkaseRootModule : ShowkaseRootModule
buildTypes {
register("nightly")
}
}

View file

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

View file

@ -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,
)
}
}

View file

@ -1,5 +1,6 @@
<?xml version="1.0" encoding="utf-8"?><!--
~ Copyright (c) 2023 New Vector Ltd
<?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.
@ -14,8 +15,7 @@
~ limitations under the License.
-->
<resources>
<color name="notification_accent_color">#368BD6</color>
</resources>
<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>

View file

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 46 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 84 KiB

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

1
changelog.d/2869.feature Normal file
View file

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

1
changelog.d/2916.misc Normal file
View file

@ -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 Normal file
View file

@ -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 Normal file
View file

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

1
changelog.d/3068.misc Normal file
View file

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

1
changelog.d/3073.bugfix Normal file
View file

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

1
changelog.d/3081.bugfix Normal file
View file

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

1
changelog.d/3082.bugfix Normal file
View file

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

1
changelog.d/3083.bugfix Normal file
View file

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

1
changelog.d/3085.bugfix Normal file
View file

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

1
changelog.d/3086.bugfix Normal file
View file

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

View file

@ -22,7 +22,7 @@ Here are the checks that Danger does so far:
- PR description is not empty
- 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 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!)

View file

@ -42,11 +42,7 @@ Then you can run the following commands (which are also used in the file for [th
```sh
git checkout develop
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
./gradlew assembleGplayNightly appDistributionUploadGplayNightly $CI_GRADLE_ARG_PROPERTIES
./gradlew assembleGplayNightly appDistributionUploadGplayNightly
```
Then you can reset the change on the codebase.

View file

@ -13,7 +13,7 @@
## Overview
- 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.
## Setup

1
enterprise Submodule

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

View file

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

View file

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

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_help_us_improve">"Μοιράσου ανώνυμα δεδομένα χρήσης για να μάς βοηθήσεις να εντοπίσουμε προβλήματα."</string>
<string name="screen_analytics_settings_read_terms">"Μπορείς να διαβάσεις όλους τους όρους μας %1$s."</string>
<string name="screen_analytics_settings_read_terms_content_link">"εδώ"</string>
<string name="screen_analytics_settings_share_data">"Κοινή χρήση δεδομένων αναλυτικών στοιχείων"</string>
</resources>

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