Merge branch 'develop' into feature/fga/authenticated_media

This commit is contained in:
ganfra 2024-07-18 15:56:48 +02:00
commit 9e27705b6e
717 changed files with 4888 additions and 4305 deletions

View file

@ -24,12 +24,17 @@ jobs:
group: ${{ github.ref == 'refs/heads/develop' && format('integration-tests-develop-{0}-{1}', matrix.target, github.sha) || format('build-debug-{0}-{1}', matrix.target, github.ref) }} group: ${{ github.ref == 'refs/heads/develop' && format('integration-tests-develop-{0}-{1}', matrix.target, github.sha) || format('build-debug-{0}-{1}', matrix.target, github.ref) }}
cancel-in-progress: true cancel-in-progress: true
steps: steps:
- uses: actions/checkout@v3 - uses: actions/checkout@v4
with: with:
# 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.sha }} ref: ${{ github.event_name == 'pull_request' && github.event.pull_request.head.sha || github.sha }}
- name: Use JDK 17
uses: actions/setup-java@v4
with:
distribution: 'temurin' # See 'Supported distributions' for available options
java-version: '17'
- name: Configure gradle - name: Configure gradle
uses: gradle/gradle-build-action@v2 uses: gradle/actions/setup-gradle@v3
with: with:
cache-read-only: ${{ github.ref != 'refs/heads/develop' }} cache-read-only: ${{ github.ref != 'refs/heads/develop' }}
- name: Assemble ${{ matrix.target }} debug apk - name: Assemble ${{ matrix.target }} debug apk
@ -48,12 +53,17 @@ jobs:
group: ${{ github.ref == 'refs/head/main' && format('build-release-apk-main-{0}', github.sha) || github.ref == 'refs/heads/develop' && format('build-release-apk-develop-{0}', github.sha) || format('build-debug-{0}', github.ref) }} group: ${{ github.ref == 'refs/head/main' && format('build-release-apk-main-{0}', github.sha) || github.ref == 'refs/heads/develop' && format('build-release-apk-develop-{0}', github.sha) || format('build-debug-{0}', github.ref) }}
cancel-in-progress: ${{ github.ref != 'refs/head/main' }} cancel-in-progress: ${{ github.ref != 'refs/head/main' }}
steps: steps:
- uses: actions/checkout@v3 - uses: actions/checkout@v4
with: with:
# https://github.com/actions/checkout/issues/881 # https://github.com/actions/checkout/issues/881
ref: ${{ github.event_name == 'pull_request' && github.event.pull_request.head.sha || github.ref }} ref: ${{ github.event_name == 'pull_request' && github.event.pull_request.head.sha || github.ref }}
- name: Use JDK 17
uses: actions/setup-java@v4
with:
distribution: 'temurin' # See 'Supported distributions' for available options
java-version: '17'
- name: Configure gradle - name: Configure gradle
uses: gradle/gradle-build-action@v2 uses: gradle/actions/setup-gradle@v3
with: with:
cache-read-only: ${{ github.ref != 'refs/heads/develop' }} cache-read-only: ${{ github.ref != 'refs/heads/develop' }}
- name: Assemble GPlay unsigned apk - name: Assemble GPlay unsigned apk

View file

@ -7,7 +7,7 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
name: Danger name: Danger
steps: steps:
- uses: actions/checkout@v3 - uses: actions/checkout@v4
- 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

View file

@ -10,7 +10,7 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: Checkout repository - name: Checkout repository
uses: actions/checkout@v3 uses: actions/checkout@v4
- name: Build docs - name: Build docs
run: ./gradlew dokkaHtml run: ./gradlew dokkaHtml

View file

@ -10,5 +10,5 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
# No concurrency required, this is a prerequisite to other actions and should run every time. # No concurrency required, this is a prerequisite to other actions and should run every time.
steps: steps:
- uses: actions/checkout@v3 - uses: actions/checkout@v4
- uses: gradle/wrapper-validation-action@v1 - uses: gradle/wrapper-validation-action@v1

View file

@ -7,7 +7,7 @@ on:
- cron: "0 4 * * *" - cron: "0 4 * * *"
env: env:
GRADLE_OPTS: -Dorg.gradle.jvmargs="-Xmx3072m -Dfile.encoding=UTF-8 -XX:+HeapDumpOnOutOfMemoryError -XX:MaxMetaspaceSize=1g" -Dkotlin.daemon.jvm.options="-Xmx2560m" -Dkotlin.incremental=false GRADLE_OPTS: -Dorg.gradle.jvmargs="-Xmx6g -Dfile.encoding=UTF-8 -XX:+HeapDumpOnOutOfMemoryError -XX:MaxMetaspaceSize=1g" -Dkotlin.incremental=false -XX:+UseG1GC
CI_GRADLE_ARG_PROPERTIES: --stacktrace -PpreDexEnable=false --max-workers 2 --no-daemon CI_GRADLE_ARG_PROPERTIES: --stacktrace -PpreDexEnable=false --max-workers 2 --no-daemon
jobs: jobs:
@ -15,13 +15,18 @@ jobs:
name: Build and publish nightly Gplay APK to Firebase name: Build and publish nightly Gplay APK to Firebase
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v3 - uses: actions/checkout@v4
- name: Set up Python 3.8 - name: Set up Python 3.8
uses: actions/setup-python@v4 uses: actions/setup-python@v4
with: with:
python-version: 3.8 python-version: 3.8
- name: Use JDK 17
uses: actions/setup-java@v4
with:
distribution: 'temurin' # See 'Supported distributions' for available options
java-version: '17'
- name: Configure gradle - name: Configure gradle
uses: gradle/gradle-build-action@v2 uses: gradle/actions/setup-gradle@v3
with: with:
cache-read-only: ${{ github.ref != 'refs/heads/develop' }} cache-read-only: ${{ github.ref != 'refs/heads/develop' }}
- name: Install towncrier - name: Install towncrier

View file

@ -39,17 +39,18 @@ jobs:
api-level: [ 28 ] api-level: [ 28 ]
# No concurrency required, runs every time on a schedule. # No concurrency required, runs every time on a schedule.
steps: steps:
- uses: actions/checkout@v3 - uses: actions/checkout@v4
- name: Set up Python 3.8 - name: Set up Python 3.8
uses: actions/setup-python@v4 uses: actions/setup-python@v4
with: with:
python-version: 3.8 python-version: 3.8
- uses: actions/setup-java@v3 - name: Use JDK 17
uses: actions/setup-java@v4
with: with:
distribution: 'adopt' distribution: 'temurin' # See 'Supported distributions' for available options
java-version: '11' java-version: '17'
- name: Configure gradle - name: Configure gradle
uses: gradle/gradle-build-action@v2 uses: gradle/actions/setup-gradle@v3
with: with:
cache-read-only: ${{ github.ref != 'refs/heads/develop' }} cache-read-only: ${{ github.ref != 'refs/heads/develop' }}
- name: Start synapse server - name: Start synapse server

View file

@ -7,7 +7,7 @@ on:
# Enrich gradle.properties for CI/CD # Enrich gradle.properties for CI/CD
env: env:
GRADLE_OPTS: -Dorg.gradle.jvmargs="-Xmx3072m -Dfile.encoding=UTF-8 -XX:+HeapDumpOnOutOfMemoryError" -XX:MaxPermSize=512m -Dkotlin.daemon.jvm.options="-Xmx2g" -Dkotlin.incremental=false GRADLE_OPTS: -Dorg.gradle.jvmargs="-Xmx3072m -Dfile.encoding=UTF-8 -XX:+HeapDumpOnOutOfMemoryError -XX:MaxMetaspaceSize=1g" -Dkotlin.daemon.jvm.options="-Xmx2560m" -Dkotlin.incremental=false
CI_GRADLE_ARG_PROPERTIES: --stacktrace -PpreDexEnable=false --max-workers 2 --no-daemon CI_GRADLE_ARG_PROPERTIES: --stacktrace -PpreDexEnable=false --max-workers 2 --no-daemon
jobs: jobs:
@ -15,7 +15,7 @@ jobs:
name: Project Check Suite name: Project Check Suite
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v3 - uses: actions/checkout@v4
- 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
@ -24,7 +24,16 @@ jobs:
name: Knit name: Knit
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v3 - uses: actions/checkout@v4
- 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: Run knit - name: Run knit
run: | run: |
./gradlew knitCheck $CI_GRADLE_ARG_PROPERTIES ./gradlew knitCheck $CI_GRADLE_ARG_PROPERTIES
@ -38,7 +47,16 @@ jobs:
group: ${{ github.ref == 'refs/heads/main' && format('lint-main-{0}', github.sha) || github.ref == 'refs/heads/develop' && format('lint-develop-{0}', github.sha) || format('lint-{0}', github.ref) }} group: ${{ github.ref == 'refs/heads/main' && format('lint-main-{0}', github.sha) || github.ref == 'refs/heads/develop' && format('lint-develop-{0}', github.sha) || format('lint-{0}', github.ref) }}
cancel-in-progress: true cancel-in-progress: true
steps: steps:
- uses: actions/checkout@v3 - uses: actions/checkout@v4
- 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: Run ktlint - name: Run ktlint
run: | run: |
./gradlew ktlintCheck $CI_GRADLE_ARG_PROPERTIES --continue ./gradlew ktlintCheck $CI_GRADLE_ARG_PROPERTIES --continue
@ -83,7 +101,16 @@ jobs:
group: ${{ github.ref == 'refs/heads/main' && format('dep-main-{0}', github.sha) || github.ref == 'refs/heads/develop' && format('dep-develop-{0}', github.sha) || format('dep-{0}', github.ref) }} group: ${{ github.ref == 'refs/heads/main' && format('dep-main-{0}', github.sha) || github.ref == 'refs/heads/develop' && format('dep-develop-{0}', github.sha) || format('dep-{0}', github.ref) }}
cancel-in-progress: true cancel-in-progress: true
steps: steps:
- uses: actions/checkout@v3 - uses: actions/checkout@v4
- 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: Dependency analysis - name: Dependency analysis
run: ./gradlew dependencyCheckAnalyze $CI_GRADLE_ARG_PROPERTIES run: ./gradlew dependencyCheckAnalyze $CI_GRADLE_ARG_PROPERTIES
- name: Upload dependency analysis - name: Upload dependency analysis

View file

@ -12,7 +12,7 @@ jobs:
if: github.repository == 'element-hq/element-android' if: github.repository == 'element-hq/element-android'
# No concurrency required, runs every time on a schedule. # No concurrency required, runs every time on a schedule.
steps: steps:
- uses: actions/checkout@v3 - uses: actions/checkout@v4
- name: Set up Python 3.8 - name: Set up Python 3.8
uses: actions/setup-python@v4 uses: actions/setup-python@v4
with: with:
@ -39,7 +39,7 @@ jobs:
if: github.repository == 'element-hq/element-android' if: github.repository == 'element-hq/element-android'
# No concurrency required, runs every time on a schedule. # No concurrency required, runs every time on a schedule.
steps: steps:
- uses: actions/checkout@v3 - uses: actions/checkout@v4
- name: Set up Python 3.8 - name: Set up Python 3.8
uses: actions/setup-python@v4 uses: actions/setup-python@v4
with: with:

View file

@ -25,15 +25,17 @@ jobs:
group: ${{ github.ref == 'refs/heads/main' && format('unit-tests-main-{0}', github.sha) || github.ref == 'refs/heads/develop' && format('unit-tests-develop-{0}', github.sha) || format('unit-tests-{0}', github.ref) }} group: ${{ github.ref == 'refs/heads/main' && format('unit-tests-main-{0}', github.sha) || github.ref == 'refs/heads/develop' && format('unit-tests-develop-{0}', github.sha) || format('unit-tests-{0}', github.ref) }}
cancel-in-progress: true cancel-in-progress: true
steps: steps:
- uses: actions/checkout@v3 - uses: actions/checkout@v4
with: with:
lfs: true lfs: true
fetch-depth: 0 fetch-depth: 0
- uses: actions/setup-java@v3 - name: Use JDK 17
uses: actions/setup-java@v4
with: with:
distribution: 'adopt' distribution: 'temurin' # See 'Supported distributions' for available options
java-version: '17' java-version: '17'
- uses: gradle/gradle-build-action@v2 - name: Configure gradle
uses: gradle/actions/setup-gradle@v3
with: with:
cache-read-only: ${{ github.ref != 'refs/heads/develop' }} cache-read-only: ${{ github.ref != 'refs/heads/develop' }}
gradle-home-cache-cleanup: ${{ github.ref == 'refs/heads/develop' }} gradle-home-cache-cleanup: ${{ github.ref == 'refs/heads/develop' }}
@ -136,13 +138,14 @@ jobs:
# group: ${{ github.ref == 'refs/heads/main' && format('unit-tests-main-{0}', github.sha) || github.ref == 'refs/heads/develop' && format('unit-tests-develop-{0}', github.sha) || format('build-android-tests-{0}', github.ref) }} # group: ${{ github.ref == 'refs/heads/main' && format('unit-tests-main-{0}', github.sha) || github.ref == 'refs/heads/develop' && format('unit-tests-develop-{0}', github.sha) || format('build-android-tests-{0}', github.ref) }}
# cancel-in-progress: true # cancel-in-progress: true
# steps: # steps:
# - uses: actions/checkout@v3 # - uses: actions/checkout@v4
# - uses: actions/setup-java@v3 # - name: Use JDK 17
# uses: actions/setup-java@v4
# with: # with:
# distribution: 'adopt' # distribution: 'temurin' # See 'Supported distributions' for available options
# java-version: 11 # java-version: '17'
# - name: Configure gradle # - name: Configure gradle
# uses: gradle/gradle-build-action@v2 # uses: gradle/actions/setup-gradle@v3
# with: # with:
# cache-read-only: ${{ github.ref != 'refs/heads/develop' }} # cache-read-only: ${{ github.ref != 'refs/heads/develop' }}
# - name: Build Android Tests # - name: Build Android Tests

View file

@ -9,7 +9,7 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v3 - uses: actions/checkout@v4
- name: Update Gradle Wrapper - name: Update Gradle Wrapper
uses: gradle-update/update-gradle-wrapper-action@v1 uses: gradle-update/update-gradle-wrapper-action@v1

View file

@ -7,7 +7,7 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
name: Validate name: Validate
steps: steps:
- uses: actions/checkout@v3 - uses: actions/checkout@v4
with: with:
lfs: 'true' lfs: 'true'

View file

@ -28,7 +28,7 @@ buildscript {
classpath 'com.google.gms:google-services:4.3.15' classpath 'com.google.gms:google-services:4.3.15'
classpath 'org.sonarsource.scanner.gradle:sonarqube-gradle-plugin:4.0.0.2929' classpath 'org.sonarsource.scanner.gradle:sonarqube-gradle-plugin:4.0.0.2929'
classpath 'com.google.android.gms:oss-licenses-plugin:0.10.6' classpath 'com.google.android.gms:oss-licenses-plugin:0.10.6'
classpath "com.likethesalad.android:stem-plugin:2.4.1" classpath "com.likethesalad.android:stem-plugin:2.9.0"
classpath 'org.owasp:dependency-check-gradle:8.2.1' classpath 'org.owasp:dependency-check-gradle:8.2.1'
classpath "org.jetbrains.dokka:dokka-gradle-plugin:1.8.10" classpath "org.jetbrains.dokka:dokka-gradle-plugin:1.8.10"
classpath "org.jetbrains.kotlinx:kotlinx-knit:0.4.0" classpath "org.jetbrains.kotlinx:kotlinx-knit:0.4.0"
@ -45,7 +45,7 @@ plugins {
// Detekt // Detekt
id "io.gitlab.arturbosch.detekt" version "1.22.0" id "io.gitlab.arturbosch.detekt" version "1.22.0"
// Ksp // Ksp
id "com.google.devtools.ksp" version "1.8.10-1.0.9" id "com.google.devtools.ksp" version "1.9.24-1.0.20"
// Dependency Analysis // Dependency Analysis
id 'com.autonomousapps.dependency-analysis' version "1.20.0" id 'com.autonomousapps.dependency-analysis' version "1.20.0"

View file

@ -33,9 +33,9 @@ def initializeReport(report, projects, classExcludes) {
) )
} }
report.reports { report.reports {
xml.enabled true xml.required = true
html.enabled true html.required = true
csv.enabled false csv.required = false
} }
gradle.projectsEvaluated { gradle.projectsEvaluated {

View file

@ -1,39 +1,39 @@
ext.versions = [ ext.versions = [
'minSdk' : 21, 'minSdk' : 21,
'compileSdk' : 33, 'compileSdk' : 34,
'targetSdk' : 33, 'targetSdk' : 34,
'sourceCompat' : JavaVersion.VERSION_11, 'sourceCompat' : JavaVersion.VERSION_17,
'targetCompat' : JavaVersion.VERSION_11, 'targetCompat' : JavaVersion.VERSION_17,
'jvmTarget' : "17",
] ]
def gradle = "7.4.2" def gradle = "8.4.2"
// Ref: https://kotlinlang.org/releases.html // Ref: https://kotlinlang.org/releases.html
def kotlin = "1.8.10" def kotlin = "1.9.24"
def kotlinCoroutines = "1.6.4" def kotlinCoroutines = "1.8.1"
def dagger = "2.45" def dagger = "2.51.1"
def firebaseBom = "32.0.0" def firebaseBom = "33.1.1"
def appDistribution = "16.0.0-beta08" def appDistribution = "16.0.0-beta08"
def retrofit = "2.9.0" def retrofit = "2.11.0"
def markwon = "4.6.2" def markwon = "4.6.2"
def moshi = "1.14.0" def moshi = "1.15.1"
def lifecycle = "2.5.1" def lifecycle = "2.8.3"
def flowBinding = "1.2.0" def flowBinding = "1.2.0"
def flipper = "0.190.0" def flipper = "0.190.0"
def epoxy = "5.0.0" def epoxy = "5.0.0"
def mavericks = "3.0.7" def mavericks = "3.0.9"
def glide = "4.15.1" def glide = "4.16.0"
def bigImageViewer = "1.8.1" def bigImageViewer = "1.8.1"
def jjwt = "0.11.5" def jjwt = "0.11.5"
def vanniktechEmoji = "0.16.0" def vanniktechEmoji = "0.16.0"
def sentry = "6.18.1" def sentry = "6.18.1"
// Use 1.6.0 alpha to fix issue with test def fragment = "1.8.1"
def fragment = "1.6.0-beta01"
// Testing // Testing
def mockk = "1.12.3" // We need to use 1.12.3 to have mocking in androidTest until a new version is released: https://github.com/mockk/mockk/issues/819 def mockk = "1.13.11"
def espresso = "3.5.1" def espresso = "3.6.1"
def androidxTest = "1.5.0" def androidxTest = "1.6.1"
def androidxOrchestrator = "1.4.2" def androidxOrchestrator = "1.5.0"
def paparazzi = "1.2.0" def paparazzi = "1.3.4"
ext.libs = [ ext.libs = [
gradle : [ gradle : [
@ -47,8 +47,8 @@ ext.libs = [
'coroutinesTest' : "org.jetbrains.kotlinx:kotlinx-coroutines-test:$kotlinCoroutines" 'coroutinesTest' : "org.jetbrains.kotlinx:kotlinx-coroutines-test:$kotlinCoroutines"
], ],
androidx : [ androidx : [
'activity' : "androidx.activity:activity-ktx:1.7.2", 'activity' : "androidx.activity:activity-ktx:1.9.0",
'appCompat' : "androidx.appcompat:appcompat:1.6.1", 'appCompat' : "androidx.appcompat:appcompat:1.7.0",
'biometric' : "androidx.biometric:biometric:1.1.0", 'biometric' : "androidx.biometric:biometric:1.1.0",
'core' : "androidx.core:core-ktx:1.10.1", 'core' : "androidx.core:core-ktx:1.10.1",
'recyclerview' : "androidx.recyclerview:recyclerview:1.3.0", 'recyclerview' : "androidx.recyclerview:recyclerview:1.3.0",
@ -76,11 +76,11 @@ ext.libs = [
'espressoCore' : "androidx.test.espresso:espresso-core:$espresso", 'espressoCore' : "androidx.test.espresso:espresso-core:$espresso",
'espressoContrib' : "androidx.test.espresso:espresso-contrib:$espresso", 'espressoContrib' : "androidx.test.espresso:espresso-contrib:$espresso",
'espressoIntents' : "androidx.test.espresso:espresso-intents:$espresso", 'espressoIntents' : "androidx.test.espresso:espresso-intents:$espresso",
'viewpager2' : "androidx.viewpager2:viewpager2:1.0.0", 'viewpager2' : "androidx.viewpager2:viewpager2:1.1.0",
'transition' : "androidx.transition:transition:1.4.1", 'transition' : "androidx.transition:transition:1.5.0",
], ],
google : [ google : [
'material' : "com.google.android.material:material:1.9.0", 'material' : "com.google.android.material:material:1.12.0",
'firebaseBom' : "com.google.firebase:firebase-bom:$firebaseBom", 'firebaseBom' : "com.google.firebase:firebase-bom:$firebaseBom",
'messaging' : "com.google.firebase:firebase-messaging", 'messaging' : "com.google.firebase:firebase-messaging",
'appdistributionApi' : "com.google.firebase:firebase-appdistribution-api-ktx:$appDistribution", 'appdistributionApi' : "com.google.firebase:firebase-appdistribution-api-ktx:$appDistribution",
@ -172,7 +172,7 @@ ext.libs = [
'kluent' : "org.amshove.kluent:kluent-android:1.73", 'kluent' : "org.amshove.kluent:kluent-android:1.73",
'timberJunitRule' : "net.lachlanmckee:timber-junit-rule:1.0.1", 'timberJunitRule' : "net.lachlanmckee:timber-junit-rule:1.0.1",
'junit' : "junit:junit:4.13.2", 'junit' : "junit:junit:4.13.2",
'robolectric' : "org.robolectric:robolectric:4.9", 'robolectric' : "org.robolectric:robolectric:4.13",
] ]
] ]

View file

@ -96,6 +96,7 @@ ext.groups = [
'com.google.auto.value', 'com.google.auto.value',
'com.google.code.findbugs', 'com.google.code.findbugs',
'com.google.code.gson', 'com.google.code.gson',
'com.google.crypto.tink',
'com.google.dagger', 'com.google.dagger',
'com.google.devtools.ksp', 'com.google.devtools.ksp',
'com.google.errorprone', 'com.google.errorprone',
@ -141,6 +142,7 @@ ext.groups = [
'commons-codec', 'commons-codec',
'commons-io', 'commons-io',
'commons-logging', 'commons-logging',
'dev.drewhamilton.poko',
'info.picocli', 'info.picocli',
'io.element.android', 'io.element.android',
'io.github.davidburstrom.contester', 'io.github.davidburstrom.contester',

View file

@ -62,7 +62,7 @@ class PaparazziExampleScreenshotTest {
val view = paparazzi.inflate<ConstraintLayout>(R.layout.item_radio) val view = paparazzi.inflate<ConstraintLayout>(R.layout.item_radio)
// Bind data to the view // Bind data to the view
view.findViewById<TextView>(R.id.actionTitle).text = paparazzi.resources.getString(R.string.room_settings_all_messages) view.findViewById<TextView>(R.id.actionTitle).text = paparazzi.resources.getString(CommonStrings.room_settings_all_messages)
view.findViewById<ImageView>(R.id.radioIcon).setImageResource(R.drawable.ic_radio_on) view.findViewById<ImageView>(R.id.radioIcon).setImageResource(R.drawable.ic_radio_on)
// Record the bound view // Record the bound view

View file

@ -179,7 +179,7 @@ class SettingsRobot {
} }
fun advancedSettings(block: SettingsAdvancedRobot.() -> Unit) { fun advancedSettings(block: SettingsAdvancedRobot.() -> Unit) {
clickOn(R.string.settings_advanced_settings) clickOn(CommonStrings.settings_advanced_settings)
block(SettingsAdvancedRobot()) block(SettingsAdvancedRobot())
pressBack() pressBack()
} }
@ -187,7 +187,7 @@ class SettingsRobot {
class SettingsAdvancedRobot { class SettingsAdvancedRobot {
fun toggleDeveloperMode() { fun toggleDeveloperMode() {
clickOn(R.string.settings_developer_mode_summary) clickOn(CommonStrings.settings_developer_mode_summary)
} }
} }
``` ```

View file

@ -42,4 +42,4 @@ signing.element.nightly.keyPassword=Secret
# Customise the Lint version to use a more recent version than the one bundled with AGP # Customise the Lint version to use a more recent version than the one bundled with AGP
# https://googlesamples.github.io/android-custom-lint-rules/usage/newer-lint.md.html # https://googlesamples.github.io/android-custom-lint-rules/usage/newer-lint.md.html
android.experimental.lint.version=8.3.0-alpha12 android.experimental.lint.version=8.6.0-alpha08

Binary file not shown.

View file

@ -1,7 +1,8 @@
distributionBase=GRADLE_USER_HOME distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists distributionPath=wrapper/dists
distributionSha256Sum=312eb12875e1747e05c2f81a4789902d7e4ec5defbd1eefeaccc08acf096505d distributionSha256Sum=f8b4f4772d302c8ff580bc40d0f56e715de69b163546944f787c87abf209c961
distributionUrl=https\://services.gradle.org/distributions/gradle-7.6-all.zip distributionUrl=https\://services.gradle.org/distributions/gradle-8.8-all.zip
networkTimeout=10000 networkTimeout=10000
validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists zipStorePath=wrapper/dists

View file

@ -38,7 +38,7 @@ android {
targetCompatibility versions.targetCompat targetCompatibility versions.targetCompat
} }
kotlinOptions { kotlinOptions {
jvmTarget = "11" jvmTarget = versions.jvmTarget
} }
buildFeatures { buildFeatures {

View file

@ -31,7 +31,6 @@ import android.view.WindowManager
import android.widget.ImageView import android.widget.ImageView
import androidx.appcompat.app.AppCompatActivity import androidx.appcompat.app.AppCompatActivity
import androidx.core.content.ContextCompat import androidx.core.content.ContextCompat
import androidx.core.view.GestureDetectorCompat
import androidx.core.view.ViewCompat import androidx.core.view.ViewCompat
import androidx.core.view.WindowInsetsCompat import androidx.core.view.WindowInsetsCompat
import androidx.core.view.isVisible import androidx.core.view.isVisible
@ -39,6 +38,7 @@ import androidx.core.view.updatePadding
import androidx.transition.TransitionManager import androidx.transition.TransitionManager
import androidx.viewpager2.widget.ViewPager2 import androidx.viewpager2.widget.ViewPager2
import im.vector.lib.attachmentviewer.databinding.ActivityAttachmentViewerBinding import im.vector.lib.attachmentviewer.databinding.ActivityAttachmentViewerBinding
import im.vector.lib.ui.styles.R
import java.lang.ref.WeakReference import java.lang.ref.WeakReference
import kotlin.math.abs import kotlin.math.abs
@ -71,7 +71,7 @@ abstract class AttachmentViewerActivity : AppCompatActivity(), AttachmentEventLi
private lateinit var swipeDismissHandler: SwipeToDismissHandler private lateinit var swipeDismissHandler: SwipeToDismissHandler
private lateinit var directionDetector: SwipeDirectionDetector private lateinit var directionDetector: SwipeDirectionDetector
private lateinit var scaleDetector: ScaleGestureDetector private lateinit var scaleDetector: ScaleGestureDetector
private lateinit var gestureDetector: GestureDetectorCompat private lateinit var gestureDetector: GestureDetector
var currentPosition = 0 var currentPosition = 0
private set private set
@ -309,7 +309,7 @@ abstract class AttachmentViewerActivity : AppCompatActivity(), AttachmentEventLi
ScaleGestureDetector(this, ScaleGestureDetector.SimpleOnScaleGestureListener()) ScaleGestureDetector(this, ScaleGestureDetector.SimpleOnScaleGestureListener())
private fun createGestureDetector() = private fun createGestureDetector() =
GestureDetectorCompat(this, object : GestureDetector.SimpleOnGestureListener() { GestureDetector(this, object : GestureDetector.SimpleOnGestureListener() {
override fun onSingleTapConfirmed(e: MotionEvent): Boolean { override fun onSingleTapConfirmed(e: MotionEvent): Boolean {
if (isImagePagerIdle) { if (isImagePagerIdle) {
handleSingleTap(e, isOverlayWasClicked) handleSingleTap(e, isOverlayWasClicked)

View file

@ -28,7 +28,6 @@ android {
targetSdk versions.targetSdk targetSdk versions.targetSdk
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
consumerProguardFiles "consumer-rules.pro"
} }
buildTypes { buildTypes {
@ -44,7 +43,7 @@ android {
} }
kotlinOptions { kotlinOptions {
jvmTarget = "11" jvmTarget = versions.jvmTarget
freeCompilerArgs += [ freeCompilerArgs += [
"-opt-in=kotlin.RequiresOptIn" "-opt-in=kotlin.RequiresOptIn"
] ]

View file

@ -17,7 +17,7 @@ android {
} }
kotlinOptions { kotlinOptions {
jvmTarget = "11" jvmTarget = versions.jvmTarget
} }
} }

View file

@ -13,7 +13,6 @@ import android.text.TextWatcher;
import android.util.Log; import android.util.Log;
import android.util.TypedValue; import android.util.TypedValue;
import android.view.Gravity; import android.view.Gravity;
import android.view.Window;
import android.view.WindowManager; import android.view.WindowManager;
import android.widget.EditText; import android.widget.EditText;
import android.widget.PopupWindow; import android.widget.PopupWindow;

View file

@ -17,7 +17,7 @@ android {
} }
kotlinOptions { kotlinOptions {
jvmTarget = "11" jvmTarget = versions.jvmTarget
} }
} }

View file

@ -20,7 +20,6 @@ import android.animation.AnimatorListenerAdapter;
import android.content.Context; import android.content.Context;
import android.content.res.Configuration; import android.content.res.Configuration;
import android.content.res.Resources; import android.content.res.Resources;
import android.graphics.drawable.Drawable;
import android.os.Build; import android.os.Build;
import android.text.Spannable; import android.text.Spannable;
import android.text.TextUtils; import android.text.TextUtils;

View file

@ -20,6 +20,7 @@ import android.content.Context;
import android.content.res.TypedArray; import android.content.res.TypedArray;
import android.util.AttributeSet; import android.util.AttributeSet;
import android.widget.EditText; import android.widget.EditText;
import com.android.dialer.dialpadview.R; import com.android.dialer.dialpadview.R;
import com.android.dialer.util.ViewUtil; import com.android.dialer.util.ViewUtil;

View file

@ -42,7 +42,7 @@ android {
} }
kotlinOptions { kotlinOptions {
jvmTarget = "11" jvmTarget = versions.jvmTarget
} }
} }

View file

@ -10,11 +10,11 @@ dependencies {
task javadocJar(type: Jar, dependsOn: 'javadoc') { task javadocJar(type: Jar, dependsOn: 'javadoc') {
from javadoc.destinationDir from javadoc.destinationDir
classifier = 'javadoc' archiveClassifier = 'javadoc'
} }
task sourcesJar(type: Jar, dependsOn: 'classes') { task sourcesJar(type: Jar, dependsOn: 'classes') {
from sourceSets.main.allSource from sourceSets.main.allSource
classifier = 'sources' archiveClassifier = 'sources'
} }
sourceSets { sourceSets {

View file

@ -13,6 +13,15 @@ android {
sourceSets { sourceSets {
main.java.srcDirs += 'src/main/kotlin' main.java.srcDirs += 'src/main/kotlin'
} }
compileOptions {
sourceCompatibility versions.sourceCompat
targetCompatibility versions.targetCompat
}
kotlinOptions {
jvmTarget = versions.jvmTarget
}
} }
dependencies { dependencies {

View file

@ -1,6 +1,13 @@
package com.amulyakhare.textdrawable; package com.amulyakhare.textdrawable;
import android.graphics.*; import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.ColorFilter;
import android.graphics.Paint;
import android.graphics.PixelFormat;
import android.graphics.Rect;
import android.graphics.RectF;
import android.graphics.Typeface;
import android.graphics.drawable.ShapeDrawable; import android.graphics.drawable.ShapeDrawable;
import android.graphics.drawable.shapes.OvalShape; import android.graphics.drawable.shapes.OvalShape;
import android.graphics.drawable.shapes.RectShape; import android.graphics.drawable.shapes.RectShape;

View file

@ -43,7 +43,7 @@ android {
} }
kotlinOptions { kotlinOptions {
jvmTarget = "11" jvmTarget = versions.jvmTarget
} }
} }

View file

@ -19,7 +19,7 @@ android {
} }
kotlinOptions { kotlinOptions {
jvmTarget = "11" jvmTarget = versions.jvmTarget
} }
} }

View file

@ -0,0 +1,20 @@
/*
* 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.
*/
package im.vector.lib.strings
typealias CommonStrings = R.string
typealias CommonPlurals = R.plurals

View file

@ -29,7 +29,6 @@ android {
targetSdk versions.targetSdk targetSdk versions.targetSdk
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
consumerProguardFiles "consumer-rules.pro"
} }
buildTypes { buildTypes {
@ -45,7 +44,7 @@ android {
} }
kotlinOptions { kotlinOptions {
jvmTarget = "11" jvmTarget = versions.jvmTarget
} }
buildFeatures { buildFeatures {

View file

@ -28,7 +28,7 @@ android {
targetCompatibility versions.targetCompat targetCompatibility versions.targetCompat
} }
kotlinOptions { kotlinOptions {
jvmTarget = "11" jvmTarget = versions.jvmTarget
} }
// publishNonDefault true // publishNonDefault true

View file

@ -1,2 +1,2 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" /> <manifest />

View file

@ -81,7 +81,7 @@ android {
buildTypes { buildTypes {
debug { debug {
if (project.hasProperty("coverage")) { if (project.hasProperty("coverage")) {
testCoverageEnabled = coverage == "true" testCoverageEnabled = project.properties["coverage"] == "true"
} }
// Set to true to log privacy or sensible data, such as token // Set to true to log privacy or sensible data, such as token
buildConfigField "boolean", "LOG_PRIVATE_DATA", project.property("vector.debugPrivateData") buildConfigField "boolean", "LOG_PRIVATE_DATA", project.property("vector.debugPrivateData")
@ -106,7 +106,7 @@ android {
} }
kotlinOptions { kotlinOptions {
jvmTarget = "11" jvmTarget = versions.jvmTarget
freeCompilerArgs += [ freeCompilerArgs += [
// Disabled for now, there are too many errors. Could be handled in another dedicated PR // Disabled for now, there are too many errors. Could be handled in another dedicated PR
// '-Xexplicit-api=strict', // or warning // '-Xexplicit-api=strict', // or warning
@ -125,6 +125,15 @@ android {
} }
} }
buildFeatures {
buildConfig true
}
packaging {
pickFirsts.add("META-INF/LICENSE.md")
pickFirsts.add("META-INF/LICENSE-notice.md")
pickFirsts.add("MANIFEST.MF")
}
} }
static def gitRevision() { static def gitRevision() {

View file

@ -23,7 +23,6 @@ import androidx.test.internal.runner.junit4.statement.UiThreadStatement
import kotlinx.coroutines.CompletableDeferred import kotlinx.coroutines.CompletableDeferred
import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.Job import kotlinx.coroutines.Job
import kotlinx.coroutines.cancel import kotlinx.coroutines.cancel
import kotlinx.coroutines.delay import kotlinx.coroutines.delay
@ -58,6 +57,7 @@ import java.util.concurrent.CountDownLatch
import java.util.concurrent.TimeUnit import java.util.concurrent.TimeUnit
import kotlin.coroutines.resume import kotlin.coroutines.resume
import kotlin.coroutines.suspendCoroutine import kotlin.coroutines.suspendCoroutine
import kotlin.time.Duration.Companion.milliseconds
/** /**
* This class exposes methods to be used in common cases * This class exposes methods to be used in common cases
@ -67,10 +67,9 @@ class CommonTestHelper internal constructor(context: Context, val cryptoConfig:
companion object { companion object {
@OptIn(ExperimentalCoroutinesApi::class)
internal fun runSessionTest(context: Context, cryptoConfig: MXCryptoConfig? = null, autoSignoutOnClose: Boolean = true, block: suspend CoroutineScope.(CommonTestHelper) -> Unit) { internal fun runSessionTest(context: Context, cryptoConfig: MXCryptoConfig? = null, autoSignoutOnClose: Boolean = true, block: suspend CoroutineScope.(CommonTestHelper) -> Unit) {
val testHelper = CommonTestHelper(context, cryptoConfig) val testHelper = CommonTestHelper(context, cryptoConfig)
return runTest(dispatchTimeoutMs = TestConstants.timeOutMillis) { return runTest(timeout = TestConstants.timeOutMillis.milliseconds) {
try { try {
withContext(Dispatchers.Default) { withContext(Dispatchers.Default) {
block(testHelper) block(testHelper)
@ -83,11 +82,10 @@ class CommonTestHelper internal constructor(context: Context, val cryptoConfig:
} }
} }
@OptIn(ExperimentalCoroutinesApi::class)
internal fun runCryptoTest(context: Context, cryptoConfig: MXCryptoConfig? = null, autoSignoutOnClose: Boolean = true, block: suspend CoroutineScope.(CryptoTestHelper, CommonTestHelper) -> Unit) { internal fun runCryptoTest(context: Context, cryptoConfig: MXCryptoConfig? = null, autoSignoutOnClose: Boolean = true, block: suspend CoroutineScope.(CryptoTestHelper, CommonTestHelper) -> Unit) {
val testHelper = CommonTestHelper(context, cryptoConfig) val testHelper = CommonTestHelper(context, cryptoConfig)
val cryptoTestHelper = CryptoTestHelper(testHelper) val cryptoTestHelper = CryptoTestHelper(testHelper)
return runTest(dispatchTimeoutMs = TestConstants.timeOutMillis) { return runTest(timeout = TestConstants.timeOutMillis.milliseconds) {
try { try {
withContext(Dispatchers.Default) { withContext(Dispatchers.Default) {
block(cryptoTestHelper, testHelper) block(cryptoTestHelper, testHelper)
@ -100,11 +98,10 @@ class CommonTestHelper internal constructor(context: Context, val cryptoConfig:
} }
} }
@OptIn(ExperimentalCoroutinesApi::class)
internal fun runLongCryptoTest(context: Context, cryptoConfig: MXCryptoConfig? = null, autoSignoutOnClose: Boolean = true, block: suspend CoroutineScope.(CryptoTestHelper, CommonTestHelper) -> Unit) { internal fun runLongCryptoTest(context: Context, cryptoConfig: MXCryptoConfig? = null, autoSignoutOnClose: Boolean = true, block: suspend CoroutineScope.(CryptoTestHelper, CommonTestHelper) -> Unit) {
val testHelper = CommonTestHelper(context, cryptoConfig) val testHelper = CommonTestHelper(context, cryptoConfig)
val cryptoTestHelper = CryptoTestHelper(testHelper) val cryptoTestHelper = CryptoTestHelper(testHelper)
return runTest(dispatchTimeoutMs = TestConstants.timeOutMillis * 4) { return runTest(timeout = (TestConstants.timeOutMillis * 4).milliseconds) {
try { try {
withContext(Dispatchers.Default) { withContext(Dispatchers.Default) {
block(cryptoTestHelper, testHelper) block(cryptoTestHelper, testHelper)

View file

@ -37,10 +37,10 @@ suspend fun <T> LiveData<T>.first(timeout: Long = TestConstants.timeOutMillis, p
withContext(Dispatchers.Main) { withContext(Dispatchers.Main) {
suspendCancellableCoroutine { continuation -> suspendCancellableCoroutine { continuation ->
val observer = object : Observer<T> { val observer = object : Observer<T> {
override fun onChanged(data: T) { override fun onChanged(value: T) {
if (predicate(data)) { if (predicate(value)) {
removeObserver(this) removeObserver(this)
continuation.resume(data) continuation.resume(value)
} }
} }
} }

View file

@ -26,7 +26,6 @@ import org.junit.runners.JUnit4
import org.junit.runners.MethodSorters import org.junit.runners.MethodSorters
import org.matrix.android.sdk.InstrumentedTest import org.matrix.android.sdk.InstrumentedTest
import org.matrix.android.sdk.api.session.crypto.MXCryptoError import org.matrix.android.sdk.api.session.crypto.MXCryptoError
import org.matrix.android.sdk.api.session.getRoom
import org.matrix.android.sdk.api.session.room.timeline.getLastMessageContent import org.matrix.android.sdk.api.session.room.timeline.getLastMessageContent
import org.matrix.android.sdk.common.CommonTestHelper.Companion.runCryptoTest import org.matrix.android.sdk.common.CommonTestHelper.Companion.runCryptoTest

View file

@ -21,7 +21,6 @@ import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.LargeTest import androidx.test.filters.LargeTest
import junit.framework.TestCase.assertEquals import junit.framework.TestCase.assertEquals
import junit.framework.TestCase.assertNotNull import junit.framework.TestCase.assertNotNull
import junit.framework.TestCase.assertTrue
import org.amshove.kluent.shouldBeEqualTo import org.amshove.kluent.shouldBeEqualTo
import org.junit.Assert import org.junit.Assert
import org.junit.Assert.assertNull import org.junit.Assert.assertNull

View file

@ -56,7 +56,7 @@ class RealmSessionStoreMigration43Test {
} }
@Test @Test
fun migrationShouldBeNeeed() { fun migrationShouldBeNeeded() {
val realmName = "session_42.realm" val realmName = "session_42.realm"
val realmConfiguration = configurationFactory.createConfiguration( val realmConfiguration = configurationFactory.createConfiguration(
realmName, realmName,

View file

@ -27,11 +27,9 @@ import java.io.File
import java.io.FileOutputStream import java.io.FileOutputStream
import java.io.IOException import java.io.IOException
import java.io.InputStream import java.io.InputStream
import java.lang.IllegalStateException
import java.util.Collections import java.util.Collections
import java.util.Locale import java.util.Locale
import java.util.concurrent.ConcurrentHashMap import java.util.concurrent.ConcurrentHashMap
import kotlin.Throws
/** /**
* Based on https://github.com/realm/realm-java/blob/master/realm/realm-library/src/testUtils/java/io/realm/TestRealmConfigurationFactory.java * Based on https://github.com/realm/realm-java/blob/master/realm/realm-library/src/testUtils/java/io/realm/TestRealmConfigurationFactory.java

View file

@ -1,5 +1,4 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android" <manifest xmlns:android="http://schemas.android.com/apk/res/android">
xmlns:tools="http://schemas.android.com/tools">
<uses-permission android:name="android.permission.INTERNET" /> <uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" /> <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />

View file

@ -17,7 +17,7 @@
package org.matrix.android.sdk.internal.crypto.store package org.matrix.android.sdk.internal.crypto.store
import androidx.lifecycle.LiveData import androidx.lifecycle.LiveData
import androidx.lifecycle.Transformations import androidx.lifecycle.map
import com.zhuinden.monarchy.Monarchy import com.zhuinden.monarchy.Monarchy
import io.realm.Realm import io.realm.Realm
import io.realm.RealmConfiguration import io.realm.RealmConfiguration
@ -280,7 +280,7 @@ internal class RustCryptoStore @Inject constructor(
{ entity -> myDeviceLastSeenInfoEntityMapper.map(entity) } { entity -> myDeviceLastSeenInfoEntityMapper.map(entity) }
) )
return Transformations.map(liveData) { return liveData.map {
it.firstOrNull().toOptional() it.firstOrNull().toOptional()
} }
} }
@ -351,7 +351,7 @@ internal class RustCryptoStore @Inject constructor(
) )
} }
) )
return Transformations.map(liveData) { return liveData.map {
it.firstOrNull() ?: GlobalCryptoConfig(false, false, false) it.firstOrNull() ?: GlobalCryptoConfig(false, false, false)
} }
} }
@ -372,7 +372,7 @@ internal class RustCryptoStore @Inject constructor(
it.blacklistUnverifiedDevices it.blacklistUnverifiedDevices
} }
) )
return Transformations.map(liveData) { return liveData.map {
it.firstOrNull() ?: false it.firstOrNull() ?: false
} }
} }

View file

@ -39,6 +39,7 @@ import org.matrix.android.sdk.internal.crypto.store.db.migration.MigrateCryptoTo
import org.matrix.android.sdk.internal.crypto.store.db.migration.MigrateCryptoTo020 import org.matrix.android.sdk.internal.crypto.store.db.migration.MigrateCryptoTo020
import org.matrix.android.sdk.internal.crypto.store.db.migration.MigrateCryptoTo021 import org.matrix.android.sdk.internal.crypto.store.db.migration.MigrateCryptoTo021
import org.matrix.android.sdk.internal.crypto.store.db.migration.MigrateCryptoTo022 import org.matrix.android.sdk.internal.crypto.store.db.migration.MigrateCryptoTo022
import org.matrix.android.sdk.internal.crypto.store.db.migration.MigrateCryptoTo023
import org.matrix.android.sdk.internal.util.database.MatrixRealmMigration import org.matrix.android.sdk.internal.util.database.MatrixRealmMigration
import org.matrix.android.sdk.internal.util.time.Clock import org.matrix.android.sdk.internal.util.time.Clock
import javax.inject.Inject import javax.inject.Inject
@ -54,7 +55,7 @@ internal class RealmCryptoStoreMigration @Inject constructor(
private val rustMigrationInfoProvider: RustMigrationInfoProvider, private val rustMigrationInfoProvider: RustMigrationInfoProvider,
) : MatrixRealmMigration( ) : MatrixRealmMigration(
dbName = "Crypto", dbName = "Crypto",
schemaVersion = 22L, schemaVersion = 23L,
) { ) {
/** /**
* Forces all RealmCryptoStoreMigration instances to be equal. * Forces all RealmCryptoStoreMigration instances to be equal.
@ -91,5 +92,6 @@ internal class RealmCryptoStoreMigration @Inject constructor(
rustMigrationInfoProvider.rustEncryptionConfiguration, rustMigrationInfoProvider.rustEncryptionConfiguration,
rustMigrationInfoProvider.migrateMegolmGroupSessions rustMigrationInfoProvider.migrateMegolmGroupSessions
).perform() ).perform()
if (oldVersion < 23) MigrateCryptoTo023(realm).perform()
} }
} }

View file

@ -0,0 +1,30 @@
/*
* Copyright (c) 2024 The Matrix.org Foundation C.I.C.
*
* 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 org.matrix.android.sdk.internal.crypto.store.db.migration
import io.realm.DynamicRealm
import org.matrix.android.sdk.internal.crypto.store.db.model.OutgoingKeyRequestEntityFields
import org.matrix.android.sdk.internal.util.database.RealmMigrator
// Some fields are now required due to upgrade of Kotlin version.
// See https://github.com/realm/realm-java/issues/7810 for more details.
internal class MigrateCryptoTo023(realm: DynamicRealm) : RealmMigrator(realm, 23) {
override fun doMigrate(realm: DynamicRealm) {
realm.schema.get("OutgoingKeyRequestEntity")
?.setRequired(OutgoingKeyRequestEntityFields.REQUEST_STATE_STR, true)
}
}

View file

@ -72,6 +72,7 @@ import org.matrix.android.sdk.internal.database.migration.MigrateSessionTo052
import org.matrix.android.sdk.internal.database.migration.MigrateSessionTo053 import org.matrix.android.sdk.internal.database.migration.MigrateSessionTo053
import org.matrix.android.sdk.internal.database.migration.MigrateSessionTo054 import org.matrix.android.sdk.internal.database.migration.MigrateSessionTo054
import org.matrix.android.sdk.internal.database.migration.MigrateSessionTo055 import org.matrix.android.sdk.internal.database.migration.MigrateSessionTo055
import org.matrix.android.sdk.internal.database.migration.MigrateSessionTo056
import org.matrix.android.sdk.internal.util.Normalizer import org.matrix.android.sdk.internal.util.Normalizer
import org.matrix.android.sdk.internal.util.database.MatrixRealmMigration import org.matrix.android.sdk.internal.util.database.MatrixRealmMigration
import javax.inject.Inject import javax.inject.Inject
@ -80,7 +81,7 @@ internal class RealmSessionStoreMigration @Inject constructor(
private val normalizer: Normalizer private val normalizer: Normalizer
) : MatrixRealmMigration( ) : MatrixRealmMigration(
dbName = "Session", dbName = "Session",
schemaVersion = 55L, schemaVersion = 56L,
) { ) {
/** /**
* Forces all RealmSessionStoreMigration instances to be equal. * Forces all RealmSessionStoreMigration instances to be equal.
@ -145,5 +146,6 @@ internal class RealmSessionStoreMigration @Inject constructor(
if (oldVersion < 53) MigrateSessionTo053(realm).perform() if (oldVersion < 53) MigrateSessionTo053(realm).perform()
if (oldVersion < 54) MigrateSessionTo054(realm).perform() if (oldVersion < 54) MigrateSessionTo054(realm).perform()
if (oldVersion < 55) MigrateSessionTo055(realm).perform() if (oldVersion < 55) MigrateSessionTo055(realm).perform()
if (oldVersion < 56) MigrateSessionTo056(realm).perform()
} }
} }

View file

@ -17,14 +17,41 @@
package org.matrix.android.sdk.internal.database.migration package org.matrix.android.sdk.internal.database.migration
import io.realm.DynamicRealm import io.realm.DynamicRealm
import org.matrix.android.sdk.internal.database.model.HomeServerCapabilitiesEntityFields import org.matrix.android.sdk.internal.database.model.EventEntityFields
import org.matrix.android.sdk.internal.extensions.forceRefreshOfHomeServerCapabilities import org.matrix.android.sdk.internal.database.model.EventInsertEntityFields
import org.matrix.android.sdk.internal.database.model.LocalRoomSummaryEntityFields
import org.matrix.android.sdk.internal.database.model.PushRulesEntityFields
import org.matrix.android.sdk.internal.database.model.PusherEntityFields
import org.matrix.android.sdk.internal.database.model.RoomEntityFields
import org.matrix.android.sdk.internal.database.model.RoomMemberSummaryEntityFields
import org.matrix.android.sdk.internal.database.model.RoomSummaryEntityFields
import org.matrix.android.sdk.internal.database.model.presence.UserPresenceEntityFields
import org.matrix.android.sdk.internal.util.database.RealmMigrator import org.matrix.android.sdk.internal.util.database.RealmMigrator
internal class MigrateSessionTo055(realm: DynamicRealm) : RealmMigrator(realm, 54) { // Some fields are now required due to upgrade of Kotlin version.
// See https://github.com/realm/realm-java/issues/7810 for more details.
internal class MigrateSessionTo055(realm: DynamicRealm) : RealmMigrator(realm, 55) {
override fun doMigrate(realm: DynamicRealm) { override fun doMigrate(realm: DynamicRealm) {
realm.schema.get("HomeServerCapabilitiesEntity") realm.schema.get("EventEntity")
?.addField(HomeServerCapabilitiesEntityFields.CAN_USE_AUTHENTICATED_MEDIA, Boolean::class.java) ?.setRequired(EventEntityFields.SEND_STATE_STR, true)
?.forceRefreshOfHomeServerCapabilities() ?.setRequired(EventEntityFields.THREAD_NOTIFICATION_STATE_STR, true)
realm.schema.get("EventInsertEntity")
?.setRequired(EventInsertEntityFields.INSERT_TYPE_STR, true)
realm.schema.get("LocalRoomSummaryEntity")
?.setRequired(LocalRoomSummaryEntityFields.STATE_STR, true)
realm.schema.get("PushRulesEntity")
?.setRequired(PushRulesEntityFields.KIND_STR, true)
realm.schema.get("PusherEntity")
?.setRequired(PusherEntityFields.STATE_STR, true)
realm.schema.get("RoomEntity")
?.setRequired(RoomEntityFields.MEMBERSHIP_STR, true)
?.setRequired(RoomEntityFields.MEMBERS_LOAD_STATUS_STR, true)
realm.schema.get("RoomMemberSummaryEntity")
?.setRequired(RoomMemberSummaryEntityFields.MEMBERSHIP_STR, true)
realm.schema.get("RoomSummaryEntity")
?.setRequired(RoomSummaryEntityFields.MEMBERSHIP_STR, true)
?.setRequired(RoomSummaryEntityFields.VERSIONING_STATE_STR, true)
realm.schema.get("UserPresenceEntity")
?.setRequired(UserPresenceEntityFields.PRESENCE_STR, true)
} }
} }

View file

@ -0,0 +1,30 @@
/*
* 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.
*/
package org.matrix.android.sdk.internal.database.migration
import io.realm.DynamicRealm
import org.matrix.android.sdk.internal.database.model.HomeServerCapabilitiesEntityFields
import org.matrix.android.sdk.internal.extensions.forceRefreshOfHomeServerCapabilities
import org.matrix.android.sdk.internal.util.database.RealmMigrator
internal class MigrateSessionTo056(realm: DynamicRealm) : RealmMigrator(realm, 56) {
override fun doMigrate(realm: DynamicRealm) {
realm.schema.get("HomeServerCapabilitiesEntity")
?.addField(HomeServerCapabilitiesEntityFields.CAN_USE_AUTHENTICATED_MEDIA, Boolean::class.java)
?.forceRefreshOfHomeServerCapabilities()
}
}

View file

@ -84,10 +84,10 @@ internal class WorkManagerProvider @Inject constructor(
workManager.enqueue(checkWorkerRequest) workManager.enqueue(checkWorkerRequest)
val checkWorkerLiveState = workManager.getWorkInfoByIdLiveData(checkWorkerRequest.id) val checkWorkerLiveState = workManager.getWorkInfoByIdLiveData(checkWorkerRequest.id)
val observer = object : Observer<WorkInfo> { val observer = object : Observer<WorkInfo> {
override fun onChanged(workInfo: WorkInfo?) { override fun onChanged(value: WorkInfo) {
if (workInfo?.state?.isFinished == true) { if (value.state.isFinished) {
checkWorkerLiveState.removeObserver(this) checkWorkerLiveState.removeObserver(this)
if (workInfo.state == WorkInfo.State.FAILED) { if (value.state == WorkInfo.State.FAILED) {
throw RuntimeException( throw RuntimeException(
"MatrixWorkerFactory is not being set on your worker configuration.\n" + "MatrixWorkerFactory is not being set on your worker configuration.\n" +
"Makes sure to add it to a DelegatingWorkerFactory if you have your own factory or use it directly.\n" + "Makes sure to add it to a DelegatingWorkerFactory if you have your own factory or use it directly.\n" +

View file

@ -17,7 +17,7 @@
package org.matrix.android.sdk.internal.session.contentscanner.db package org.matrix.android.sdk.internal.session.contentscanner.db
import androidx.lifecycle.LiveData import androidx.lifecycle.LiveData
import androidx.lifecycle.Transformations import androidx.lifecycle.map
import com.zhuinden.monarchy.Monarchy import com.zhuinden.monarchy.Monarchy
import io.realm.Realm import io.realm.Realm
import io.realm.RealmConfiguration import io.realm.RealmConfiguration
@ -138,7 +138,7 @@ internal class RealmContentScannerStore @Inject constructor(
entity.toModel() entity.toModel()
} }
) )
return Transformations.map(liveData) { return liveData.map {
it.firstOrNull().toOptional() it.firstOrNull().toOptional()
} }
} }

View file

@ -17,7 +17,7 @@
package org.matrix.android.sdk.internal.session.homeserver package org.matrix.android.sdk.internal.session.homeserver
import androidx.lifecycle.LiveData import androidx.lifecycle.LiveData
import androidx.lifecycle.Transformations import androidx.lifecycle.map
import com.zhuinden.monarchy.Monarchy import com.zhuinden.monarchy.Monarchy
import io.realm.Realm import io.realm.Realm
import io.realm.kotlin.where import io.realm.kotlin.where
@ -46,7 +46,7 @@ internal class HomeServerCapabilitiesDataSource @Inject constructor(
{ realm: Realm -> realm.where<HomeServerCapabilitiesEntity>() }, { realm: Realm -> realm.where<HomeServerCapabilitiesEntity>() },
{ HomeServerCapabilitiesMapper.map(it) } { HomeServerCapabilitiesMapper.map(it) }
) )
return Transformations.map(liveData) { return liveData.map {
it.firstOrNull().toOptional() it.firstOrNull().toOptional()
} }
} }

View file

@ -84,7 +84,10 @@ internal class DefaultIdentityService @Inject constructor(
private val sessionParams: SessionParams private val sessionParams: SessionParams
) : IdentityService, SessionLifecycleObserver { ) : IdentityService, SessionLifecycleObserver {
private val lifecycleOwner: LifecycleOwner = LifecycleOwner { lifecycleRegistry } private val lifecycleOwner: LifecycleOwner = object : LifecycleOwner {
override val lifecycle: Lifecycle
get() = lifecycleRegistry
}
private val lifecycleRegistry: LifecycleRegistry = LifecycleRegistry(lifecycleOwner) private val lifecycleRegistry: LifecycleRegistry = LifecycleRegistry(lifecycleOwner)
private val listeners = mutableSetOf<IdentityServiceListener>() private val listeners = mutableSetOf<IdentityServiceListener>()

View file

@ -64,7 +64,10 @@ internal class IntegrationManager @Inject constructor(
SessionLifecycleObserver { SessionLifecycleObserver {
private val currentConfigs = ArrayList<IntegrationManagerConfig>() private val currentConfigs = ArrayList<IntegrationManagerConfig>()
private val lifecycleOwner: LifecycleOwner = LifecycleOwner { lifecycleRegistry } private val lifecycleOwner: LifecycleOwner = object : LifecycleOwner {
override val lifecycle: Lifecycle
get() = lifecycleRegistry
}
private val lifecycleRegistry: LifecycleRegistry = LifecycleRegistry(lifecycleOwner) private val lifecycleRegistry: LifecycleRegistry = LifecycleRegistry(lifecycleOwner)
private val listeners = HashSet<IntegrationManagerService.Listener>() private val listeners = HashSet<IntegrationManagerService.Listener>()

View file

@ -16,7 +16,7 @@
package org.matrix.android.sdk.internal.session.pushrules package org.matrix.android.sdk.internal.session.pushrules
import androidx.lifecycle.LiveData import androidx.lifecycle.LiveData
import androidx.lifecycle.Transformations import androidx.lifecycle.map
import com.zhuinden.monarchy.Monarchy import com.zhuinden.monarchy.Monarchy
import org.matrix.android.sdk.api.session.events.model.Event import org.matrix.android.sdk.api.session.events.model.Event
import org.matrix.android.sdk.api.session.pushrules.Action import org.matrix.android.sdk.api.session.pushrules.Action
@ -160,7 +160,7 @@ internal class DefaultPushRuleService @Inject constructor(
result.pushRules.map(PushRuleEntity::ruleId).filter { !it.startsWith(".") } result.pushRules.map(PushRuleEntity::ruleId).filter { !it.startsWith(".") }
} }
) )
return Transformations.map(liveData) { results -> return liveData.map { results ->
results.firstOrNull().orEmpty().toSet() results.firstOrNull().orEmpty().toSet()
} }
} }

View file

@ -17,7 +17,7 @@
package org.matrix.android.sdk.internal.session.room package org.matrix.android.sdk.internal.session.room
import androidx.lifecycle.LiveData import androidx.lifecycle.LiveData
import androidx.lifecycle.Transformations import androidx.lifecycle.map
import androidx.paging.PagedList import androidx.paging.PagedList
import com.zhuinden.monarchy.Monarchy import com.zhuinden.monarchy.Monarchy
import org.matrix.android.sdk.api.session.events.model.Event import org.matrix.android.sdk.api.session.events.model.Event
@ -242,7 +242,7 @@ internal class DefaultRoomService @Inject constructor(
}, },
{ it.asDomain() } { it.asDomain() }
) )
return Transformations.map(liveData) { results -> return liveData.map { results ->
results.firstOrNull().toOptional() results.firstOrNull().toOptional()
} }
} }

View file

@ -17,7 +17,7 @@
package org.matrix.android.sdk.internal.session.room package org.matrix.android.sdk.internal.session.room
import androidx.lifecycle.LiveData import androidx.lifecycle.LiveData
import androidx.lifecycle.Transformations import androidx.lifecycle.map
import com.zhuinden.monarchy.Monarchy import com.zhuinden.monarchy.Monarchy
import io.realm.Realm import io.realm.Realm
import org.matrix.android.sdk.api.extensions.orFalse import org.matrix.android.sdk.api.extensions.orFalse
@ -48,7 +48,7 @@ internal class RoomDataSource @Inject constructor(
} }
) )
return Transformations.map(liveData) { results -> return liveData.map { results ->
results.firstOrNull().orFalse() results.firstOrNull().orFalse()
} }
} }

View file

@ -18,7 +18,7 @@ package org.matrix.android.sdk.internal.session.room.accountdata
import androidx.lifecycle.LiveData import androidx.lifecycle.LiveData
import androidx.lifecycle.MediatorLiveData import androidx.lifecycle.MediatorLiveData
import androidx.lifecycle.Transformations import androidx.lifecycle.map
import com.zhuinden.monarchy.Monarchy import com.zhuinden.monarchy.Monarchy
import io.realm.Realm import io.realm.Realm
import io.realm.RealmQuery import io.realm.RealmQuery
@ -44,7 +44,7 @@ internal class RoomAccountDataDataSource @Inject constructor(
} }
fun getLiveAccountDataEvent(roomId: String, type: String): LiveData<Optional<RoomAccountDataEvent>> { fun getLiveAccountDataEvent(roomId: String, type: String): LiveData<Optional<RoomAccountDataEvent>> {
return Transformations.map(getLiveAccountDataEvents(roomId, setOf(type))) { return getLiveAccountDataEvents(roomId, setOf(type)).map {
it.firstOrNull().toOptional() it.firstOrNull().toOptional()
} }
} }

View file

@ -17,7 +17,7 @@
package org.matrix.android.sdk.internal.session.room.draft package org.matrix.android.sdk.internal.session.room.draft
import androidx.lifecycle.LiveData import androidx.lifecycle.LiveData
import androidx.lifecycle.Transformations import androidx.lifecycle.map
import com.zhuinden.monarchy.Monarchy import com.zhuinden.monarchy.Monarchy
import io.realm.Realm import io.realm.Realm
import io.realm.kotlin.createObject import io.realm.kotlin.createObject
@ -72,7 +72,7 @@ internal class DraftRepository @Inject constructor(
} }
} }
) )
return Transformations.map(liveData) { return liveData.map {
it.firstOrNull()?.firstOrNull().toOptional() it.firstOrNull()?.firstOrNull().toOptional()
} }
} }

View file

@ -17,7 +17,7 @@
package org.matrix.android.sdk.internal.session.room.location package org.matrix.android.sdk.internal.session.room.location
import androidx.lifecycle.LiveData import androidx.lifecycle.LiveData
import androidx.lifecycle.Transformations import androidx.lifecycle.map
import com.zhuinden.monarchy.Monarchy import com.zhuinden.monarchy.Monarchy
import dagger.assisted.Assisted import dagger.assisted.Assisted
import dagger.assisted.AssistedFactory import dagger.assisted.AssistedFactory
@ -119,13 +119,13 @@ internal class DefaultLocationSharingService @AssistedInject constructor(
} }
override fun getLiveLocationShareSummary(beaconInfoEventId: String): LiveData<Optional<LiveLocationShareAggregatedSummary>> { override fun getLiveLocationShareSummary(beaconInfoEventId: String): LiveData<Optional<LiveLocationShareAggregatedSummary>> {
return Transformations.map( return monarchy
monarchy.findAllMappedWithChanges( .findAllMappedWithChanges(
{ LiveLocationShareAggregatedSummaryEntity.where(it, roomId = roomId, eventId = beaconInfoEventId) }, { LiveLocationShareAggregatedSummaryEntity.where(it, roomId = roomId, eventId = beaconInfoEventId) },
liveLocationShareAggregatedSummaryMapper liveLocationShareAggregatedSummaryMapper
) )
) { .map {
it.firstOrNull().toOptional() it.firstOrNull().toOptional()
} }
} }
} }

View file

@ -17,7 +17,7 @@
package org.matrix.android.sdk.internal.session.room.notification package org.matrix.android.sdk.internal.session.room.notification
import androidx.lifecycle.LiveData import androidx.lifecycle.LiveData
import androidx.lifecycle.Transformations import androidx.lifecycle.map
import com.zhuinden.monarchy.Monarchy import com.zhuinden.monarchy.Monarchy
import dagger.assisted.Assisted import dagger.assisted.Assisted
import dagger.assisted.AssistedFactory import dagger.assisted.AssistedFactory
@ -42,7 +42,7 @@ internal class DefaultRoomPushRuleService @AssistedInject constructor(
} }
override fun getLiveRoomNotificationState(): LiveData<RoomNotificationState> { override fun getLiveRoomNotificationState(): LiveData<RoomNotificationState> {
return Transformations.map(getPushRuleForRoom()) { return getPushRuleForRoom().map {
it?.toRoomNotificationState() ?: RoomNotificationState.ALL_MESSAGES it?.toRoomNotificationState() ?: RoomNotificationState.ALL_MESSAGES
} }
} }
@ -60,7 +60,7 @@ internal class DefaultRoomPushRuleService @AssistedInject constructor(
result.toRoomPushRule() result.toRoomPushRule()
} }
) )
return Transformations.map(liveData) { results -> return liveData.map { results ->
results.firstOrNull() results.firstOrNull()
} }
} }

View file

@ -17,7 +17,8 @@
package org.matrix.android.sdk.internal.session.room.poll package org.matrix.android.sdk.internal.session.room.poll
import androidx.lifecycle.LiveData import androidx.lifecycle.LiveData
import androidx.lifecycle.Transformations import androidx.lifecycle.map
import androidx.lifecycle.switchMap
import com.zhuinden.monarchy.Monarchy import com.zhuinden.monarchy.Monarchy
import dagger.assisted.Assisted import dagger.assisted.Assisted
import dagger.assisted.AssistedFactory import dagger.assisted.AssistedFactory
@ -112,7 +113,7 @@ internal class DefaultPollHistoryService @AssistedInject constructor(
override fun getPollEvents(): LiveData<List<TimelineEvent>> { override fun getPollEvents(): LiveData<List<TimelineEvent>> {
val pollHistoryStatusLiveData = getPollHistoryStatus() val pollHistoryStatusLiveData = getPollHistoryStatus()
return Transformations.switchMap(pollHistoryStatusLiveData) { results -> return pollHistoryStatusLiveData.switchMap { results ->
val oldestTimestamp = results.firstOrNull()?.oldestTimestampTargetReachedMs ?: clock.epochMillis() val oldestTimestamp = results.firstOrNull()?.oldestTimestampTargetReachedMs ?: clock.epochMillis()
getPollStartEventsAfter(oldestTimestamp) getPollStartEventsAfter(oldestTimestamp)
} }
@ -132,7 +133,7 @@ internal class DefaultPollHistoryService @AssistedInject constructor(
} }
) )
return Transformations.map(eventsLiveData) { events -> return eventsLiveData.map { events ->
events.filter { it.root.getClearType() in EventType.POLL_START.values } events.filter { it.root.getClearType() in EventType.POLL_START.values }
.distinctBy { it.eventId } .distinctBy { it.eventId }
} }

View file

@ -17,7 +17,7 @@
package org.matrix.android.sdk.internal.session.room.read package org.matrix.android.sdk.internal.session.room.read
import androidx.lifecycle.LiveData import androidx.lifecycle.LiveData
import androidx.lifecycle.Transformations import androidx.lifecycle.map
import com.zhuinden.monarchy.Monarchy import com.zhuinden.monarchy.Monarchy
import dagger.assisted.Assisted import dagger.assisted.Assisted
import dagger.assisted.AssistedFactory import dagger.assisted.AssistedFactory
@ -94,7 +94,7 @@ internal class DefaultReadService @AssistedInject constructor(
{ ReadMarkerEntity.where(it, roomId) }, { ReadMarkerEntity.where(it, roomId) },
{ it.eventId } { it.eventId }
) )
return Transformations.map(liveRealmData) { return liveRealmData.map {
it.firstOrNull().toOptional() it.firstOrNull().toOptional()
} }
} }
@ -104,7 +104,7 @@ internal class DefaultReadService @AssistedInject constructor(
{ ReadReceiptEntity.where(it, roomId = roomId, userId = userId, threadId = threadId) }, { ReadReceiptEntity.where(it, roomId = roomId, userId = userId, threadId = threadId) },
{ it.eventId } { it.eventId }
) )
return Transformations.map(liveRealmData) { return liveRealmData.map {
it.firstOrNull().toOptional() it.firstOrNull().toOptional()
} }
} }
@ -125,7 +125,7 @@ internal class DefaultReadService @AssistedInject constructor(
{ ReadReceiptsSummaryEntity.where(it, eventId) }, { ReadReceiptsSummaryEntity.where(it, eventId) },
{ readReceiptsSummaryMapper.map(it) } { readReceiptsSummaryMapper.map(it) }
) )
return Transformations.map(liveRealmData) { return liveRealmData.map {
it.firstOrNull().orEmpty() it.firstOrNull().orEmpty()
} }
} }

View file

@ -16,7 +16,7 @@
package org.matrix.android.sdk.internal.session.room.relation package org.matrix.android.sdk.internal.session.room.relation
import androidx.lifecycle.LiveData import androidx.lifecycle.LiveData
import androidx.lifecycle.Transformations import androidx.lifecycle.map
import com.zhuinden.monarchy.Monarchy import com.zhuinden.monarchy.Monarchy
import dagger.assisted.Assisted import dagger.assisted.Assisted
import dagger.assisted.AssistedFactory import dagger.assisted.AssistedFactory
@ -163,7 +163,7 @@ internal class DefaultRelationService @AssistedInject constructor(
{ EventAnnotationsSummaryEntity.where(it, roomId, eventId) }, { EventAnnotationsSummaryEntity.where(it, roomId, eventId) },
{ it.asDomain() } { it.asDomain() }
) )
return Transformations.map(liveData) { results -> return liveData.map { results ->
results.firstOrNull().toOptional() results.firstOrNull().toOptional()
} }
} }

View file

@ -17,7 +17,7 @@
package org.matrix.android.sdk.internal.session.room.state package org.matrix.android.sdk.internal.session.room.state
import androidx.lifecycle.LiveData import androidx.lifecycle.LiveData
import androidx.lifecycle.Transformations import androidx.lifecycle.map
import com.zhuinden.monarchy.Monarchy import com.zhuinden.monarchy.Monarchy
import io.realm.Realm import io.realm.Realm
import io.realm.RealmQuery import io.realm.RealmQuery
@ -52,7 +52,7 @@ internal class StateEventDataSource @Inject constructor(
{ realm -> buildStateEventQuery(realm, roomId, setOf(eventType), stateKey) }, { realm -> buildStateEventQuery(realm, roomId, setOf(eventType), stateKey) },
{ it.root?.asDomain() } { it.root?.asDomain() }
) )
return Transformations.map(liveData) { results -> return liveData.map { results ->
results.firstOrNull().toOptional() results.firstOrNull().toOptional()
} }
} }
@ -72,7 +72,7 @@ internal class StateEventDataSource @Inject constructor(
{ realm -> buildStateEventQuery(realm, roomId, eventTypes, stateKey) }, { realm -> buildStateEventQuery(realm, roomId, eventTypes, stateKey) },
{ it.root?.asDomain() } { it.root?.asDomain() }
) )
return Transformations.map(liveData) { results -> return liveData.map { results ->
results.filterNotNull() results.filterNotNull()
} }
} }

View file

@ -19,7 +19,8 @@ package org.matrix.android.sdk.internal.session.room.summary
import androidx.lifecycle.LiveData import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.Transformations import androidx.lifecycle.map
import androidx.lifecycle.switchMap
import androidx.paging.LivePagedListBuilder import androidx.paging.LivePagedListBuilder
import androidx.paging.PagedList import androidx.paging.PagedList
import com.zhuinden.monarchy.Monarchy import com.zhuinden.monarchy.Monarchy
@ -84,7 +85,7 @@ internal class RoomSummaryDataSource @Inject constructor(
{ realm -> RoomSummaryEntity.where(realm, roomId).isNotEmpty(RoomSummaryEntityFields.DISPLAY_NAME) }, { realm -> RoomSummaryEntity.where(realm, roomId).isNotEmpty(RoomSummaryEntityFields.DISPLAY_NAME) },
{ roomSummaryMapper.map(it) } { roomSummaryMapper.map(it) }
) )
return Transformations.map(liveData) { results -> return liveData.map { results ->
results.firstOrNull().toOptional() results.firstOrNull().toOptional()
} }
} }
@ -113,7 +114,7 @@ internal class RoomSummaryDataSource @Inject constructor(
{ realm -> LocalRoomSummaryEntity.where(realm, roomId) }, { realm -> LocalRoomSummaryEntity.where(realm, roomId) },
{ localRoomSummaryMapper.map(it) } { localRoomSummaryMapper.map(it) }
) )
return Transformations.map(liveData) { results -> return liveData.map { results ->
results.firstOrNull().toOptional() results.firstOrNull().toOptional()
} }
} }
@ -165,7 +166,7 @@ internal class RoomSummaryDataSource @Inject constructor(
roomSummaryMapper.map(it) roomSummaryMapper.map(it)
} }
) )
return Transformations.map(liveData) { results -> return liveData.map { results ->
results.firstOrNull().toOptional() results.firstOrNull().toOptional()
} }
} }
@ -292,7 +293,7 @@ internal class RoomSummaryDataSource @Inject constructor(
val liveRooms = monarchy.findAllManagedWithChanges { val liveRooms = monarchy.findAllManagedWithChanges {
roomSummariesQuery(it, queryParams) roomSummariesQuery(it, queryParams)
} }
return Transformations.map(liveRooms) { return liveRooms.map {
it.realmResults.where().count().toInt() it.realmResults.where().count().toInt()
} }
} }
@ -387,7 +388,7 @@ internal class RoomSummaryDataSource @Inject constructor(
// and switch map to listen those? // and switch map to listen those?
val mediatorLiveData = HierarchyLiveDataHelper(spaceId, memberShips, this).liveData() val mediatorLiveData = HierarchyLiveDataHelper(spaceId, memberShips, this).liveData()
return Transformations.switchMap(mediatorLiveData) { allIds -> return mediatorLiveData.switchMap { allIds ->
monarchy.findAllMappedWithChanges( monarchy.findAllMappedWithChanges(
{ {
it.where<RoomSummaryEntity>() it.where<RoomSummaryEntity>()
@ -412,15 +413,16 @@ internal class RoomSummaryDataSource @Inject constructor(
} }
fun getFlattenOrphanRoomsLive(): LiveData<List<RoomSummary>> { fun getFlattenOrphanRoomsLive(): LiveData<List<RoomSummary>> {
return Transformations.map( return getRoomSummariesLive(
getRoomSummariesLive(roomSummaryQueryParams { roomSummaryQueryParams {
memberships = Membership.activeMemberships() memberships = Membership.activeMemberships()
excludeType = listOf(RoomType.SPACE) excludeType = listOf(RoomType.SPACE)
roomCategoryFilter = RoomCategoryFilter.ONLY_ROOMS roomCategoryFilter = RoomCategoryFilter.ONLY_ROOMS
}) }
) { )
it.filter { isOrphan(it) } .map {
} it.filter { isOrphan(it) }
}
} }
private fun isOrphan(roomSummary: RoomSummary): Boolean { private fun isOrphan(roomSummary: RoomSummary): Boolean {

View file

@ -17,7 +17,7 @@
package org.matrix.android.sdk.internal.session.user package org.matrix.android.sdk.internal.session.user
import androidx.lifecycle.LiveData import androidx.lifecycle.LiveData
import androidx.lifecycle.Transformations import androidx.lifecycle.map
import androidx.paging.DataSource import androidx.paging.DataSource
import androidx.paging.LivePagedListBuilder import androidx.paging.LivePagedListBuilder
import androidx.paging.PagedList import androidx.paging.PagedList
@ -73,7 +73,7 @@ internal class UserDataSource @Inject constructor(
{ UserEntity.where(it, userId) }, { UserEntity.where(it, userId) },
{ it.asDomain() } { it.asDomain() }
) )
return Transformations.map(liveData) { results -> return liveData.map { results ->
results.firstOrNull().toOptional() results.firstOrNull().toOptional()
} }
} }

View file

@ -17,7 +17,7 @@
package org.matrix.android.sdk.internal.session.user.accountdata package org.matrix.android.sdk.internal.session.user.accountdata
import androidx.lifecycle.LiveData import androidx.lifecycle.LiveData
import androidx.lifecycle.Transformations import androidx.lifecycle.map
import com.zhuinden.monarchy.Monarchy import com.zhuinden.monarchy.Monarchy
import io.realm.Realm import io.realm.Realm
import io.realm.RealmQuery import io.realm.RealmQuery
@ -42,7 +42,7 @@ internal class UserAccountDataDataSource @Inject constructor(
} }
fun getLiveAccountDataEvent(type: String): LiveData<Optional<UserAccountDataEvent>> { fun getLiveAccountDataEvent(type: String): LiveData<Optional<UserAccountDataEvent>> {
return Transformations.map(getLiveAccountDataEvents(setOf(type))) { return getLiveAccountDataEvents(setOf(type)).map {
it.firstOrNull().toOptional() it.firstOrNull().toOptional()
} }
} }

View file

@ -20,7 +20,7 @@ import androidx.lifecycle.Lifecycle
import androidx.lifecycle.LifecycleOwner import androidx.lifecycle.LifecycleOwner
import androidx.lifecycle.LifecycleRegistry import androidx.lifecycle.LifecycleRegistry
import androidx.lifecycle.LiveData import androidx.lifecycle.LiveData
import androidx.lifecycle.Transformations import androidx.lifecycle.map
import org.matrix.android.sdk.api.query.QueryStateEventValue import org.matrix.android.sdk.api.query.QueryStateEventValue
import org.matrix.android.sdk.api.query.QueryStringValue import org.matrix.android.sdk.api.query.QueryStringValue
import org.matrix.android.sdk.api.session.Session import org.matrix.android.sdk.api.session.Session
@ -57,7 +57,10 @@ internal class WidgetManager @Inject constructor(
IntegrationManagerService.Listener, SessionLifecycleObserver { IntegrationManagerService.Listener, SessionLifecycleObserver {
private val lifecycleOwner: LifecycleOwner = LifecycleOwner { lifecycleRegistry } private val lifecycleOwner: LifecycleOwner = object : LifecycleOwner {
override val lifecycle: Lifecycle
get() = lifecycleRegistry
}
private val lifecycleRegistry: LifecycleRegistry = LifecycleRegistry(lifecycleOwner) private val lifecycleRegistry: LifecycleRegistry = LifecycleRegistry(lifecycleOwner)
override fun onSessionStarted(session: Session) { override fun onSessionStarted(session: Session) {
@ -82,7 +85,7 @@ internal class WidgetManager @Inject constructor(
eventTypes = setOf(EventType.STATE_ROOM_WIDGET, EventType.STATE_ROOM_WIDGET_LEGACY), eventTypes = setOf(EventType.STATE_ROOM_WIDGET, EventType.STATE_ROOM_WIDGET_LEGACY),
stateKey = widgetId stateKey = widgetId
) )
return Transformations.map(liveWidgetEvents) { widgetEvents -> return liveWidgetEvents.map { widgetEvents ->
widgetEvents.mapEventsToWidgets(widgetTypes, excludedTypes) widgetEvents.mapEventsToWidgets(widgetTypes, excludedTypes)
} }
} }
@ -141,7 +144,7 @@ internal class WidgetManager @Inject constructor(
excludedTypes: Set<String>? = null excludedTypes: Set<String>? = null
): LiveData<List<Widget>> { ): LiveData<List<Widget>> {
val widgetsAccountData = userAccountDataDataSource.getLiveAccountDataEvent(UserAccountDataTypes.TYPE_WIDGETS) val widgetsAccountData = userAccountDataDataSource.getLiveAccountDataEvent(UserAccountDataTypes.TYPE_WIDGETS)
return Transformations.map(widgetsAccountData) { return widgetsAccountData.map {
it.getOrNull()?.mapToWidgets(widgetTypes, excludedTypes).orEmpty() it.getOrNull()?.mapToWidgets(widgetTypes, excludedTypes).orEmpty()
} }
} }

View file

@ -19,6 +19,6 @@ package org.matrix.android.sdk.internal.util
import androidx.collection.LruCache import androidx.collection.LruCache
@Suppress("NULLABLE_TYPE_PARAMETER_AGAINST_NOT_NULL_TYPE_PARAMETER") @Suppress("NULLABLE_TYPE_PARAMETER_AGAINST_NOT_NULL_TYPE_PARAMETER")
internal inline fun <K, V> LruCache<K, V>.getOrPut(key: K, defaultValue: () -> V): V { internal inline fun <K : Any, V : Any> LruCache<K, V>.getOrPut(key: K, defaultValue: () -> V): V {
return get(key) ?: defaultValue().also { put(key, it) } return get(key) ?: defaultValue().also { put(key, it) }
} }

View file

@ -29,7 +29,6 @@ import org.junit.Test
import org.matrix.android.sdk.BuildConfig import org.matrix.android.sdk.BuildConfig
import org.matrix.android.sdk.api.util.getApplicationInfoCompat import org.matrix.android.sdk.api.util.getApplicationInfoCompat
import org.matrix.android.sdk.api.util.getPackageInfoCompat import org.matrix.android.sdk.api.util.getPackageInfoCompat
import java.lang.Exception
private const val A_PACKAGE_NAME = "org.matrix.sdk" private const val A_PACKAGE_NAME = "org.matrix.sdk"
private const val AN_APP_NAME = "Element" private const val AN_APP_NAME = "Element"

View file

@ -16,17 +16,12 @@
package org.matrix.android.sdk.internal.session.room.location package org.matrix.android.sdk.internal.session.room.location
import androidx.arch.core.util.Function
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.Transformations
import io.mockk.coEvery import io.mockk.coEvery
import io.mockk.coVerify import io.mockk.coVerify
import io.mockk.every
import io.mockk.just import io.mockk.just
import io.mockk.mockk import io.mockk.mockk
import io.mockk.mockkStatic import io.mockk.mockkStatic
import io.mockk.runs import io.mockk.runs
import io.mockk.slot
import io.mockk.unmockkAll import io.mockk.unmockkAll
import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.test.runTest import kotlinx.coroutines.test.runTest
@ -37,7 +32,6 @@ import org.junit.Test
import org.matrix.android.sdk.api.session.room.location.UpdateLiveLocationShareResult import org.matrix.android.sdk.api.session.room.location.UpdateLiveLocationShareResult
import org.matrix.android.sdk.api.session.room.model.livelocation.LiveLocationShareAggregatedSummary import org.matrix.android.sdk.api.session.room.model.livelocation.LiveLocationShareAggregatedSummary
import org.matrix.android.sdk.api.util.Cancelable import org.matrix.android.sdk.api.util.Cancelable
import org.matrix.android.sdk.api.util.Optional
import org.matrix.android.sdk.api.util.toOptional import org.matrix.android.sdk.api.util.toOptional
import org.matrix.android.sdk.internal.database.mapper.LiveLocationShareAggregatedSummaryMapper import org.matrix.android.sdk.internal.database.mapper.LiveLocationShareAggregatedSummaryMapper
import org.matrix.android.sdk.internal.database.model.livelocation.LiveLocationShareAggregatedSummaryEntity import org.matrix.android.sdk.internal.database.model.livelocation.LiveLocationShareAggregatedSummaryEntity
@ -262,25 +256,14 @@ internal class DefaultLocationSharingServiceTest {
endOfLiveTimestampMillis = 123, endOfLiveTimestampMillis = 123,
lastLocationDataContent = null lastLocationDataContent = null
) )
fakeMonarchy.givenWhere<LiveLocationShareAggregatedSummaryEntity>() fakeMonarchy.givenWhere<LiveLocationShareAggregatedSummaryEntity>()
.givenEqualTo(LiveLocationShareAggregatedSummaryEntityFields.ROOM_ID, A_ROOM_ID) .givenEqualTo(LiveLocationShareAggregatedSummaryEntityFields.ROOM_ID, A_ROOM_ID)
.givenEqualTo(LiveLocationShareAggregatedSummaryEntityFields.EVENT_ID, AN_EVENT_ID) .givenEqualTo(LiveLocationShareAggregatedSummaryEntityFields.EVENT_ID, AN_EVENT_ID)
val liveData = fakeMonarchy.givenFindAllMappedWithChangesReturns( fakeMonarchy.givenFindAllMappedWithChangesReturns(
realmEntities = listOf(entity), realmEntities = listOf(entity),
mappedResult = listOf(summary), mappedResult = listOf(summary),
fakeLiveLocationShareAggregatedSummaryMapper fakeLiveLocationShareAggregatedSummaryMapper
) )
val mapper = slot<Function<List<LiveLocationShareAggregatedSummary>, Optional<LiveLocationShareAggregatedSummary>>>()
every {
Transformations.map(
liveData,
capture(mapper)
)
} answers {
val value = secondArg<Function<List<LiveLocationShareAggregatedSummary>, Optional<LiveLocationShareAggregatedSummary>>>().apply(listOf(summary))
MutableLiveData(value)
}
val result = defaultLocationSharingService.getLiveLocationShareSummary(AN_EVENT_ID).value val result = defaultLocationSharingService.getLiveLocationShareSummary(AN_EVENT_ID).value

View file

@ -1,11 +1,10 @@
#!/usr/bin/env python3 #!/usr/bin/env python3
from collections import OrderedDict
import requests
import json import json
import re
import os import os
import re
import requests
from bs4 import BeautifulSoup from bs4 import BeautifulSoup
from collections import OrderedDict
# A list of words to not capitalize in emoji-names # A list of words to not capitalize in emoji-names
capitalization_exclude = {'with', 'a', 'at', 'of', 'for', 'and', 'over', 'the', 'off', 'on', 'out', 'in', 'but', 'or'} capitalization_exclude = {'with', 'a', 'at', 'of', 'for', 'and', 'over', 'the', 'off', 'on', 'out', 'in', 'but', 'or'}

View file

@ -11,7 +11,7 @@
<issue id="TypographyEllipsis" severity="error" /> <issue id="TypographyEllipsis" severity="error" />
<issue id="ImpliedQuantity" severity="warning" /> <issue id="ImpliedQuantity" severity="warning" />
<issue id="MissingQuantity" severity="warning" /> <issue id="MissingQuantity" severity="warning" />
<issue id="UnusedQuantity" severity="error" /> <issue id="UnusedQuantity" severity="warning" />
<issue id="IconXmlAndPng" severity="error" /> <issue id="IconXmlAndPng" severity="error" />
<issue id="IconDipSize" severity="error" /> <issue id="IconDipSize" severity="error" />
<issue id="IconDuplicatesConfig" severity="error" /> <issue id="IconDuplicatesConfig" severity="error" />

View file

@ -18,10 +18,10 @@
import argparse import argparse
import json import json
import os import os
# Run `pip3 install requests` if not installed yet
import requests
# Run `pip3 install re` if not installed yet # Run `pip3 install re` if not installed yet
import re import re
# Run `pip3 install requests` if not installed yet
import requests
# This script downloads artifacts from GitHub. # This script downloads artifacts from GitHub.
# Ref: https://docs.github.com/en/rest/actions/artifacts#get-an-artifact # Ref: https://docs.github.com/en/rest/actions/artifacts#get-an-artifact

View file

@ -250,7 +250,7 @@ android {
resValue "string", "app_name", "Element - dbg" resValue "string", "app_name", "Element - dbg"
if (project.hasProperty("coverage")) { if (project.hasProperty("coverage")) {
testCoverageEnabled = coverage == "true" testCoverageEnabled = project.coverage == "true"
} }
} }
@ -342,7 +342,7 @@ android {
} }
} }
lintOptions { lint {
lintConfig file("../tools/lint/lint.xml") lintConfig file("../tools/lint/lint.xml")
checkDependencies true checkDependencies true
@ -355,7 +355,7 @@ android {
} }
kotlinOptions { kotlinOptions {
jvmTarget = "11" jvmTarget = versions.jvmTarget
freeCompilerArgs += [ freeCompilerArgs += [
"-opt-in=kotlin.RequiresOptIn", "-opt-in=kotlin.RequiresOptIn",
// Fixes false positive "This is an internal Mavericks API. It is not intended for external use." // Fixes false positive "This is an internal Mavericks API. It is not intended for external use."
@ -370,6 +370,13 @@ android {
buildFeatures { buildFeatures {
viewBinding true viewBinding true
buildConfig true
}
packaging {
pickFirsts.add("META-INF/LICENSE.md")
pickFirsts.add("META-INF/LICENSE-notice.md")
pickFirsts.add("MANIFEST.MF")
} }
} }
@ -377,6 +384,7 @@ dependencies {
implementation project(':vector') implementation project(':vector')
implementation project(':vector-config') implementation project(':vector-config')
implementation project(':library:core-utils') implementation project(':library:core-utils')
implementation project(':library:ui-strings')
debugImplementation project(':library:external:span') debugImplementation project(':library:external:span')
debugImplementation project(':library:ui-styles') debugImplementation project(':library:ui-styles')
implementation libs.dagger.hilt implementation libs.dagger.hilt
@ -393,7 +401,7 @@ dependencies {
debugImplementation 'com.facebook.soloader:soloader:0.10.5' debugImplementation 'com.facebook.soloader:soloader:0.10.5'
debugImplementation "com.kgurgul.flipper:flipper-realm-android:2.2.0" debugImplementation "com.kgurgul.flipper:flipper-realm-android:2.2.0"
gplayImplementation "com.google.android.gms:play-services-location:21.0.1" gplayImplementation "com.google.android.gms:play-services-location:21.3.0"
// UnifiedPush gplay flavor only // UnifiedPush gplay flavor only
gplayImplementation platform(libs.google.firebaseBom) gplayImplementation platform(libs.google.firebaseBom)
gplayImplementation(libs.google.messaging) { gplayImplementation(libs.google.messaging) {
@ -409,7 +417,7 @@ dependencies {
nightlyImplementation libs.google.appdistribution nightlyImplementation libs.google.appdistribution
// OSS License, gplay flavor only // OSS License, gplay flavor only
gplayImplementation 'com.google.android.gms:play-services-oss-licenses:17.0.1' gplayImplementation 'com.google.android.gms:play-services-oss-licenses:17.1.0'
kapt libs.dagger.hiltCompiler kapt libs.dagger.hiltCompiler
ksp libs.airbnb.epoxyProcessor ksp libs.airbnb.epoxyProcessor

View file

@ -80,3 +80,16 @@
# JNA # JNA
-keep class com.sun.jna.** { *; } -keep class com.sun.jna.** { *; }
-keep class * implements com.sun.jna.** { *; } -keep class * implements com.sun.jna.** { *; }
# New
-dontwarn com.google.appengine.api.urlfetch.**
-dontwarn com.google.common.io.LimitInputStream
-dontwarn com.google.firebase.analytics.connector.AnalyticsConnector
-dontwarn com.google.javascript.jscomp.**
-dontwarn com.likethesalad.android.templates.provider.api.TemplatesProvider
-dontwarn com.yahoo.platform.yui.compressor.**
-dontwarn java.awt.**
-dontwarn org.apache.velocity.**
-dontwarn org.commonmark.ext.gfm.strikethrough.Strikethrough
-dontwarn org.mozilla.javascript.**
-dontwarn org.slf4j.**

View file

@ -26,6 +26,7 @@ import androidx.test.filters.LargeTest
import com.adevinta.android.barista.internal.viewaction.SleepViewAction import com.adevinta.android.barista.internal.viewaction.SleepViewAction
import im.vector.app.features.MainActivity import im.vector.app.features.MainActivity
import im.vector.app.ui.robot.ElementRobot import im.vector.app.ui.robot.ElementRobot
import im.vector.lib.strings.CommonStrings
import org.junit.Rule import org.junit.Rule
import org.junit.Test import org.junit.Test
import org.junit.rules.RuleChain import org.junit.rules.RuleChain
@ -61,7 +62,7 @@ class CantVerifyTest {
val activity = EspressoHelper.getCurrentActivity()!! val activity = EspressoHelper.getCurrentActivity()!!
Espresso.onView(ViewMatchers.isRoot()) Espresso.onView(ViewMatchers.isRoot())
.perform(waitForView(ViewMatchers.withText(R.string.crosssigning_cannot_verify_this_session))) .perform(waitForView(ViewMatchers.withText(CommonStrings.crosssigning_cannot_verify_this_session)))
// check that the text is correct // check that the text is correct
val popup = activity.findViewById<View>(com.tapadoo.alerter.R.id.llAlertBackground)!! val popup = activity.findViewById<View>(com.tapadoo.alerter.R.id.llAlertBackground)!!
@ -73,7 +74,7 @@ class CantVerifyTest {
Espresso.onView(ViewMatchers.isRoot()).perform(SleepViewAction.sleep(2000)) Espresso.onView(ViewMatchers.isRoot()).perform(SleepViewAction.sleep(2000))
Espresso.onView(ViewMatchers.withText(R.string.bottom_sheet_setup_secure_backup_title)) Espresso.onView(ViewMatchers.withText(CommonStrings.bottom_sheet_setup_secure_backup_title))
.check(ViewAssertions.matches(ViewMatchers.isDisplayed())) .check(ViewAssertions.matches(ViewMatchers.isDisplayed()))
} }
} }

View file

@ -31,6 +31,7 @@ import androidx.test.filters.LargeTest
import im.vector.app.features.MainActivity import im.vector.app.features.MainActivity
import im.vector.app.features.analytics.ui.consent.AnalyticsOptInActivity import im.vector.app.features.analytics.ui.consent.AnalyticsOptInActivity
import im.vector.app.features.home.HomeActivity import im.vector.app.features.home.HomeActivity
import im.vector.lib.strings.CommonStrings
import org.hamcrest.CoreMatchers.not import org.hamcrest.CoreMatchers.not
import org.junit.Ignore import org.junit.Ignore
import org.junit.Rule import org.junit.Rule
@ -55,7 +56,7 @@ class RegistrationTest {
// Check splashscreen is there // Check splashscreen is there
onView(withId(R.id.loginSplashSubmit)) onView(withId(R.id.loginSplashSubmit))
.check(matches(isDisplayed())) .check(matches(isDisplayed()))
.check(matches(withText(R.string.login_splash_submit))) .check(matches(withText(CommonStrings.login_splash_submit)))
// Click on get started // Click on get started
onView(withId(R.id.loginSplashSubmit)) onView(withId(R.id.loginSplashSubmit))
@ -64,7 +65,7 @@ class RegistrationTest {
// Check that homeserver options are shown // Check that homeserver options are shown
onView(withId(R.id.loginServerTitle)) onView(withId(R.id.loginServerTitle))
.check(matches(isDisplayed())) .check(matches(isDisplayed()))
.check(matches(withText(R.string.login_server_title))) .check(matches(withText(CommonStrings.login_server_title)))
// Chose custom server // Chose custom server
onView(withId(R.id.loginServerChoiceOther)) onView(withId(R.id.loginServerChoiceOther))

View file

@ -42,6 +42,7 @@ import im.vector.app.core.utils.getMatrixInstance
import im.vector.app.features.MainActivity import im.vector.app.features.MainActivity
import im.vector.app.features.crypto.recover.SetupMode import im.vector.app.features.crypto.recover.SetupMode
import im.vector.app.features.home.HomeActivity import im.vector.app.features.home.HomeActivity
import im.vector.lib.strings.CommonStrings
import org.hamcrest.CoreMatchers.not import org.hamcrest.CoreMatchers.not
import org.junit.Before import org.junit.Before
import org.junit.Ignore import org.junit.Ignore
@ -109,7 +110,7 @@ class SecurityBootstrapTest : VerificationTestBase() {
.perform(click()) .perform(click())
onView(isRoot()) onView(isRoot())
.perform(waitForView(withText(R.string.bootstrap_info_text_2))) .perform(waitForView(withText(CommonStrings.bootstrap_info_text_2)))
// test back // test back
onView(isRoot()).perform(pressBack()) onView(isRoot()).perform(pressBack())
@ -124,7 +125,7 @@ class SecurityBootstrapTest : VerificationTestBase() {
.perform(click()) .perform(click())
onView(isRoot()) onView(isRoot())
.perform(waitForView(withText(R.string.bootstrap_info_text_2))) .perform(waitForView(withText(CommonStrings.bootstrap_info_text_2)))
onView(withId(R.id.ssss_passphrase_enter_edittext)) onView(withId(R.id.ssss_passphrase_enter_edittext))
.perform(typeText("person woman man camera tv")) .perform(typeText("person woman man camera tv"))
@ -139,7 +140,7 @@ class SecurityBootstrapTest : VerificationTestBase() {
onView(withId(R.id.bootstrapSubmit)) onView(withId(R.id.bootstrapSubmit))
.perform(closeSoftKeyboard(), click()) .perform(closeSoftKeyboard(), click())
onView(withText(R.string.passphrase_passphrase_does_not_match)).check(matches(isDisplayed())) onView(withText(CommonStrings.passphrase_passphrase_does_not_match)).check(matches(isDisplayed()))
onView(withId(R.id.ssss_passphrase_enter_edittext)) onView(withId(R.id.ssss_passphrase_enter_edittext))
.perform(replaceText("person woman man camera tv")) .perform(replaceText("person woman man camera tv"))
@ -148,7 +149,7 @@ class SecurityBootstrapTest : VerificationTestBase() {
.perform(closeSoftKeyboard(), click()) .perform(closeSoftKeyboard(), click())
onView(withId(R.id.bottomSheetScrollView)) onView(withId(R.id.bottomSheetScrollView))
.perform(waitForView(withText(R.string.bottom_sheet_save_your_recovery_key_content))) .perform(waitForView(withText(CommonStrings.bottom_sheet_save_your_recovery_key_content)))
intending(hasAction(Intent.ACTION_SEND)).respondWith(ActivityResult(Activity.RESULT_OK, null)) intending(hasAction(Intent.ACTION_SEND)).respondWith(ActivityResult(Activity.RESULT_OK, null))
@ -156,12 +157,12 @@ class SecurityBootstrapTest : VerificationTestBase() {
.perform(click()) .perform(click())
// Dismiss dialog // Dismiss dialog
onView(withText(R.string.ok)).inRoot(RootMatchers.isDialog()).perform(click()) onView(withText(CommonStrings.ok)).inRoot(RootMatchers.isDialog()).perform(click())
onView(withId(R.id.bottomSheetScrollView)) onView(withId(R.id.bottomSheetScrollView))
.perform(waitForView(withText(R.string.bottom_sheet_save_your_recovery_key_content))) .perform(waitForView(withText(CommonStrings.bottom_sheet_save_your_recovery_key_content)))
onView(withText(R.string._continue)).perform(click()) onView(withText(CommonStrings._continue)).perform(click())
// Assert that all is configured // Assert that all is configured
val crossSigningInitialized = runBlockingTest { val crossSigningInitialized = runBlockingTest {

View file

@ -27,6 +27,7 @@ import im.vector.app.espresso.tools.waitUntilViewVisible
import im.vector.app.features.home.HomeActivity import im.vector.app.features.home.HomeActivity
import im.vector.app.ui.robot.AnalyticsRobot import im.vector.app.ui.robot.AnalyticsRobot
import im.vector.app.ui.robot.OnboardingRobot import im.vector.app.ui.robot.OnboardingRobot
import im.vector.lib.strings.CommonStrings
import kotlinx.coroutines.CompletableDeferred import kotlinx.coroutines.CompletableDeferred
import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.DelicateCoroutinesApi import kotlinx.coroutines.DelicateCoroutinesApi
@ -184,18 +185,18 @@ abstract class VerificationTestBase {
Espresso.onView(ViewMatchers.isRoot()) Espresso.onView(ViewMatchers.isRoot())
.perform(waitForView(ViewMatchers.withId(R.id.bottomSheetFragmentContainer))) .perform(waitForView(ViewMatchers.withId(R.id.bottomSheetFragmentContainer)))
Espresso.onView(ViewMatchers.withText(R.string.verification_verify_identity)) Espresso.onView(ViewMatchers.withText(CommonStrings.verification_verify_identity))
.check(ViewAssertions.matches(ViewMatchers.isDisplayed())) .check(ViewAssertions.matches(ViewMatchers.isDisplayed()))
// 4S is not setup so passphrase option should be hidden // 4S is not setup so passphrase option should be hidden
Espresso.onView(ViewMatchers.withId(R.id.bottomSheetVerificationRecyclerView)) Espresso.onView(ViewMatchers.withId(R.id.bottomSheetVerificationRecyclerView))
.check(ViewAssertions.matches(CoreMatchers.not(ViewMatchers.hasDescendant(ViewMatchers.withText(R.string.verification_cannot_access_other_session))))) .check(ViewAssertions.matches(CoreMatchers.not(ViewMatchers.hasDescendant(ViewMatchers.withText(CommonStrings.verification_cannot_access_other_session)))))
Espresso.onView(ViewMatchers.withId(R.id.bottomSheetVerificationRecyclerView)) Espresso.onView(ViewMatchers.withId(R.id.bottomSheetVerificationRecyclerView))
.check(ViewAssertions.matches(ViewMatchers.hasDescendant(ViewMatchers.withText(R.string.verification_verify_with_another_device)))) .check(ViewAssertions.matches(ViewMatchers.hasDescendant(ViewMatchers.withText(CommonStrings.verification_verify_with_another_device))))
Espresso.onView(ViewMatchers.withId(R.id.bottomSheetVerificationRecyclerView)) Espresso.onView(ViewMatchers.withId(R.id.bottomSheetVerificationRecyclerView))
.check(ViewAssertions.matches(ViewMatchers.hasDescendant(ViewMatchers.withText(R.string.bad_passphrase_key_reset_all_action)))) .check(ViewAssertions.matches(ViewMatchers.hasDescendant(ViewMatchers.withText(CommonStrings.bad_passphrase_key_reset_all_action))))
return uiSession return uiSession
} }

View file

@ -31,6 +31,7 @@ import androidx.test.filters.LargeTest
import im.vector.app.core.utils.getMatrixInstance import im.vector.app.core.utils.getMatrixInstance
import im.vector.app.features.MainActivity import im.vector.app.features.MainActivity
import im.vector.app.ui.robot.ElementRobot import im.vector.app.ui.robot.ElementRobot
import im.vector.lib.strings.CommonStrings
import kotlinx.coroutines.test.runTest import kotlinx.coroutines.test.runTest
import org.amshove.kluent.internal.assertEquals import org.amshove.kluent.internal.assertEquals
import org.junit.After import org.junit.After
@ -117,13 +118,13 @@ class VerifySessionInteractiveTest : VerificationTestBase() {
onView(withId(R.id.bottomSheetVerificationRecyclerView)) onView(withId(R.id.bottomSheetVerificationRecyclerView))
.perform( .perform(
actionOnItem<RecyclerView.ViewHolder>( actionOnItem<RecyclerView.ViewHolder>(
hasDescendant(withText(R.string.verification_verify_with_another_device)), hasDescendant(withText(CommonStrings.verification_verify_with_another_device)),
click() click()
) )
) )
onView(withId(R.id.bottomSheetVerificationRecyclerView)) onView(withId(R.id.bottomSheetVerificationRecyclerView))
.check(matches(hasDescendant(withText(R.string.verification_request_was_sent)))) .check(matches(hasDescendant(withText(CommonStrings.verification_request_was_sent))))
val txId = runBlockingTest { val txId = runBlockingTest {
otherRequest.await().transactionId otherRequest.await().transactionId
@ -139,9 +140,9 @@ class VerifySessionInteractiveTest : VerificationTestBase() {
} }
onView(withId(R.id.bottomSheetVerificationRecyclerView)) onView(withId(R.id.bottomSheetVerificationRecyclerView))
.perform(waitForView(hasDescendant(withText(R.string.verification_scan_self_notice)))) .perform(waitForView(hasDescendant(withText(CommonStrings.verification_scan_self_notice))))
onView(withId(R.id.bottomSheetVerificationRecyclerView)) onView(withId(R.id.bottomSheetVerificationRecyclerView))
.perform(waitForView(hasDescendant(withText(R.string.verification_scan_self_emoji_subtitle)))) .perform(waitForView(hasDescendant(withText(CommonStrings.verification_scan_self_emoji_subtitle))))
// there should be the QR code also // there should be the QR code also
onView(withId(R.id.bottomSheetVerificationRecyclerView)) onView(withId(R.id.bottomSheetVerificationRecyclerView))
@ -151,16 +152,16 @@ class VerifySessionInteractiveTest : VerificationTestBase() {
onView(withId(R.id.bottomSheetVerificationRecyclerView)) onView(withId(R.id.bottomSheetVerificationRecyclerView))
.perform( .perform(
actionOnItem<RecyclerView.ViewHolder>( actionOnItem<RecyclerView.ViewHolder>(
hasDescendant(withText(R.string.verification_scan_self_emoji_subtitle)), hasDescendant(withText(CommonStrings.verification_scan_self_emoji_subtitle)),
click() click()
) )
) )
onView(withId(R.id.bottomSheetVerificationRecyclerView)) onView(withId(R.id.bottomSheetVerificationRecyclerView))
.perform(waitForView(hasDescendant(withText(R.string.verification_sas_do_not_match)))) .perform(waitForView(hasDescendant(withText(CommonStrings.verification_sas_do_not_match))))
onView(withId(R.id.bottomSheetVerificationRecyclerView)) onView(withId(R.id.bottomSheetVerificationRecyclerView))
.perform(waitForView(hasDescendant(withText(R.string.verification_sas_match)))) .perform(waitForView(hasDescendant(withText(CommonStrings.verification_sas_match))))
// check that the code matches // check that the code matches
val uiCode = runBlockingTest { val uiCode = runBlockingTest {
@ -190,19 +191,19 @@ class VerifySessionInteractiveTest : VerificationTestBase() {
onView(withId(R.id.bottomSheetVerificationRecyclerView)) onView(withId(R.id.bottomSheetVerificationRecyclerView))
.perform( .perform(
actionOnItem<RecyclerView.ViewHolder>( actionOnItem<RecyclerView.ViewHolder>(
hasDescendant(withText(R.string.verification_sas_match)), hasDescendant(withText(CommonStrings.verification_sas_match)),
click() click()
) )
) )
onView(withId(R.id.bottomSheetVerificationRecyclerView)) onView(withId(R.id.bottomSheetVerificationRecyclerView))
.perform(waitForView(hasDescendant(withText(R.string.verification_conclusion_ok_notice)))) .perform(waitForView(hasDescendant(withText(CommonStrings.verification_conclusion_ok_notice))))
// click on done // click on done
onView(withId(R.id.bottomSheetVerificationRecyclerView)) onView(withId(R.id.bottomSheetVerificationRecyclerView))
.perform( .perform(
actionOnItem<RecyclerView.ViewHolder>( actionOnItem<RecyclerView.ViewHolder>(
hasDescendant(withText(R.string.done)), hasDescendant(withText(CommonStrings.done)),
click() click()
) )
) )

View file

@ -31,6 +31,7 @@ import im.vector.app.espresso.tools.waitUntilViewVisible
import im.vector.app.features.MainActivity import im.vector.app.features.MainActivity
import im.vector.app.features.home.HomeActivity import im.vector.app.features.home.HomeActivity
import im.vector.app.ui.robot.ElementRobot import im.vector.app.ui.robot.ElementRobot
import im.vector.lib.strings.CommonStrings
import kotlinx.coroutines.test.runTest import kotlinx.coroutines.test.runTest
import org.junit.After import org.junit.After
import org.junit.Before import org.junit.Before
@ -102,13 +103,13 @@ class VerifySessionNavigationTest : VerificationTestBase() {
Espresso.onView(ViewMatchers.withId(R.id.bottomSheetVerificationRecyclerView)) Espresso.onView(ViewMatchers.withId(R.id.bottomSheetVerificationRecyclerView))
.perform( .perform(
RecyclerViewActions.actionOnItem<RecyclerView.ViewHolder>( RecyclerViewActions.actionOnItem<RecyclerView.ViewHolder>(
ViewMatchers.hasDescendant(ViewMatchers.withText(R.string.verification_verify_with_another_device)), ViewMatchers.hasDescendant(ViewMatchers.withText(CommonStrings.verification_verify_with_another_device)),
ViewActions.click() ViewActions.click()
) )
) )
Espresso.onView(ViewMatchers.withId(R.id.bottomSheetVerificationRecyclerView)) Espresso.onView(ViewMatchers.withId(R.id.bottomSheetVerificationRecyclerView))
.check(ViewAssertions.matches(ViewMatchers.hasDescendant(ViewMatchers.withText(R.string.verification_request_was_sent)))) .check(ViewAssertions.matches(ViewMatchers.hasDescendant(ViewMatchers.withText(CommonStrings.verification_request_was_sent))))
val txId = runBlockingTest { val txId = runBlockingTest {
otherRequest.await().transactionId otherRequest.await().transactionId
@ -127,7 +128,7 @@ class VerifySessionNavigationTest : VerificationTestBase() {
.perform(waitForView(ViewMatchers.withId(R.id.bottomSheetFragmentContainer))) .perform(waitForView(ViewMatchers.withId(R.id.bottomSheetFragmentContainer)))
Espresso.onView(ViewMatchers.withId(R.id.bottomSheetVerificationRecyclerView)) Espresso.onView(ViewMatchers.withId(R.id.bottomSheetVerificationRecyclerView))
.check(ViewAssertions.matches(ViewMatchers.hasDescendant(ViewMatchers.withText(R.string.verification_verify_with_another_device)))) .check(ViewAssertions.matches(ViewMatchers.hasDescendant(ViewMatchers.withText(CommonStrings.verification_verify_with_another_device))))
runBlockingTest { runBlockingTest {
otherGetCancelledRequest.await() otherGetCancelledRequest.await()

View file

@ -43,6 +43,7 @@ import im.vector.app.features.crypto.recover.Params
import im.vector.app.features.crypto.recover.SetupMode import im.vector.app.features.crypto.recover.SetupMode
import im.vector.app.features.home.HomeActivity import im.vector.app.features.home.HomeActivity
import im.vector.app.ui.robot.AnalyticsRobot import im.vector.app.ui.robot.AnalyticsRobot
import im.vector.lib.strings.CommonStrings
import kotlinx.coroutines.runBlocking import kotlinx.coroutines.runBlocking
import org.junit.Before import org.junit.Before
import org.junit.Ignore import org.junit.Ignore
@ -148,17 +149,17 @@ class VerifySessionPassphraseTest : VerificationTestBase() {
onView(isRoot()) onView(isRoot())
.perform(waitForView(withId(R.id.bottomSheetFragmentContainer))) .perform(waitForView(withId(R.id.bottomSheetFragmentContainer)))
onView(withText(R.string.verification_verify_identity)) onView(withText(CommonStrings.verification_verify_identity))
.check(matches(isDisplayed())) .check(matches(isDisplayed()))
// 4S is setup so passphrase option should be visible // 4S is setup so passphrase option should be visible
onView(withId(R.id.bottomSheetVerificationRecyclerView)) onView(withId(R.id.bottomSheetVerificationRecyclerView))
.check(matches((hasDescendant(withText(R.string.verification_cannot_access_other_session))))) .check(matches((hasDescendant(withText(CommonStrings.verification_cannot_access_other_session)))))
onView(withId(R.id.bottomSheetVerificationRecyclerView)) onView(withId(R.id.bottomSheetVerificationRecyclerView))
.perform( .perform(
actionOnItem<RecyclerView.ViewHolder>( actionOnItem<RecyclerView.ViewHolder>(
hasDescendant(withText(R.string.verification_cannot_access_other_session)), hasDescendant(withText(CommonStrings.verification_cannot_access_other_session)),
click() click()
) )
) )
@ -178,14 +179,14 @@ class VerifySessionPassphraseTest : VerificationTestBase() {
withIdlingResource(activityIdlingResource(HomeActivity::class.java)) { withIdlingResource(activityIdlingResource(HomeActivity::class.java)) {
System.out.println("*** passphrase 1.1") System.out.println("*** passphrase 1.1")
onView(withId(R.id.bottomSheetVerificationRecyclerView)) onView(withId(R.id.bottomSheetVerificationRecyclerView))
.perform(waitForView(hasDescendant(withText(R.string.verification_conclusion_ok_notice)))) .perform(waitForView(hasDescendant(withText(CommonStrings.verification_conclusion_ok_notice))))
} }
// click on done // click on done
onView(withId(R.id.bottomSheetVerificationRecyclerView)) onView(withId(R.id.bottomSheetVerificationRecyclerView))
.perform( .perform(
actionOnItem<RecyclerView.ViewHolder>( actionOnItem<RecyclerView.ViewHolder>(
hasDescendant(withText(R.string.done)), hasDescendant(withText(CommonStrings.done)),
click() click()
) )
) )

View file

@ -30,13 +30,12 @@ import androidx.test.espresso.matcher.ViewMatchers.isFocusable
import androidx.test.espresso.matcher.ViewMatchers.withClassName import androidx.test.espresso.matcher.ViewMatchers.withClassName
import androidx.test.espresso.matcher.ViewMatchers.withId import androidx.test.espresso.matcher.ViewMatchers.withId
import androidx.test.espresso.matcher.ViewMatchers.withText import androidx.test.espresso.matcher.ViewMatchers.withText
import im.vector.app.R
import org.hamcrest.Matchers.allOf import org.hamcrest.Matchers.allOf
import org.hamcrest.Matchers.instanceOf import org.hamcrest.Matchers.instanceOf
import org.hamcrest.Matchers.`is` import org.hamcrest.Matchers.`is`
fun clickOnPreference(@StringRes textResId: Int) { fun clickOnPreference(@StringRes textResId: Int) {
onView(withId(R.id.recycler_view)) onView(withId(androidx.preference.R.id.recycler_view))
.perform( .perform(
actionOnItem<RecyclerView.ViewHolder>( actionOnItem<RecyclerView.ViewHolder>(
allOf( allOf(

View file

@ -23,13 +23,13 @@ import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.LargeTest import androidx.test.filters.LargeTest
import androidx.test.platform.app.InstrumentationRegistry import androidx.test.platform.app.InstrumentationRegistry
import androidx.test.rule.GrantPermissionRule import androidx.test.rule.GrantPermissionRule
import im.vector.app.R
import im.vector.app.espresso.tools.ScreenshotFailureRule import im.vector.app.espresso.tools.ScreenshotFailureRule
import im.vector.app.features.MainActivity import im.vector.app.features.MainActivity
import im.vector.app.getString import im.vector.app.getString
import im.vector.app.ui.robot.ElementRobot import im.vector.app.ui.robot.ElementRobot
import im.vector.app.ui.robot.settings.labs.LabFeaturesPreferences import im.vector.app.ui.robot.settings.labs.LabFeaturesPreferences
import im.vector.app.ui.robot.withDeveloperMode import im.vector.app.ui.robot.withDeveloperMode
import im.vector.lib.strings.CommonStrings
import org.junit.Rule import org.junit.Rule
import org.junit.Test import org.junit.Test
import org.junit.rules.RuleChain import org.junit.rules.RuleChain
@ -55,7 +55,7 @@ class UiAllScreensSanityTest {
InstrumentationRegistry.getInstrumentation() InstrumentationRegistry.getInstrumentation()
.targetContext .targetContext
.resources .resources
.getBoolean(R.bool.settings_labs_new_app_layout_default) .getBoolean(im.vector.app.config.R.bool.settings_labs_new_app_layout_default)
) )
) )
@ -151,7 +151,7 @@ class UiAllScreensSanityTest {
advancedSettings { crawlDeveloperOptions() } advancedSettings { crawlDeveloperOptions() }
} }
roomList { roomList {
openRoom(getString(R.string.room_displayname_empty_room)) { openRoom(getString(CommonStrings.room_displayname_empty_room)) {
val message = "Test view source" val message = "Test view source"
postMessage(message) postMessage(message)
openMessageMenu(message) { openMessageMenu(message) {

View file

@ -23,6 +23,7 @@ import im.vector.app.R
import im.vector.app.espresso.tools.waitUntilActivityVisible import im.vector.app.espresso.tools.waitUntilActivityVisible
import im.vector.app.espresso.tools.waitUntilViewVisible import im.vector.app.espresso.tools.waitUntilViewVisible
import im.vector.app.features.analytics.ui.consent.AnalyticsOptInActivity import im.vector.app.features.analytics.ui.consent.AnalyticsOptInActivity
import im.vector.lib.strings.CommonStrings
class AnalyticsRobot { class AnalyticsRobot {
@ -38,7 +39,7 @@ class AnalyticsRobot {
waitUntilActivityVisible<AnalyticsOptInActivity> { waitUntilActivityVisible<AnalyticsOptInActivity> {
waitUntilViewVisible(withId(R.id.title)) waitUntilViewVisible(withId(R.id.title))
} }
assertDisplayed(R.id.title, R.string.analytics_opt_in_title) assertDisplayed(R.id.title, CommonStrings.analytics_opt_in_title)
if (optIn) { if (optIn) {
clickOn(R.id.submit) clickOn(R.id.submit)
} else { } else {

View file

@ -29,6 +29,7 @@ import im.vector.app.R
import im.vector.app.espresso.tools.waitUntilActivityVisible import im.vector.app.espresso.tools.waitUntilActivityVisible
import im.vector.app.espresso.tools.waitUntilViewVisible import im.vector.app.espresso.tools.waitUntilViewVisible
import im.vector.app.features.home.room.detail.RoomDetailActivity import im.vector.app.features.home.room.detail.RoomDetailActivity
import im.vector.lib.strings.CommonStrings
import org.hamcrest.CoreMatchers.allOf import org.hamcrest.CoreMatchers.allOf
class CreateNewRoomRobot( class CreateNewRoomRobot(
@ -39,7 +40,7 @@ class CreateNewRoomRobot(
createdRoom = true createdRoom = true
BaristaListAssertions.assertListItemCount(R.id.createRoomForm, 12) BaristaListAssertions.assertListItemCount(R.id.createRoomForm, 12)
roomName?.let { roomName?.let {
onView(allOf(withId(R.id.formTextInputTextInputEditText), withHint(R.string.create_room_name_hint))) onView(allOf(withId(R.id.formTextInputTextInputEditText), withHint(CommonStrings.create_room_name_hint)))
.perform(replaceText(roomName)) .perform(replaceText(roomName))
closeSoftKeyboard() closeSoftKeyboard()
} }
@ -53,7 +54,7 @@ class CreateNewRoomRobot(
fun crawl() { fun crawl() {
// Room access bottom sheet // Room access bottom sheet
BaristaClickInteractions.clickOn(R.string.room_settings_room_access_private_title) BaristaClickInteractions.clickOn(CommonStrings.room_settings_room_access_private_title)
pressBack() pressBack()
} }
} }

View file

@ -49,6 +49,7 @@ import im.vector.app.ui.robot.settings.labs.LabFeature
import im.vector.app.ui.robot.settings.labs.LabFeaturesPreferences import im.vector.app.ui.robot.settings.labs.LabFeaturesPreferences
import im.vector.app.ui.robot.space.SpaceRobot import im.vector.app.ui.robot.space.SpaceRobot
import im.vector.app.withIdlingResource import im.vector.app.withIdlingResource
import im.vector.lib.strings.CommonStrings
import timber.log.Timber import timber.log.Timber
class ElementRobot( class ElementRobot(
@ -100,7 +101,7 @@ class ElementRobot(
openActionBarOverflowOrOptionsMenu( openActionBarOverflowOrOptionsMenu(
ApplicationProvider.getApplicationContext() ApplicationProvider.getApplicationContext()
) )
clickOn(R.string.home_layout_preferences) clickOn(CommonStrings.home_layout_preferences)
waitUntilDialogVisible(withId(R.id.home_layout_settings_recents)) waitUntilDialogVisible(withId(R.id.home_layout_settings_recents))
block(LayoutPreferencesRobot()) block(LayoutPreferencesRobot())
@ -149,7 +150,7 @@ class ElementRobot(
LabFeature.THREAD_MESSAGES -> { LabFeature.THREAD_MESSAGES -> {
settings(shouldGoBack = false) { settings(shouldGoBack = false) {
labs(shouldGoBack = false) { labs(shouldGoBack = false) {
onView(withText(R.string.labs_enable_thread_messages)) onView(withText(CommonStrings.labs_enable_thread_messages))
.check(ViewAssertions.matches(isDisplayed())) .check(ViewAssertions.matches(isDisplayed()))
.perform(ViewActions.closeSoftKeyboard(), click()) .perform(ViewActions.closeSoftKeyboard(), click())
} }
@ -185,9 +186,9 @@ class ElementRobot(
onView(withId((R.id.avatar))) onView(withId((R.id.avatar)))
.perform(click()) .perform(click())
waitUntilActivityVisible<VectorSettingsActivity> { waitUntilActivityVisible<VectorSettingsActivity> {
clickOn(R.string.settings_general_title) clickOn(CommonStrings.settings_general_title)
} }
clickOnPreference(R.string.action_sign_out) clickOnPreference(CommonStrings.action_sign_out)
} else { } else {
clickOn(R.id.groupToolbarAvatarImageView) clickOn(R.id.groupToolbarAvatarImageView)
clickOn(R.id.homeDrawerHeaderSignoutView) clickOn(R.id.homeDrawerHeaderSignoutView)

View file

@ -29,6 +29,7 @@ import im.vector.app.espresso.tools.waitUntilViewVisible
import im.vector.app.features.home.room.detail.timeline.edithistory.ViewEditHistoryBottomSheet import im.vector.app.features.home.room.detail.timeline.edithistory.ViewEditHistoryBottomSheet
import im.vector.app.features.reactions.EmojiReactionPickerActivity import im.vector.app.features.reactions.EmojiReactionPickerActivity
import im.vector.app.interactWithSheet import im.vector.app.interactWithSheet
import im.vector.lib.strings.CommonStrings
import java.lang.Thread.sleep import java.lang.Thread.sleep
class MessageMenuRobot( class MessageMenuRobot(
@ -36,7 +37,7 @@ class MessageMenuRobot(
) { ) {
fun viewSource() { fun viewSource() {
clickOn(R.string.view_source) clickOn(CommonStrings.view_source)
// wait for library // wait for library
sleep(1000) sleep(1000)
pressBack() pressBack()
@ -44,8 +45,8 @@ class MessageMenuRobot(
} }
fun editHistory() { fun editHistory() {
clickOn(R.string.message_view_edit_history) clickOn(CommonStrings.message_view_edit_history)
interactWithSheet<ViewEditHistoryBottomSheet>(withText(R.string.message_edits), openState = BottomSheetBehavior.STATE_COLLAPSED) { interactWithSheet<ViewEditHistoryBottomSheet>(withText(CommonStrings.message_edits), openState = BottomSheetBehavior.STATE_COLLAPSED) {
pressBack() pressBack()
} }
autoClosed = true autoClosed = true
@ -57,7 +58,7 @@ class MessageMenuRobot(
} }
fun addReactionFromEmojiPicker() { fun addReactionFromEmojiPicker() {
clickOn(R.string.message_add_reaction) clickOn(CommonStrings.message_add_reaction)
// Wait for emoji to load, it's async now // Wait for emoji to load, it's async now
waitUntilActivityVisible<EmojiReactionPickerActivity> { waitUntilActivityVisible<EmojiReactionPickerActivity> {
closeSoftKeyboard() closeSoftKeyboard()
@ -69,17 +70,17 @@ class MessageMenuRobot(
} }
fun edit() { fun edit() {
clickOn(R.string.edit) clickOn(CommonStrings.edit)
autoClosed = true autoClosed = true
} }
fun replyInThread() { fun replyInThread() {
clickOn(R.string.reply_in_thread) clickOn(CommonStrings.reply_in_thread)
autoClosed = true autoClosed = true
} }
fun viewInRoom() { fun viewInRoom() {
clickOn(R.string.view_in_room) clickOn(CommonStrings.view_in_room)
autoClosed = true autoClosed = true
} }
} }

View file

@ -20,16 +20,17 @@ import androidx.test.espresso.Espresso
import androidx.test.espresso.matcher.ViewMatchers import androidx.test.espresso.matcher.ViewMatchers
import im.vector.app.R import im.vector.app.R
import im.vector.app.waitForView import im.vector.app.waitForView
import im.vector.lib.strings.CommonStrings
class NewDirectMessageRobot { class NewDirectMessageRobot {
fun verifyQrCodeButton() { fun verifyQrCodeButton() {
Espresso.onView(ViewMatchers.withId(R.id.userListRecyclerView)) Espresso.onView(ViewMatchers.withId(R.id.userListRecyclerView))
.perform(waitForView(ViewMatchers.withText(R.string.qr_code))) .perform(waitForView(ViewMatchers.withText(CommonStrings.qr_code)))
} }
fun verifyInviteFriendsButton() { fun verifyInviteFriendsButton() {
Espresso.onView(ViewMatchers.withId(R.id.userListRecyclerView)) Espresso.onView(ViewMatchers.withId(R.id.userListRecyclerView))
.perform(waitForView(ViewMatchers.withText(R.string.invite_friends))) .perform(waitForView(ViewMatchers.withText(CommonStrings.invite_friends)))
} }
} }

View file

@ -24,6 +24,7 @@ import im.vector.app.espresso.tools.waitUntilViewVisible
import im.vector.app.features.DefaultVectorFeatures import im.vector.app.features.DefaultVectorFeatures
import im.vector.app.features.VectorFeatures import im.vector.app.features.VectorFeatures
import im.vector.app.ui.robot.settings.labs.LabFeaturesPreferences import im.vector.app.ui.robot.settings.labs.LabFeaturesPreferences
import im.vector.lib.strings.CommonStrings
class NewRoomRobot( class NewRoomRobot(
var createdRoom: Boolean = false, var createdRoom: Boolean = false,
@ -32,7 +33,7 @@ class NewRoomRobot(
private val features: VectorFeatures = DefaultVectorFeatures() private val features: VectorFeatures = DefaultVectorFeatures()
fun createNewRoom(block: CreateNewRoomRobot.() -> Unit) { fun createNewRoom(block: CreateNewRoomRobot.() -> Unit) {
clickOn(R.string.create_new_room) clickOn(CommonStrings.create_new_room)
waitUntilViewVisible(withId(R.id.createRoomForm)) waitUntilViewVisible(withId(R.id.createRoomForm))
val createNewRoomRobot = CreateNewRoomRobot() val createNewRoomRobot = CreateNewRoomRobot()
block(createNewRoomRobot) block(createNewRoomRobot)

View file

@ -31,6 +31,7 @@ import im.vector.app.R
import im.vector.app.espresso.tools.waitUntilViewVisible import im.vector.app.espresso.tools.waitUntilViewVisible
import im.vector.app.features.DefaultVectorFeatures import im.vector.app.features.DefaultVectorFeatures
import im.vector.app.waitForView import im.vector.app.waitForView
import im.vector.lib.strings.CommonStrings
class OnboardingRobot { class OnboardingRobot {
private val defaultVectorFeatures = DefaultVectorFeatures() private val defaultVectorFeatures = DefaultVectorFeatures()
@ -46,7 +47,7 @@ class OnboardingRobot {
// TODO https://github.com/element-hq/element-android/issues/6652 // TODO https://github.com/element-hq/element-android/issues/6652
} else { } else {
clickOn(R.id.loginSplashSubmit) clickOn(R.id.loginSplashSubmit)
assertDisplayed(R.id.useCaseHeaderTitle, R.string.ftue_auth_use_case_title) assertDisplayed(R.id.useCaseHeaderTitle, CommonStrings.ftue_auth_use_case_title)
clickOn(R.id.useCaseOptionOne) clickOn(R.id.useCaseOptionOne)
OnboardingServersRobot().crawlSignUp() OnboardingServersRobot().crawlSignUp()
pressBack() pressBack()
@ -71,27 +72,27 @@ class OnboardingRobot {
initSession(true, userId, password, homeServerUrl) initSession(true, userId, password, homeServerUrl)
} }
waitUntilViewVisible(withText(R.string.ftue_account_created_congratulations_title)) waitUntilViewVisible(withText(CommonStrings.ftue_account_created_congratulations_title))
if (defaultVectorFeatures.isOnboardingPersonalizeEnabled()) { if (defaultVectorFeatures.isOnboardingPersonalizeEnabled()) {
clickOn(R.string.ftue_account_created_personalize) clickOn(CommonStrings.ftue_account_created_personalize)
waitUntilViewVisible(withText(R.string.ftue_display_name_title)) waitUntilViewVisible(withText(CommonStrings.ftue_display_name_title))
writeTo(R.id.displayNameInput, "UI automation") writeTo(R.id.displayNameInput, "UI automation")
clickOn(R.string.ftue_personalize_submit) clickOn(CommonStrings.ftue_personalize_submit)
waitUntilViewVisible(withText(R.string.ftue_profile_picture_title)) waitUntilViewVisible(withText(CommonStrings.ftue_profile_picture_title))
clickOn(R.string.ftue_personalize_skip_this_step) clickOn(CommonStrings.ftue_personalize_skip_this_step)
waitUntilViewVisible(withText(R.string.ftue_personalize_complete_title)) waitUntilViewVisible(withText(CommonStrings.ftue_personalize_complete_title))
clickOn(R.string.ftue_personalize_lets_go) clickOn(CommonStrings.ftue_personalize_lets_go)
} else { } else {
clickOn(R.string.ftue_account_created_take_me_home) clickOn(CommonStrings.ftue_account_created_take_me_home)
} }
} }
private fun createAccountViaCombinedRegister(homeServerUrl: String, userId: String, password: String) { private fun createAccountViaCombinedRegister(homeServerUrl: String, userId: String, password: String) {
waitUntilViewVisible(withId(R.id.loginSplashSubmit)) waitUntilViewVisible(withId(R.id.loginSplashSubmit))
assertDisplayed(R.id.loginSplashSubmit, R.string.login_splash_create_account) assertDisplayed(R.id.loginSplashSubmit, CommonStrings.login_splash_create_account)
clickOn(R.id.loginSplashSubmit) clickOn(R.id.loginSplashSubmit)
clickOn(R.id.useCaseOptionOne) clickOn(R.id.useCaseOptionOne)
@ -117,7 +118,7 @@ class OnboardingRobot {
private fun loginViaCombinedLogin(homeServerUrl: String, userId: String, password: String) { private fun loginViaCombinedLogin(homeServerUrl: String, userId: String, password: String) {
waitUntilViewVisible(withId(R.id.loginSplashSubmit)) waitUntilViewVisible(withId(R.id.loginSplashSubmit))
assertDisplayed(R.id.loginSplashSubmit, R.string.login_splash_create_account) assertDisplayed(R.id.loginSplashSubmit, CommonStrings.login_splash_create_account)
clickOn(R.id.loginSplashAlreadyHaveAccount) clickOn(R.id.loginSplashAlreadyHaveAccount)
waitUntilViewVisible(withId(R.id.loginRoot)) waitUntilViewVisible(withId(R.id.loginRoot))
@ -139,14 +140,14 @@ class OnboardingRobot {
homeServerUrl: String homeServerUrl: String
) { ) {
waitUntilViewVisible(withId(R.id.loginSplashSubmit)) waitUntilViewVisible(withId(R.id.loginSplashSubmit))
assertDisplayed(R.id.loginSplashSubmit, R.string.login_splash_create_account) assertDisplayed(R.id.loginSplashSubmit, CommonStrings.login_splash_create_account)
if (createAccount) { if (createAccount) {
clickOn(R.id.loginSplashSubmit) clickOn(R.id.loginSplashSubmit)
clickOn(R.id.useCaseOptionOne) clickOn(R.id.useCaseOptionOne)
} else { } else {
clickOn(R.id.loginSplashAlreadyHaveAccount) clickOn(R.id.loginSplashAlreadyHaveAccount)
} }
assertDisplayed(R.id.loginServerTitle, R.string.login_server_title) assertDisplayed(R.id.loginServerTitle, CommonStrings.login_server_title)
// Chose custom server // Chose custom server
clickOn(R.id.loginServerChoiceOther) clickOn(R.id.loginServerChoiceOther)
// Enter local synapse // Enter local synapse

View file

@ -23,11 +23,12 @@ import com.adevinta.android.barista.interaction.BaristaClickInteractions
import com.adevinta.android.barista.interaction.BaristaEditTextInteractions import com.adevinta.android.barista.interaction.BaristaEditTextInteractions
import im.vector.app.R import im.vector.app.R
import im.vector.app.espresso.tools.waitUntilViewVisible import im.vector.app.espresso.tools.waitUntilViewVisible
import im.vector.lib.strings.CommonStrings
class OnboardingServersRobot { class OnboardingServersRobot {
fun crawlSignUp() { fun crawlSignUp() {
BaristaVisibilityAssertions.assertDisplayed(R.id.loginServerTitle, R.string.login_server_title) BaristaVisibilityAssertions.assertDisplayed(R.id.loginServerTitle, CommonStrings.login_server_title)
crawlMatrixServer(isSignUp = true) crawlMatrixServer(isSignUp = true)
crawlEmsServer() crawlEmsServer()
crawlOtherServer(isSignUp = true) crawlOtherServer(isSignUp = true)
@ -35,7 +36,7 @@ class OnboardingServersRobot {
} }
fun crawlSignIn() { fun crawlSignIn() {
BaristaVisibilityAssertions.assertDisplayed(R.id.loginServerTitle, R.string.login_server_title) BaristaVisibilityAssertions.assertDisplayed(R.id.loginServerTitle, CommonStrings.login_server_title)
crawlMatrixServer(isSignUp = false) crawlMatrixServer(isSignUp = false)
crawlEmsServer() crawlEmsServer()
crawlOtherServer(isSignUp = false) crawlOtherServer(isSignUp = false)
@ -49,7 +50,7 @@ class OnboardingServersRobot {
BaristaClickInteractions.clickOn(R.id.loginServerUrlFormSubmit) BaristaClickInteractions.clickOn(R.id.loginServerUrlFormSubmit)
waitUntilViewVisible(ViewMatchers.withId(R.id.loginSignupSigninTitle)) waitUntilViewVisible(ViewMatchers.withId(R.id.loginSignupSigninTitle))
BaristaVisibilityAssertions.assertDisplayed(R.id.loginSignupSigninText, "Connect to chat.mozilla.org") BaristaVisibilityAssertions.assertDisplayed(R.id.loginSignupSigninText, "Connect to chat.mozilla.org")
BaristaVisibilityAssertions.assertDisplayed(R.id.loginSignupSigninSubmit, R.string.login_signin_sso) BaristaVisibilityAssertions.assertDisplayed(R.id.loginSignupSigninSubmit, CommonStrings.login_signin_sso)
Espresso.pressBack() Espresso.pressBack()
BaristaEditTextInteractions.writeTo(R.id.loginServerUrlFormHomeServerUrl, "https://matrix.org") BaristaEditTextInteractions.writeTo(R.id.loginServerUrlFormHomeServerUrl, "https://matrix.org")
@ -62,14 +63,14 @@ class OnboardingServersRobot {
private fun crawlEmsServer() { private fun crawlEmsServer() {
BaristaClickInteractions.clickOn(R.id.loginServerChoiceEms) BaristaClickInteractions.clickOn(R.id.loginServerChoiceEms)
waitUntilViewVisible(ViewMatchers.withId(R.id.loginServerUrlFormTitle)) waitUntilViewVisible(ViewMatchers.withId(R.id.loginServerUrlFormTitle))
BaristaVisibilityAssertions.assertDisplayed(R.id.loginServerUrlFormTitle, R.string.login_connect_to_modular) BaristaVisibilityAssertions.assertDisplayed(R.id.loginServerUrlFormTitle, CommonStrings.login_connect_to_modular)
BaristaEditTextInteractions.writeTo(R.id.loginServerUrlFormHomeServerUrl, "https://one.ems.host") BaristaEditTextInteractions.writeTo(R.id.loginServerUrlFormHomeServerUrl, "https://one.ems.host")
BaristaClickInteractions.clickOn(R.id.loginServerUrlFormSubmit) BaristaClickInteractions.clickOn(R.id.loginServerUrlFormSubmit)
waitUntilViewVisible(ViewMatchers.withId(R.id.loginSignupSigninTitle)) waitUntilViewVisible(ViewMatchers.withId(R.id.loginSignupSigninTitle))
BaristaVisibilityAssertions.assertDisplayed(R.id.loginSignupSigninText, "one.ems.host") BaristaVisibilityAssertions.assertDisplayed(R.id.loginSignupSigninText, "one.ems.host")
BaristaVisibilityAssertions.assertDisplayed(R.id.loginSignupSigninSubmit, R.string.login_signin_sso) BaristaVisibilityAssertions.assertDisplayed(R.id.loginSignupSigninSubmit, CommonStrings.login_signin_sso)
Espresso.pressBack() Espresso.pressBack()
Espresso.pressBack() Espresso.pressBack()
} }
@ -91,7 +92,7 @@ class OnboardingServersRobot {
private fun crawlSignInWithMatrixId() { private fun crawlSignInWithMatrixId() {
BaristaClickInteractions.clickOn(R.id.loginServerIKnowMyIdSubmit) BaristaClickInteractions.clickOn(R.id.loginServerIKnowMyIdSubmit)
waitUntilViewVisible(ViewMatchers.withId(R.id.loginTitle)) waitUntilViewVisible(ViewMatchers.withId(R.id.loginTitle))
BaristaVisibilityAssertions.assertDisplayed(R.id.loginTitle, R.string.login_signin_matrix_id_title) BaristaVisibilityAssertions.assertDisplayed(R.id.loginTitle, CommonStrings.login_signin_matrix_id_title)
Espresso.pressBack() Espresso.pressBack()
} }
} }

View file

@ -39,6 +39,7 @@ import im.vector.app.features.home.room.detail.timeline.reactions.ViewReactionsB
import im.vector.app.features.reactions.data.EmojiDataSource import im.vector.app.features.reactions.data.EmojiDataSource
import im.vector.app.interactWithSheet import im.vector.app.interactWithSheet
import im.vector.app.withRetry import im.vector.app.withRetry
import im.vector.lib.strings.CommonStrings
import java.lang.Thread.sleep import java.lang.Thread.sleep
class RoomDetailRobot { class RoomDetailRobot {
@ -93,7 +94,7 @@ class RoomDetailRobot {
// Open reactions // Open reactions
longClickReaction(quickReaction) longClickReaction(quickReaction)
// wait for bottom sheet // wait for bottom sheet
interactWithSheet<ViewReactionsBottomSheet>(withText(R.string.reactions), openState = BottomSheetBehavior.STATE_COLLAPSED) { interactWithSheet<ViewReactionsBottomSheet>(withText(CommonStrings.reactions), openState = BottomSheetBehavior.STATE_COLLAPSED) {
pressBack() pressBack()
} }
println("Room Detail Robot: Open reaction from emoji picker") println("Room Detail Robot: Open reaction from emoji picker")

View file

@ -36,6 +36,7 @@ import im.vector.app.features.home.room.list.home.header.HomeRoomFilter
import im.vector.app.features.roomdirectory.RoomDirectoryActivity import im.vector.app.features.roomdirectory.RoomDirectoryActivity
import im.vector.app.ui.robot.settings.labs.LabFeaturesPreferences import im.vector.app.ui.robot.settings.labs.LabFeaturesPreferences
import im.vector.app.waitForView import im.vector.app.waitForView
import im.vector.lib.strings.CommonStrings
class RoomListRobot(private val labsPreferences: LabFeaturesPreferences) { class RoomListRobot(private val labsPreferences: LabFeaturesPreferences) {
@ -55,7 +56,7 @@ class RoomListRobot(private val labsPreferences: LabFeaturesPreferences) {
onView(withId(R.id.roomListView)) onView(withId(R.id.roomListView))
.perform( .perform(
RecyclerViewActions.actionOnItem<RecyclerView.ViewHolder>( RecyclerViewActions.actionOnItem<RecyclerView.ViewHolder>(
hasDescendant(withText(R.string.room_displayname_empty_room)), hasDescendant(withText(CommonStrings.room_displayname_empty_room)),
ViewActions.longClick() ViewActions.longClick()
) )
) )

View file

@ -29,6 +29,7 @@ import im.vector.app.espresso.tools.waitUntilActivityVisible
import im.vector.app.espresso.tools.waitUntilDialogVisible import im.vector.app.espresso.tools.waitUntilDialogVisible
import im.vector.app.espresso.tools.waitUntilViewVisible import im.vector.app.espresso.tools.waitUntilViewVisible
import im.vector.app.features.roommemberprofile.RoomMemberProfileActivity import im.vector.app.features.roommemberprofile.RoomMemberProfileActivity
import im.vector.lib.strings.CommonStrings
class RoomSettingsRobot { class RoomSettingsRobot {
@ -58,8 +59,8 @@ class RoomSettingsRobot {
// Uploads // Uploads
clickListItem(R.id.matrixProfileRecyclerView, 10) clickListItem(R.id.matrixProfileRecyclerView, 10)
// File tab // File tab
clickOn(R.string.uploads_files_title) clickOn(CommonStrings.uploads_files_title)
waitUntilViewVisible(withText(R.string.uploads_media_title)) waitUntilViewVisible(withText(CommonStrings.uploads_media_title))
pressBack() pressBack()
waitUntilViewVisible(withId(R.id.matrixProfileRecyclerView)) waitUntilViewVisible(withId(R.id.matrixProfileRecyclerView))
@ -74,19 +75,19 @@ class RoomSettingsRobot {
// Room addresses // Room addresses
clickListItem(R.id.matrixProfileRecyclerView, 16) clickListItem(R.id.matrixProfileRecyclerView, 16)
waitUntilViewVisible(withText(R.string.room_alias_published_alias_title)) waitUntilViewVisible(withText(CommonStrings.room_alias_published_alias_title))
pressBack() pressBack()
// Room permissions // Room permissions
clickListItem(R.id.matrixProfileRecyclerView, 18) clickListItem(R.id.matrixProfileRecyclerView, 18)
waitUntilViewVisible(withText(R.string.room_permissions_change_room_avatar)) waitUntilViewVisible(withText(CommonStrings.room_permissions_change_room_avatar))
clickOn(R.string.room_permissions_change_room_avatar) clickOn(CommonStrings.room_permissions_change_room_avatar)
waitUntilDialogVisible(withId(android.R.id.button2)) waitUntilDialogVisible(withId(android.R.id.button2))
clickDialogNegativeButton() clickDialogNegativeButton()
waitUntilViewVisible(withText(R.string.room_permissions_title)) waitUntilViewVisible(withText(CommonStrings.room_permissions_title))
// Toggle // Toggle
clickOn(R.string.show_advanced) clickOn(CommonStrings.show_advanced)
clickOn(R.string.hide_advanced) clickOn(CommonStrings.hide_advanced)
pressBack() pressBack()
// Menu share // Menu share

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