From fa05b18d323bb236eacea7e6a19b161a4c4e9f54 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Thu, 11 Jan 2024 20:45:22 +0100 Subject: [PATCH 001/127] Create gplay and fdroid variant --- app/build.gradle.kts | 21 ++++++++++++++++--- .../io/element/android/x/di/AppModule.kt | 6 ++---- .../main/kotlin/extension/KoverExtension.kt | 6 +++--- .../android/samples/minimal/Singleton.kt | 6 ++---- 4 files changed, 25 insertions(+), 14 deletions(-) diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 543a414091..05f7bdf139 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -69,7 +69,7 @@ android { } signingConfigs { - named("debug") { + getByName("debug") { keyAlias = "androiddebugkey" keyPassword = "android" storeFile = file("./signature/debug.keystore") @@ -87,13 +87,13 @@ android { } buildTypes { - named("debug") { + getByName("debug") { resValue("string", "app_name", "Element X dbg") applicationIdSuffix = ".debug" signingConfig = signingConfigs.getByName("debug") } - named("release") { + getByName("release") { resValue("string", "app_name", "Element X") signingConfig = signingConfigs.getByName("debug") @@ -143,6 +143,21 @@ android { buildFeatures { buildConfig = true } + flavorDimensions += "store" + productFlavors { + create("gplay") { + dimension = "store" + isDefault = true + buildConfigField("String", "SHORT_FLAVOR_DESCRIPTION", "\"G\"") + buildConfigField("String", "FLAVOR_DESCRIPTION", "\"GooglePlay\"") + + } + create("fdroid") { + dimension = "store" + buildConfigField("String", "SHORT_FLAVOR_DESCRIPTION", "\"F\"") + buildConfigField("String", "FLAVOR_DESCRIPTION", "\"FDroid\"") + } + } } androidComponents { diff --git a/app/src/main/kotlin/io/element/android/x/di/AppModule.kt b/app/src/main/kotlin/io/element/android/x/di/AppModule.kt index 995dcf61e5..bf4880b372 100644 --- a/app/src/main/kotlin/io/element/android/x/di/AppModule.kt +++ b/app/src/main/kotlin/io/element/android/x/di/AppModule.kt @@ -91,10 +91,8 @@ object AppModule { gitRevisionDate = "TODO", // BuildConfig.GIT_BRANCH_NAME, gitBranchName = "TODO", - // BuildConfig.FLAVOR_DESCRIPTION, - flavorDescription = "TODO", - // BuildConfig.SHORT_FLAVOR_DESCRIPTION, - flavorShortDescription = "TODO", + flavorDescription = BuildConfig.FLAVOR_DESCRIPTION, + flavorShortDescription = BuildConfig.SHORT_FLAVOR_DESCRIPTION, ) @Provides diff --git a/plugins/src/main/kotlin/extension/KoverExtension.kt b/plugins/src/main/kotlin/extension/KoverExtension.kt index 42b7a5bc1f..9185bfb1b0 100644 --- a/plugins/src/main/kotlin/extension/KoverExtension.kt +++ b/plugins/src/main/kotlin/extension/KoverExtension.kt @@ -97,8 +97,8 @@ fun Project.setupKover() { defaults { // add reports of both 'debug' and 'release' Android build variants to default reports - mergeWith("debug") - mergeWith("release") + mergeWith("gplayDebug") + mergeWith("gplayRelease") verify { onCheck = true @@ -202,7 +202,7 @@ fun Project.setupKover() { } } - androidReports("release") {} + androidReports("gplayRelease") {} } } diff --git a/samples/minimal/src/main/kotlin/io/element/android/samples/minimal/Singleton.kt b/samples/minimal/src/main/kotlin/io/element/android/samples/minimal/Singleton.kt index cc54fd051f..fc8fe81d8a 100644 --- a/samples/minimal/src/main/kotlin/io/element/android/samples/minimal/Singleton.kt +++ b/samples/minimal/src/main/kotlin/io/element/android/samples/minimal/Singleton.kt @@ -43,10 +43,8 @@ object Singleton { gitRevisionDate = "TODO", // BuildConfig.GIT_BRANCH_NAME, gitBranchName = "TODO", - // BuildConfig.FLAVOR_DESCRIPTION, - flavorDescription = "TODO", - // BuildConfig.SHORT_FLAVOR_DESCRIPTION, - flavorShortDescription = "TODO", + flavorDescription = "NA", + flavorShortDescription = "NA", ) init { From db6b52f8bfef5b3aa19fe874d745f7d19ccfffc0 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Thu, 11 Jan 2024 21:02:26 +0100 Subject: [PATCH 002/127] Update gradle tasks and paths regarding the new gplay and fdroid flavor. --- .github/workflows/build.yml | 6 +++--- .github/workflows/maestro.yml | 2 +- .github/workflows/nightly.yml | 2 +- .github/workflows/release.yml | 6 +++--- app/build.gradle.kts | 2 +- tools/release/release.sh | 6 +++--- 6 files changed, 12 insertions(+), 12 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index e220ec76e4..c93d1a2ab0 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -47,14 +47,14 @@ jobs: ELEMENT_ANDROID_MAPTILER_API_KEY: ${{ secrets.MAPTILER_KEY }} ELEMENT_ANDROID_MAPTILER_LIGHT_MAP_ID: ${{ secrets.MAPTILER_LIGHT_MAP_ID }} ELEMENT_ANDROID_MAPTILER_DARK_MAP_ID: ${{ secrets.MAPTILER_DARK_MAP_ID }} - run: ./gradlew :app:assembleDebug -PallWarningsAsErrors=true $CI_GRADLE_ARG_PROPERTIES + run: ./gradlew :app:assembleGplayDebug :app:assembleFDroidDebug -PallWarningsAsErrors=true $CI_GRADLE_ARG_PROPERTIES - name: Upload APK APKs if: ${{ matrix.variant == 'debug' }} uses: actions/upload-artifact@v4 with: name: elementx-debug path: | - app/build/outputs/apk/debug/*.apk + app/build/outputs/apk/gplay/debug/*.apk - uses: rnkdsh/action-upload-diawi@v1.5.4 id: diawi # Do not fail the whole build if Diawi upload fails @@ -64,7 +64,7 @@ jobs: if: ${{ matrix.variant == 'debug' && github.event_name == 'pull_request' && env.token != '' }} with: token: ${{ env.token }} - file: app/build/outputs/apk/debug/app-arm64-v8a-debug.apk + file: app/build/outputs/apk/gplay/debug/app-gplay-arm64-v8a-debug.apk - name: Add or update PR comment with QR Code to download APK. if: ${{ matrix.variant == 'debug' && github.event_name == 'pull_request' && steps.diawi.conclusion == 'success' }} uses: NejcZdovc/comment-pr@v2 diff --git a/.github/workflows/maestro.yml b/.github/workflows/maestro.yml index 0e2dc74b92..c6d4c44d80 100644 --- a/.github/workflows/maestro.yml +++ b/.github/workflows/maestro.yml @@ -53,7 +53,7 @@ jobs: api-key: ${{ secrets.MAESTRO_CLOUD_API_KEY }} # Doc says (https://github.com/mobile-dev-inc/action-maestro-cloud#android): # app-file should point to an x86 compatible APK file, so upload the x86_64 one (much smaller than the universal APK). - app-file: app/build/outputs/apk/debug/app-x86_64-debug.apk + app-file: app/build/outputs/apk/gplay/debug/app-gplay-x86_64-debug.apk env: | USERNAME=maestroelement PASSWORD=${{ secrets.MATRIX_MAESTRO_ACCOUNT_PASSWORD }} diff --git a/.github/workflows/nightly.yml b/.github/workflows/nightly.yml index 91976f56a0..b1e9dddde9 100644 --- a/.github/workflows/nightly.yml +++ b/.github/workflows/nightly.yml @@ -45,7 +45,7 @@ jobs: - name: Additionally upload Nightly APK to browserstack for testing continue-on-error: true # don't block anything by this upload failing (for now) run: | - curl -u "$BROWSERSTACK_USERNAME:$BROWSERSTACK_PASSWORD" -X POST "https://api-cloud.browserstack.com/app-automate/upload" -F "file=@app/build/outputs/apk/nightly/app-universal-nightly.apk" -F "custom_id=element-x-android-nightly" + curl -u "$BROWSERSTACK_USERNAME:$BROWSERSTACK_PASSWORD" -X POST "https://api-cloud.browserstack.com/app-automate/upload" -F "file=@app/build/outputs/apk/gplay/nightly/app-gplay-universal-nightly.apk" -F "custom_id=element-x-android-nightly" env: BROWSERSTACK_USERNAME: ${{ secrets.ELEMENT_ANDROID_BROWSERSTACK_USERNAME }} BROWSERSTACK_PASSWORD: ${{ secrets.ELEMENT_ANDROID_BROWSERSTACK_ACCESS_KEY }} diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 59b5f60cec..97e3634a6a 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -31,10 +31,10 @@ jobs: ELEMENT_ANDROID_MAPTILER_API_KEY: ${{ secrets.MAPTILER_KEY }} ELEMENT_ANDROID_MAPTILER_LIGHT_MAP_ID: ${{ secrets.MAPTILER_LIGHT_MAP_ID }} ELEMENT_ANDROID_MAPTILER_DARK_MAP_ID: ${{ secrets.MAPTILER_DARK_MAP_ID }} - run: ./gradlew bundleRelease $CI_GRADLE_ARG_PROPERTIES + run: ./gradlew bundleGplayRelease $CI_GRADLE_ARG_PROPERTIES - name: Upload bundle as artifact uses: actions/upload-artifact@v4 with: - name: elementx-app-bundle-unsigned + name: elementx-app-gplay-bundle-unsigned path: | - app/build/outputs/bundle/release/app-release.aab + app/build/outputs/bundle/gplayRelease/app-gplay-release.aab diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 05f7bdf139..c5918bfef7 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -124,7 +124,7 @@ android { // We upload the universal APK to fix this error: // "App Distribution found more than 1 output file for this variant. // Please contact firebase-support@google.com for help using APK splits with App Distribution." - artifactPath = "$rootDir/app/build/outputs/apk/nightly/app-universal-nightly.apk" + artifactPath = "$rootDir/app/build/outputs/apk/gplay/nightly/app-gplay-universal-nightly.apk" // artifactType = "AAB" // artifactPath = "$rootDir/app/build/outputs/bundle/nightly/app-nightly.aab" // This file will be generated by the GitHub action diff --git a/tools/release/release.sh b/tools/release/release.sh index 26a94cb09e..f793ac2a4e 100755 --- a/tools/release/release.sh +++ b/tools/release/release.sh @@ -143,7 +143,7 @@ git commit -a -m "Setting version for the release ${version}" printf "\n================================================================================\n" printf "Building the bundle locally first...\n" -./gradlew clean app:bundleRelease +./gradlew clean app:bundleGplayRelease printf "\n================================================================================\n" printf "Running towncrier...\n" @@ -218,7 +218,7 @@ fi printf "\n================================================================================\n" printf "Wait for the GitHub action https://github.com/element-hq/element-x-android/actions/workflows/release.yml?query=branch%%3Amain to build the 'main' branch.\n" -read -p "After GHA is finished, please enter the artifact URL (for 'elementx-app-bundle-unsigned'): " artifactUrl +read -p "After GHA is finished, please enter the artifact URL (for 'elementx-app-gplay-bundle-unsigned'): " artifactUrl printf "\n================================================================================\n" printf "Downloading the artifact...\n" @@ -235,7 +235,7 @@ python3 ./tools/github/download_github_artifacts.py \ printf "\n================================================================================\n" printf "Unzipping the artifact...\n" -unzip ${targetPath}/elementx-app-bundle-unsigned.zip -d ${targetPath} +unzip ${targetPath}/elementx-app-gplay-bundle-unsigned.zip -d ${targetPath} unsignedBundlePath="${targetPath}/app-release.aab" signedBundlePath="${targetPath}/app-release-signed.aab" From 31fe516a49901642b04348f30b482bd444053e8e Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Thu, 11 Jan 2024 21:25:14 +0100 Subject: [PATCH 003/127] Ensure that FDroid build will not include Firebase push provider. `allLibrariesImpl()` is also used by the midule uitest, and in this case `gplayImplementation` cannot be found. Since the push provider modules do not contain any ui, it's fine to move the dependency declaration to the app module. --- app/build.gradle.kts | 5 +++++ plugins/src/main/kotlin/extension/DependencyHandleScope.kt | 4 ---- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/app/build.gradle.kts b/app/build.gradle.kts index c5918bfef7..e7fd35b08f 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -237,6 +237,11 @@ dependencies { implementation(projects.appconfig) anvil(projects.anvilcodegen) + // Comment to not include firebase in the project + "gplayImplementation"(projects.libraries.pushproviders.firebase) + // Comment to not include unified push in the project + implementation(projects.libraries.pushproviders.unifiedpush) + implementation(libs.appyx.core) implementation(libs.androidx.splash) implementation(libs.androidx.core) diff --git a/plugins/src/main/kotlin/extension/DependencyHandleScope.kt b/plugins/src/main/kotlin/extension/DependencyHandleScope.kt index 625d2cf7dc..caa928c51d 100644 --- a/plugins/src/main/kotlin/extension/DependencyHandleScope.kt +++ b/plugins/src/main/kotlin/extension/DependencyHandleScope.kt @@ -87,10 +87,6 @@ fun DependencyHandlerScope.allLibrariesImpl() { implementation(project(":libraries:permissions:impl")) implementation(project(":libraries:push:impl")) implementation(project(":libraries:push:impl")) - // Comment to not include firebase in the project - implementation(project(":libraries:pushproviders:firebase")) - // Comment to not include unified push in the project - implementation(project(":libraries:pushproviders:unifiedpush")) implementation(project(":libraries:featureflag:impl")) implementation(project(":libraries:pushstore:impl")) implementation(project(":libraries:preferences:impl")) From 4286be7cfb4ce8f6c55b28de9ecfc97ad3ab9166 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Thu, 11 Jan 2024 21:33:08 +0100 Subject: [PATCH 004/127] Add fdroid of gplay to the rageshake data as a label. --- .../features/rageshake/impl/reporter/DefaultBugReporter.kt | 1 + 1 file changed, 1 insertion(+) diff --git a/features/rageshake/impl/src/main/kotlin/io/element/android/features/rageshake/impl/reporter/DefaultBugReporter.kt b/features/rageshake/impl/src/main/kotlin/io/element/android/features/rageshake/impl/reporter/DefaultBugReporter.kt index 2fc834086a..2123717f8e 100755 --- a/features/rageshake/impl/src/main/kotlin/io/element/android/features/rageshake/impl/reporter/DefaultBugReporter.kt +++ b/features/rageshake/impl/src/main/kotlin/io/element/android/features/rageshake/impl/reporter/DefaultBugReporter.kt @@ -199,6 +199,7 @@ class DefaultBugReporter @Inject constructor( // add some github labels builder.addFormDataPart("label", buildMeta.versionName) + builder.addFormDataPart("label", buildMeta.flavorDescription) if (crashCallStack.isNotEmpty() && withCrashLogs) { builder.addFormDataPart("label", "crash") } From a455a03a0f0a6b909bc69d2895c081446d49b1e8 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Thu, 11 Jan 2024 21:38:11 +0100 Subject: [PATCH 005/127] Also export fdroid build as artifact. --- .github/workflows/build.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index c93d1a2ab0..e25784de00 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -55,6 +55,7 @@ jobs: name: elementx-debug path: | app/build/outputs/apk/gplay/debug/*.apk + app/build/outputs/apk/fdroid/debug/*.apk - uses: rnkdsh/action-upload-diawi@v1.5.4 id: diawi # Do not fail the whole build if Diawi upload fails From df9f6a980928a0cd527d9292fe64830f1b7fb879 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Thu, 11 Jan 2024 21:38:48 +0100 Subject: [PATCH 006/127] Cleanup --- app/build.gradle.kts | 1 - 1 file changed, 1 deletion(-) diff --git a/app/build.gradle.kts b/app/build.gradle.kts index e7fd35b08f..35de2038c0 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -150,7 +150,6 @@ android { isDefault = true buildConfigField("String", "SHORT_FLAVOR_DESCRIPTION", "\"G\"") buildConfigField("String", "FLAVOR_DESCRIPTION", "\"GooglePlay\"") - } create("fdroid") { dimension = "store" From 55db8fb200a6012fd0e5e9478aaa2a342913e610 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Thu, 11 Jan 2024 22:03:34 +0100 Subject: [PATCH 007/127] Only call setupKover() for the app, not for minimal. minimal does not have the gplay variant. --- app/build.gradle.kts | 5 +++++ .../kotlin/io.element.android-compose-application.gradle.kts | 5 ----- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 35de2038c0..e977af4c86 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -20,6 +20,8 @@ import com.android.build.api.variant.FilterConfiguration.FilterType.ABI import extension.allFeaturesImpl import extension.allLibrariesImpl import extension.allServicesImpl +import extension.koverDependencies +import extension.setupKover import org.jetbrains.kotlin.cli.common.toBooleanLenient plugins { @@ -36,6 +38,8 @@ plugins { // id("com.google.gms.google-services") } +setupKover() + android { namespace = "io.element.android.x" @@ -270,4 +274,5 @@ dependencies { testImplementation(projects.libraries.matrix.test) ksp(libs.showkase.processor) + koverDependencies() } diff --git a/plugins/src/main/kotlin/io.element.android-compose-application.gradle.kts b/plugins/src/main/kotlin/io.element.android-compose-application.gradle.kts index 015f0d4db8..2ac8fb8b72 100644 --- a/plugins/src/main/kotlin/io.element.android-compose-application.gradle.kts +++ b/plugins/src/main/kotlin/io.element.android-compose-application.gradle.kts @@ -17,12 +17,10 @@ /** * This will generate the plugin "io.element.android-compose-application" to use by app and samples modules */ -import extension.koverDependencies import extension.androidConfig import extension.commonDependencies import extension.composeConfig import extension.composeDependencies -import extension.setupKover import org.gradle.accessors.dm.LibrariesForLibs val libs = the() @@ -32,8 +30,6 @@ plugins { id("com.autonomousapps.dependency-analysis") } -setupKover() - android { androidConfig(project) composeConfig(libs) @@ -46,5 +42,4 @@ dependencies { commonDependencies(libs) composeDependencies(libs) coreLibraryDesugaring(libs.android.desugar) - koverDependencies() } From e0d4ece5b7d35e9ea6b66912b56f0266de755b16 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Thu, 11 Jan 2024 22:19:43 +0100 Subject: [PATCH 008/127] Fix gradle task ambiguity. --- .github/workflows/build.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index e25784de00..dd138f8e67 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -83,7 +83,7 @@ jobs: run: ./gradlew compileReleaseSources -PallWarningsAsErrors=true $CI_GRADLE_ARG_PROPERTIES - name: Compile nightly sources if: ${{ matrix.variant == 'nightly' }} - run: ./gradlew compileNightlySources -PallWarningsAsErrors=true $CI_GRADLE_ARG_PROPERTIES + run: ./gradlew compileGplayNightlySources -PallWarningsAsErrors=true $CI_GRADLE_ARG_PROPERTIES - name: Compile samples minimal if: ${{ matrix.variant == 'samples' }} run: ./gradlew :samples:minimal:assemble $CI_GRADLE_ARG_PROPERTIES From 1ab10a9e64eb4eaee5849d1cc004296f7cb55c83 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Fri, 12 Jan 2024 09:16:50 +0100 Subject: [PATCH 009/127] var -> val --- .../rageshake/impl/reporter/DefaultBugReporterTest.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/features/rageshake/impl/src/test/kotlin/io/element/android/features/rageshake/impl/reporter/DefaultBugReporterTest.kt b/features/rageshake/impl/src/test/kotlin/io/element/android/features/rageshake/impl/reporter/DefaultBugReporterTest.kt index 44e085c569..da25571266 100755 --- a/features/rageshake/impl/src/test/kotlin/io/element/android/features/rageshake/impl/reporter/DefaultBugReporterTest.kt +++ b/features/rageshake/impl/src/test/kotlin/io/element/android/features/rageshake/impl/reporter/DefaultBugReporterTest.kt @@ -48,7 +48,7 @@ class DefaultBugReporterTest { val sut = createDefaultBugReporter(server) var onUploadCancelledCalled = false var onUploadFailedCalled = false - var progressValues = mutableListOf() + val progressValues = mutableListOf() var onUploadSucceedCalled = false sut.sendBugReport( withDevicesLogs = true, @@ -97,7 +97,7 @@ class DefaultBugReporterTest { var onUploadCancelledCalled = false var onUploadFailedCalled = false var onUploadFailedReason: String? = null - var progressValues = mutableListOf() + val progressValues = mutableListOf() var onUploadSucceedCalled = false sut.sendBugReport( withDevicesLogs = true, From 592bdb0a575a59d31a1402215d99cba40b2bae2f Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Fri, 12 Jan 2024 09:18:50 +0100 Subject: [PATCH 010/127] Fix test. The change is due to the new label send to the server. --- .../rageshake/impl/reporter/DefaultBugReporterTest.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/features/rageshake/impl/src/test/kotlin/io/element/android/features/rageshake/impl/reporter/DefaultBugReporterTest.kt b/features/rageshake/impl/src/test/kotlin/io/element/android/features/rageshake/impl/reporter/DefaultBugReporterTest.kt index da25571266..c5317e5e48 100755 --- a/features/rageshake/impl/src/test/kotlin/io/element/android/features/rageshake/impl/reporter/DefaultBugReporterTest.kt +++ b/features/rageshake/impl/src/test/kotlin/io/element/android/features/rageshake/impl/reporter/DefaultBugReporterTest.kt @@ -80,7 +80,7 @@ class DefaultBugReporterTest { server.shutdown() assertThat(onUploadCancelledCalled).isFalse() assertThat(onUploadFailedCalled).isFalse() - assertThat(progressValues.size).isEqualTo(10) + assertThat(progressValues.size).isEqualTo(11) assertThat(onUploadSucceedCalled).isTrue() } @@ -131,7 +131,7 @@ class DefaultBugReporterTest { assertThat(onUploadCancelledCalled).isFalse() assertThat(onUploadFailedCalled).isTrue() assertThat(onUploadFailedReason).isEqualTo("An error body") - assertThat(progressValues.size).isEqualTo(10) + assertThat(progressValues.size).isEqualTo(11) assertThat(onUploadSucceedCalled).isFalse() } From 14d5274d22eb8bd925663295c5c785ca0b44b853 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Fri, 12 Jan 2024 15:56:47 +0100 Subject: [PATCH 011/127] Display name disambiguation #2215. Applied to: - timeline message - detail of timeline message - reply preview of timeline message - rendering of state Event Not applied to: - room last message - room member list (we display the MatrixId here) - room member detail page --- changelog.d/2215.misc | 1 + .../event/TimelineItemContentFactory.kt | 4 +- .../event/TimelineItemEventFactory.kt | 3 +- .../impl/DefaultRoomLastMessageFormatter.kt | 2 + .../impl/DefaultTimelineEventFormatter.kt | 4 +- .../item/event/ProfileTimelineDetails.kt | 18 +++++ .../item/event/ProfileTimelineDetailsTest.kt | 74 +++++++++++++++++++ 7 files changed, 101 insertions(+), 5 deletions(-) create mode 100644 changelog.d/2215.misc create mode 100644 libraries/matrix/api/src/test/kotlin/io/element/android/libraries/matrix/api/timeline/item/event/ProfileTimelineDetailsTest.kt diff --git a/changelog.d/2215.misc b/changelog.d/2215.misc new file mode 100644 index 0000000000..1b343d2eb5 --- /dev/null +++ b/changelog.d/2215.misc @@ -0,0 +1 @@ +Disambiguate display name in the timeline. diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/factories/event/TimelineItemContentFactory.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/factories/event/TimelineItemContentFactory.kt index abd4dce536..4a15a47f95 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/factories/event/TimelineItemContentFactory.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/factories/event/TimelineItemContentFactory.kt @@ -24,13 +24,13 @@ import io.element.android.libraries.matrix.api.timeline.item.event.FailedToParse import io.element.android.libraries.matrix.api.timeline.item.event.MessageContent import io.element.android.libraries.matrix.api.timeline.item.event.PollContent import io.element.android.libraries.matrix.api.timeline.item.event.ProfileChangeContent -import io.element.android.libraries.matrix.api.timeline.item.event.ProfileTimelineDetails import io.element.android.libraries.matrix.api.timeline.item.event.RedactedContent import io.element.android.libraries.matrix.api.timeline.item.event.RoomMembershipContent import io.element.android.libraries.matrix.api.timeline.item.event.StateContent import io.element.android.libraries.matrix.api.timeline.item.event.StickerContent import io.element.android.libraries.matrix.api.timeline.item.event.UnableToDecryptContent import io.element.android.libraries.matrix.api.timeline.item.event.UnknownContent +import io.element.android.libraries.matrix.api.timeline.item.event.getDisambiguatedDisplayName import javax.inject.Inject class TimelineItemContentFactory @Inject constructor( @@ -50,7 +50,7 @@ class TimelineItemContentFactory @Inject constructor( is FailedToParseMessageLikeContent -> failedToParseMessageFactory.create(itemContent) is FailedToParseStateContent -> failedToParseStateFactory.create(itemContent) is MessageContent -> { - val senderDisplayName = (eventTimelineItem.senderProfile as? ProfileTimelineDetails.Ready)?.displayName ?: eventTimelineItem.sender.value + val senderDisplayName = eventTimelineItem.senderProfile.getDisambiguatedDisplayName(eventTimelineItem.sender) messageFactory.create(itemContent, senderDisplayName, eventTimelineItem.eventId) } is ProfileChangeContent -> profileChangeFactory.create(eventTimelineItem) diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/factories/event/TimelineItemEventFactory.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/factories/event/TimelineItemEventFactory.kt index 0f204921d2..29ea9df6c2 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/factories/event/TimelineItemEventFactory.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/factories/event/TimelineItemEventFactory.kt @@ -33,6 +33,7 @@ import io.element.android.libraries.matrix.api.MatrixClient import io.element.android.libraries.matrix.api.room.RoomMember import io.element.android.libraries.matrix.api.timeline.MatrixTimelineItem import io.element.android.libraries.matrix.api.timeline.item.event.ProfileTimelineDetails +import io.element.android.libraries.matrix.api.timeline.item.event.getDisambiguatedDisplayName import kotlinx.collections.immutable.toImmutableList import java.text.DateFormat import java.util.Date @@ -63,7 +64,7 @@ class TimelineItemEventFactory @Inject constructor( senderAvatarUrl = null } is ProfileTimelineDetails.Ready -> { - senderDisplayName = senderProfile.displayName + senderDisplayName = senderProfile.getDisambiguatedDisplayName(currentSender) senderAvatarUrl = senderProfile.avatarUrl } } diff --git a/libraries/eventformatter/impl/src/main/kotlin/io/element/android/libraries/eventformatter/impl/DefaultRoomLastMessageFormatter.kt b/libraries/eventformatter/impl/src/main/kotlin/io/element/android/libraries/eventformatter/impl/DefaultRoomLastMessageFormatter.kt index 131250fac7..e9066681c5 100644 --- a/libraries/eventformatter/impl/src/main/kotlin/io/element/android/libraries/eventformatter/impl/DefaultRoomLastMessageFormatter.kt +++ b/libraries/eventformatter/impl/src/main/kotlin/io/element/android/libraries/eventformatter/impl/DefaultRoomLastMessageFormatter.kt @@ -69,6 +69,8 @@ class DefaultRoomLastMessageFormatter @Inject constructor( override fun format(event: EventTimelineItem, isDmRoom: Boolean): CharSequence? { val isOutgoing = event.isOwn + // Note: we do not use disambiguated display name here, see + // https://github.com/element-hq/element-x-ios/issues/1845#issuecomment-1888707428 val senderDisplayName = (event.senderProfile as? ProfileTimelineDetails.Ready)?.displayName ?: event.sender.value return when (val content = event.content) { is MessageContent -> processMessageContents(content, senderDisplayName, isDmRoom) diff --git a/libraries/eventformatter/impl/src/main/kotlin/io/element/android/libraries/eventformatter/impl/DefaultTimelineEventFormatter.kt b/libraries/eventformatter/impl/src/main/kotlin/io/element/android/libraries/eventformatter/impl/DefaultTimelineEventFormatter.kt index 63c8f939a0..e147f25e16 100644 --- a/libraries/eventformatter/impl/src/main/kotlin/io/element/android/libraries/eventformatter/impl/DefaultTimelineEventFormatter.kt +++ b/libraries/eventformatter/impl/src/main/kotlin/io/element/android/libraries/eventformatter/impl/DefaultTimelineEventFormatter.kt @@ -27,13 +27,13 @@ import io.element.android.libraries.matrix.api.timeline.item.event.FailedToParse import io.element.android.libraries.matrix.api.timeline.item.event.MessageContent import io.element.android.libraries.matrix.api.timeline.item.event.PollContent import io.element.android.libraries.matrix.api.timeline.item.event.ProfileChangeContent -import io.element.android.libraries.matrix.api.timeline.item.event.ProfileTimelineDetails import io.element.android.libraries.matrix.api.timeline.item.event.RedactedContent import io.element.android.libraries.matrix.api.timeline.item.event.RoomMembershipContent import io.element.android.libraries.matrix.api.timeline.item.event.StateContent import io.element.android.libraries.matrix.api.timeline.item.event.StickerContent import io.element.android.libraries.matrix.api.timeline.item.event.UnableToDecryptContent import io.element.android.libraries.matrix.api.timeline.item.event.UnknownContent +import io.element.android.libraries.matrix.api.timeline.item.event.getDisambiguatedDisplayName import io.element.android.libraries.ui.strings.CommonStrings import io.element.android.services.toolbox.api.strings.StringProvider import javax.inject.Inject @@ -48,7 +48,7 @@ class DefaultTimelineEventFormatter @Inject constructor( ) : TimelineEventFormatter { override fun format(event: EventTimelineItem): CharSequence? { val isOutgoing = event.isOwn - val senderDisplayName = (event.senderProfile as? ProfileTimelineDetails.Ready)?.displayName ?: event.sender.value + val senderDisplayName = event.senderProfile.getDisambiguatedDisplayName(event.sender) return when (val content = event.content) { is RoomMembershipContent -> { roomMembershipContentFormatter.format(content, senderDisplayName, isOutgoing) diff --git a/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/timeline/item/event/ProfileTimelineDetails.kt b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/timeline/item/event/ProfileTimelineDetails.kt index 44664a256a..efbc2564a9 100644 --- a/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/timeline/item/event/ProfileTimelineDetails.kt +++ b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/timeline/item/event/ProfileTimelineDetails.kt @@ -17,6 +17,7 @@ package io.element.android.libraries.matrix.api.timeline.item.event import androidx.compose.runtime.Immutable +import io.element.android.libraries.matrix.api.core.UserId @Immutable sealed interface ProfileTimelineDetails { @@ -34,3 +35,20 @@ sealed interface ProfileTimelineDetails { val message: String ) : ProfileTimelineDetails } + +/** + * Returns a disambiguated display name for the user. + * If the display name is null, or profile is not Ready, the user ID is returned. + * If the display name is ambiguous, the user ID is appended in parentheses. + * Otherwise, the display name is returned. + */ +fun ProfileTimelineDetails.getDisambiguatedDisplayName(userId: UserId): String { + return when (this) { + is ProfileTimelineDetails.Ready -> when { + displayName == null -> userId.value + displayNameAmbiguous -> "$displayName ($userId)" + else -> displayName + } + else -> userId.value + } +} diff --git a/libraries/matrix/api/src/test/kotlin/io/element/android/libraries/matrix/api/timeline/item/event/ProfileTimelineDetailsTest.kt b/libraries/matrix/api/src/test/kotlin/io/element/android/libraries/matrix/api/timeline/item/event/ProfileTimelineDetailsTest.kt new file mode 100644 index 0000000000..e760cfa210 --- /dev/null +++ b/libraries/matrix/api/src/test/kotlin/io/element/android/libraries/matrix/api/timeline/item/event/ProfileTimelineDetailsTest.kt @@ -0,0 +1,74 @@ +/* + * 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 io.element.android.libraries.matrix.api.timeline.item.event + +import com.google.common.truth.Truth.assertThat +import io.element.android.libraries.matrix.api.core.UserId +import org.junit.Test + +private const val A_USER_ID = "@foo:example.org" +private val aUserId = UserId(A_USER_ID) + +class ProfileTimelineDetailsTest { + @Test + fun `getDisambiguatedDisplayName of Unavailable should be equal to userId`() { + assertThat(ProfileTimelineDetails.Unavailable.getDisambiguatedDisplayName(aUserId)).isEqualTo(A_USER_ID) + } + + @Test + fun `getDisambiguatedDisplayName of Error should be equal to userId`() { + assertThat(ProfileTimelineDetails.Error("An error").getDisambiguatedDisplayName(aUserId)).isEqualTo(A_USER_ID) + } + + @Test + fun `getDisambiguatedDisplayName of Pending should be equal to userId`() { + assertThat(ProfileTimelineDetails.Pending.getDisambiguatedDisplayName(aUserId)).isEqualTo(A_USER_ID) + } + + @Test + fun `getDisambiguatedDisplayName of Ready without display name should be equal to userId`() { + assertThat( + ProfileTimelineDetails.Ready( + displayName = null, + displayNameAmbiguous = false, + avatarUrl = null, + ).getDisambiguatedDisplayName(aUserId) + ).isEqualTo(A_USER_ID) + } + + @Test + fun `getDisambiguatedDisplayName of Ready with display name should be equal to display name`() { + assertThat( + ProfileTimelineDetails.Ready( + displayName = "Alice", + displayNameAmbiguous = false, + avatarUrl = null, + ).getDisambiguatedDisplayName(aUserId) + ).isEqualTo("Alice") + } + + @Test + fun `getDisambiguatedDisplayName of Ready with display name and ambiguous should be equal to display name with user id`() { + assertThat( + ProfileTimelineDetails.Ready( + displayName = "Alice", + displayNameAmbiguous = true, + avatarUrl = null, + ).getDisambiguatedDisplayName(aUserId) + ).isEqualTo("Alice ($A_USER_ID)") + } +} From 4bbaced0d48f58e13ffe5c018c5f3c9f85369bc3 Mon Sep 17 00:00:00 2001 From: ganfra Date: Wed, 17 Jan 2024 11:29:28 +0100 Subject: [PATCH 012/127] Setting version for the next release 0.4.2 --- plugins/src/main/kotlin/Versions.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/src/main/kotlin/Versions.kt b/plugins/src/main/kotlin/Versions.kt index 8d7b845805..a67390c54b 100644 --- a/plugins/src/main/kotlin/Versions.kt +++ b/plugins/src/main/kotlin/Versions.kt @@ -56,7 +56,7 @@ private const val versionMinor = 4 // Note: even values are reserved for regular release, odd values for hotfix release. // When creating a hotfix, you should decrease the value, since the current value // is the value for the next regular release. -private const val versionPatch = 1 +private const val versionPatch = 2 object Versions { val versionCode = 4_000_000 + versionMajor * 1_00_00 + versionMinor * 1_00 + versionPatch From 26438d97ac8065903020b62c0450b4fc7bc0d239 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 17 Jan 2024 15:18:22 +0000 Subject: [PATCH 013/127] Update dependency com.posthog:posthog-android to v3.1.3 --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index d65eb31e8a..ad5dd35665 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -172,7 +172,7 @@ opusencoder = "io.element.android:opusencoder:1.1.0" kotlinpoet = "com.squareup:kotlinpoet:1.15.3" # Analytics -posthog = "com.posthog:posthog-android:3.1.2" +posthog = "com.posthog:posthog-android:3.1.3" sentry = "io.sentry:sentry-android:7.2.0" matrix_analytics_events = "com.github.matrix-org:matrix-analytics-events:aa14cbcdf81af2746d20a71779ec751f971e1d7f" From 7498c148f119e4e1649cb2b7b58d0308842c868c Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Wed, 17 Jan 2024 16:07:26 +0100 Subject: [PATCH 014/127] Ensure that a PushProvider is available on a device before using it. It help to fallback to UnifiedPush (if available) if the PlayServices are not installed on the device. --- .../android/libraries/push/api/PushService.kt | 4 ++++ .../libraries/push/impl/DefaultPushService.kt | 4 +++- .../pushproviders/api/PushProvider.kt | 5 +++++ .../firebase/FirebasePushProvider.kt | 18 ++++++++++++++++++ .../unifiedpush/UnifiedPushProvider.kt | 15 +++++++++++++++ 5 files changed, 45 insertions(+), 1 deletion(-) diff --git a/libraries/push/api/src/main/kotlin/io/element/android/libraries/push/api/PushService.kt b/libraries/push/api/src/main/kotlin/io/element/android/libraries/push/api/PushService.kt index 1a0eb7a93c..5f4736e5ab 100644 --- a/libraries/push/api/src/main/kotlin/io/element/android/libraries/push/api/PushService.kt +++ b/libraries/push/api/src/main/kotlin/io/element/android/libraries/push/api/PushService.kt @@ -24,6 +24,10 @@ interface PushService { // TODO Move away fun notificationStyleChanged() + /** + * Return the list of push providers, available at compile time, and + * available at runtime, sorted by index. + */ fun getAvailablePushProviders(): List /** diff --git a/libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/DefaultPushService.kt b/libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/DefaultPushService.kt index b16908269d..e60cd8b014 100644 --- a/libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/DefaultPushService.kt +++ b/libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/DefaultPushService.kt @@ -38,7 +38,9 @@ class DefaultPushService @Inject constructor( } override fun getAvailablePushProviders(): List { - return pushProviders.sortedBy { it.index } + return pushProviders + .filter { it.isAvailable() } + .sortedBy { it.index } } /** diff --git a/libraries/pushproviders/api/src/main/kotlin/io/element/android/libraries/pushproviders/api/PushProvider.kt b/libraries/pushproviders/api/src/main/kotlin/io/element/android/libraries/pushproviders/api/PushProvider.kt index d71cd9ec3f..3d8349a117 100644 --- a/libraries/pushproviders/api/src/main/kotlin/io/element/android/libraries/pushproviders/api/PushProvider.kt +++ b/libraries/pushproviders/api/src/main/kotlin/io/element/android/libraries/pushproviders/api/PushProvider.kt @@ -32,6 +32,11 @@ interface PushProvider { */ val name: String + /** + * Return true if the push provider is available on this device. + */ + fun isAvailable(): Boolean + fun getDistributors(): List /** diff --git a/libraries/pushproviders/firebase/src/main/kotlin/io/element/android/libraries/pushproviders/firebase/FirebasePushProvider.kt b/libraries/pushproviders/firebase/src/main/kotlin/io/element/android/libraries/pushproviders/firebase/FirebasePushProvider.kt index 1fad74e1be..4c3d6d3a20 100644 --- a/libraries/pushproviders/firebase/src/main/kotlin/io/element/android/libraries/pushproviders/firebase/FirebasePushProvider.kt +++ b/libraries/pushproviders/firebase/src/main/kotlin/io/element/android/libraries/pushproviders/firebase/FirebasePushProvider.kt @@ -16,9 +16,13 @@ package io.element.android.libraries.pushproviders.firebase +import android.content.Context +import com.google.android.gms.common.ConnectionResult +import com.google.android.gms.common.GoogleApiAvailability import com.squareup.anvil.annotations.ContributesMultibinding import io.element.android.libraries.core.log.logger.LoggerTag import io.element.android.libraries.di.AppScope +import io.element.android.libraries.di.ApplicationContext import io.element.android.libraries.matrix.api.MatrixClient import io.element.android.libraries.pushproviders.api.Distributor import io.element.android.libraries.pushproviders.api.PushProvider @@ -30,6 +34,7 @@ private val loggerTag = LoggerTag("FirebasePushProvider", LoggerTag.PushLoggerTa @ContributesMultibinding(AppScope::class) class FirebasePushProvider @Inject constructor( + @ApplicationContext private val context: Context, private val firebaseStore: FirebaseStore, private val firebaseTroubleshooter: FirebaseTroubleshooter, private val pusherSubscriber: PusherSubscriber, @@ -37,6 +42,19 @@ class FirebasePushProvider @Inject constructor( override val index = FirebaseConfig.INDEX override val name = FirebaseConfig.NAME + override fun isAvailable(): Boolean { + // The PlayServices has to be available + val apiAvailability = GoogleApiAvailability.getInstance() + val resultCode = apiAvailability.isGooglePlayServicesAvailable(context) + return if (resultCode == ConnectionResult.SUCCESS) { + Timber.tag(loggerTag.value).d("Google Play Services is available") + true + } else { + Timber.tag(loggerTag.value).w("Google Play Services is not available") + false + } + } + override fun getDistributors(): List { return listOf(Distributor("Firebase", "Firebase")) } diff --git a/libraries/pushproviders/unifiedpush/src/main/kotlin/io/element/android/libraries/pushproviders/unifiedpush/UnifiedPushProvider.kt b/libraries/pushproviders/unifiedpush/src/main/kotlin/io/element/android/libraries/pushproviders/unifiedpush/UnifiedPushProvider.kt index bca4fd3ed3..5d0a0da7a1 100644 --- a/libraries/pushproviders/unifiedpush/src/main/kotlin/io/element/android/libraries/pushproviders/unifiedpush/UnifiedPushProvider.kt +++ b/libraries/pushproviders/unifiedpush/src/main/kotlin/io/element/android/libraries/pushproviders/unifiedpush/UnifiedPushProvider.kt @@ -19,6 +19,7 @@ package io.element.android.libraries.pushproviders.unifiedpush import android.content.Context import com.squareup.anvil.annotations.ContributesMultibinding import io.element.android.libraries.androidutils.system.getApplicationLabel +import io.element.android.libraries.core.log.logger.LoggerTag import io.element.android.libraries.di.AppScope import io.element.android.libraries.di.ApplicationContext import io.element.android.libraries.matrix.api.MatrixClient @@ -26,8 +27,11 @@ import io.element.android.libraries.pushproviders.api.Distributor import io.element.android.libraries.pushproviders.api.PushProvider import io.element.android.libraries.pushstore.api.clientsecret.PushClientSecret import org.unifiedpush.android.connector.UnifiedPush +import timber.log.Timber import javax.inject.Inject +private val loggerTag = LoggerTag("UnifiedPushProvider", LoggerTag.PushLoggerTag) + @ContributesMultibinding(AppScope::class) class UnifiedPushProvider @Inject constructor( @ApplicationContext private val context: Context, @@ -38,6 +42,17 @@ class UnifiedPushProvider @Inject constructor( override val index = UnifiedPushConfig.INDEX override val name = UnifiedPushConfig.NAME + override fun isAvailable(): Boolean { + val isAvailable = getDistributors().isNotEmpty() + return if (isAvailable) { + Timber.tag(loggerTag.value).d("UnifiedPush is available") + true + } else { + Timber.tag(loggerTag.value).w("UnifiedPush is not available") + false + } + } + override fun getDistributors(): List { val distributors = UnifiedPush.getDistributors(context) return distributors.mapNotNull { From 54f3f8d01f7c55f040670ea470625f38f16ffb88 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Wed, 17 Jan 2024 16:56:26 +0100 Subject: [PATCH 015/127] changelog --- changelog.d/2248.misc | 1 + 1 file changed, 1 insertion(+) create mode 100644 changelog.d/2248.misc diff --git a/changelog.d/2248.misc b/changelog.d/2248.misc new file mode 100644 index 0000000000..eed13375a0 --- /dev/null +++ b/changelog.d/2248.misc @@ -0,0 +1 @@ +Fallback to UnifiedPush (if available) if the PlayServices are not installed on the device. From a7c21a8c98ad5c7f1b570321004793be1e3bb35f Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Wed, 17 Jan 2024 11:31:04 +0100 Subject: [PATCH 016/127] Better log. --- .../src/main/kotlin/io/element/android/appnav/RootFlowNode.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/appnav/src/main/kotlin/io/element/android/appnav/RootFlowNode.kt b/appnav/src/main/kotlin/io/element/android/appnav/RootFlowNode.kt index 42c9869523..8a9ea22926 100644 --- a/appnav/src/main/kotlin/io/element/android/appnav/RootFlowNode.kt +++ b/appnav/src/main/kotlin/io/element/android/appnav/RootFlowNode.kt @@ -141,7 +141,7 @@ class RootFlowNode @AssistedInject constructor( onSuccess(sessionId) } .onFailure { - Timber.v("Failed to restore session $sessionId") + Timber.e(it, "Failed to restore session $sessionId") onFailure() } } From bdb331439c1879fe0b03a039f101bd0e57aa7e17 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 17 Jan 2024 18:25:03 +0100 Subject: [PATCH 017/127] Update dependency com.google.testparameterinjector:test-parameter-injector to v1.15 (#2246) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index ad5dd35665..363dfbfced 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -133,7 +133,7 @@ test_mockk = "io.mockk:mockk:1.13.9" test_konsist = "com.lemonappdev:konsist:0.13.0" test_turbine = "app.cash.turbine:turbine:1.0.0" test_truth = "com.google.truth:truth:1.2.0" -test_parameter_injector = "com.google.testparameterinjector:test-parameter-injector:1.14" +test_parameter_injector = "com.google.testparameterinjector:test-parameter-injector:1.15" test_robolectric = "org.robolectric:robolectric:4.11.1" test_appyx_junit = { module = "com.bumble.appyx:testing-junit4", version.ref = "appyx" } From e6877d3142e2086b4649b6ac27950a0bba755c4c Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 17 Jan 2024 18:25:25 +0100 Subject: [PATCH 018/127] Update plugin dependencycheck to v9.0.9 (#2243) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 363dfbfced..33efc9e9a8 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -214,7 +214,7 @@ anvil = { id = "com.squareup.anvil", version.ref = "anvil" } detekt = "io.gitlab.arturbosch.detekt:1.23.4" ktlint = "org.jlleitschuh.gradle.ktlint:12.1.0" dependencygraph = "com.savvasdalkitsis.module-dependency-graph:0.12" -dependencycheck = "org.owasp.dependencycheck:9.0.8" +dependencycheck = "org.owasp.dependencycheck:9.0.9" dependencyanalysis = { id = "com.autonomousapps.dependency-analysis", version.ref = "dependencyAnalysis" } paparazzi = "app.cash.paparazzi:1.3.1" kover = { id = "org.jetbrains.kotlinx.kover", version.ref = "kover" } From 34ab3d4d0ee43e51e86a47640f7d91e6597f9e25 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 18 Jan 2024 03:10:45 +0000 Subject: [PATCH 019/127] Update dependencyAnalysis to v1.29.0 --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 33efc9e9a8..ea63cc11c9 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -33,7 +33,7 @@ test_core = "1.5.0" #other coil = "2.5.0" datetime = "0.5.0" -dependencyAnalysis = "1.28.0" +dependencyAnalysis = "1.29.0" serialization_json = "1.6.2" showkase = "1.0.2" appyx = "1.4.0" From 56990e5e5b5959f8497091a5b6101cc385dc90f0 Mon Sep 17 00:00:00 2001 From: Jorge Martin Espinosa Date: Thu, 18 Jan 2024 08:49:55 +0100 Subject: [PATCH 020/127] Upgrade Material3 Compose to `1.2.0-beta02` (#2247) * Upgrade Material3 Compose to `1.2.0-beta02`. There is also a constraint on a transitive Compose Foundation dependency version (1.6.0-beta02) that fixes the timeline scrolling issue. --------- Co-authored-by: ElementBot --- ...ade-material3-compose-to-1.2.0-beta02.misc | 3 +++ gradle/libs.versions.toml | 3 ++- .../components/tooltip/PlainTooltip.kt | 3 ++- .../components/tooltip/TooltipBox.kt | 3 ++- .../kotlin/extension/DependencyHandleScope.kt | 21 +++++++++++++++++++ ...cesView-Day-0_1_null_0,NEXUS_5,1.0,en].png | 4 ++-- ...sView-Night-0_2_null_0,NEXUS_5,1.0,en].png | 4 ++-- ...ollView-Day-0_1_null_0,NEXUS_5,1.0,en].png | 4 ++-- ...ollView-Day-0_1_null_1,NEXUS_5,1.0,en].png | 4 ++-- ...ollView-Day-0_1_null_2,NEXUS_5,1.0,en].png | 4 ++-- ...ollView-Day-0_1_null_3,NEXUS_5,1.0,en].png | 4 ++-- ...ollView-Day-0_1_null_4,NEXUS_5,1.0,en].png | 4 ++-- ...ollView-Day-0_1_null_5,NEXUS_5,1.0,en].png | 4 ++-- ...ollView-Day-0_1_null_6,NEXUS_5,1.0,en].png | 4 ++-- ...ollView-Day-0_1_null_7,NEXUS_5,1.0,en].png | 4 ++-- ...lView-Night-0_2_null_0,NEXUS_5,1.0,en].png | 4 ++-- ...lView-Night-0_2_null_1,NEXUS_5,1.0,en].png | 4 ++-- ...lView-Night-0_2_null_2,NEXUS_5,1.0,en].png | 4 ++-- ...lView-Night-0_2_null_3,NEXUS_5,1.0,en].png | 4 ++-- ...lView-Night-0_2_null_4,NEXUS_5,1.0,en].png | 4 ++-- ...lView-Night-0_2_null_5,NEXUS_5,1.0,en].png | 4 ++-- ...lView-Night-0_2_null_6,NEXUS_5,1.0,en].png | 4 ++-- ...lView-Night-0_2_null_7,NEXUS_5,1.0,en].png | 4 ++-- ...ngsView-Day-1_2_null_0,NEXUS_5,1.0,en].png | 4 ++-- ...ngsView-Day-1_2_null_1,NEXUS_5,1.0,en].png | 4 ++-- ...ngsView-Day-1_2_null_2,NEXUS_5,1.0,en].png | 4 ++-- ...ngsView-Day-1_2_null_3,NEXUS_5,1.0,en].png | 4 ++-- ...sView-Night-1_3_null_0,NEXUS_5,1.0,en].png | 4 ++-- ...sView-Night-1_3_null_1,NEXUS_5,1.0,en].png | 4 ++-- ...sView-Night-1_3_null_2,NEXUS_5,1.0,en].png | 4 ++-- ...sView-Night-1_3_null_3,NEXUS_5,1.0,en].png | 4 ++-- ...ngsView-Day-2_3_null_0,NEXUS_5,1.0,en].png | 4 ++-- ...sView-Night-2_4_null_0,NEXUS_5,1.0,en].png | 4 ++-- ...ingView-Day-4_5_null_0,NEXUS_5,1.0,en].png | 4 ++-- ...gView-Night-4_6_null_0,NEXUS_5,1.0,en].png | 4 ++-- ...ingOption-Day-7_8_null,NEXUS_5,1.0,en].png | 4 ++-- ...gOption-Night-7_9_null,NEXUS_5,1.0,en].png | 4 ++-- ...ingView-Day-8_9_null_0,NEXUS_5,1.0,en].png | 4 ++-- ...ingView-Day-8_9_null_1,NEXUS_5,1.0,en].png | 4 ++-- ...ingView-Day-8_9_null_2,NEXUS_5,1.0,en].png | 4 ++-- ...ingView-Day-8_9_null_3,NEXUS_5,1.0,en].png | 4 ++-- ...ingView-Day-8_9_null_4,NEXUS_5,1.0,en].png | 4 ++-- ...View-Night-8_10_null_0,NEXUS_5,1.0,en].png | 4 ++-- ...View-Night-8_10_null_1,NEXUS_5,1.0,en].png | 4 ++-- ...View-Night-8_10_null_2,NEXUS_5,1.0,en].png | 4 ++-- ...View-Night-8_10_null_3,NEXUS_5,1.0,en].png | 4 ++-- ...View-Night-8_10_null_4,NEXUS_5,1.0,en].png | 4 ++-- ...otViewDark--1_1_null_0,NEXUS_5,1.0,en].png | 4 ++-- ...otViewDark--1_1_null_1,NEXUS_5,1.0,en].png | 4 ++-- ...tViewLight--0_0_null_0,NEXUS_5,1.0,en].png | 4 ++-- ...tViewLight--0_0_null_1,NEXUS_5,1.0,en].png | 4 ++-- ...lsViewDark--3_3_null_5,NEXUS_5,1.0,en].png | 4 ++-- ...sViewLight--2_2_null_5,NEXUS_5,1.0,en].png | 4 ++-- ...ettings-Day-4_5_null_0,NEXUS_5,1.0,en].png | 4 ++-- ...ettings-Day-4_5_null_1,NEXUS_5,1.0,en].png | 4 ++-- ...ettings-Day-4_5_null_2,NEXUS_5,1.0,en].png | 4 ++-- ...ettings-Day-4_5_null_3,NEXUS_5,1.0,en].png | 4 ++-- ...ettings-Day-4_5_null_4,NEXUS_5,1.0,en].png | 4 ++-- ...ettings-Day-4_5_null_5,NEXUS_5,1.0,en].png | 4 ++-- ...ettings-Day-4_5_null_6,NEXUS_5,1.0,en].png | 4 ++-- ...tings-Night-4_6_null_0,NEXUS_5,1.0,en].png | 4 ++-- ...tings-Night-4_6_null_1,NEXUS_5,1.0,en].png | 4 ++-- ...tings-Night-4_6_null_2,NEXUS_5,1.0,en].png | 4 ++-- ...tings-Night-4_6_null_3,NEXUS_5,1.0,en].png | 4 ++-- ...tings-Night-4_6_null_4,NEXUS_5,1.0,en].png | 4 ++-- ...tings-Night-4_6_null_5,NEXUS_5,1.0,en].png | 4 ++-- ...tings-Night-4_6_null_6,NEXUS_5,1.0,en].png | 4 ++-- ...acyOption-Day-3_4_null,NEXUS_5,1.0,en].png | 4 ++-- ...yOption-Night-3_5_null,NEXUS_5,1.0,en].png | 4 ++-- ...ettings-Day-5_6_null_0,NEXUS_5,1.0,en].png | 4 ++-- ...tings-Night-5_7_null_0,NEXUS_5,1.0,en].png | 4 ++-- ...etailsDark--1_1_null_0,NEXUS_5,1.0,en].png | 4 ++-- ...etailsDark--1_1_null_1,NEXUS_5,1.0,en].png | 4 ++-- ...etailsDark--1_1_null_2,NEXUS_5,1.0,en].png | 4 ++-- ...etailsDark--1_1_null_3,NEXUS_5,1.0,en].png | 4 ++-- ...etailsDark--1_1_null_4,NEXUS_5,1.0,en].png | 4 ++-- ...etailsDark--1_1_null_7,NEXUS_5,1.0,en].png | 4 ++-- ...etailsDark--1_1_null_8,NEXUS_5,1.0,en].png | 4 ++-- ...oomDetails--0_0_null_0,NEXUS_5,1.0,en].png | 4 ++-- ...oomDetails--0_0_null_1,NEXUS_5,1.0,en].png | 4 ++-- ...oomDetails--0_0_null_2,NEXUS_5,1.0,en].png | 4 ++-- ...oomDetails--0_0_null_3,NEXUS_5,1.0,en].png | 4 ++-- ...oomDetails--0_0_null_4,NEXUS_5,1.0,en].png | 4 ++-- ...oomDetails--0_0_null_7,NEXUS_5,1.0,en].png | 4 ++-- ...oomDetails--0_0_null_8,NEXUS_5,1.0,en].png | 4 ++-- ...ootView-Day-3_4_null_0,NEXUS_5,1.0,en].png | 4 ++-- ...ootView-Day-3_4_null_3,NEXUS_5,1.0,en].png | 4 ++-- ...ootView-Day-3_4_null_5,NEXUS_5,1.0,en].png | 4 ++-- ...ootView-Day-3_4_null_6,NEXUS_5,1.0,en].png | 4 ++-- ...ootView-Day-3_4_null_7,NEXUS_5,1.0,en].png | 4 ++-- ...ootView-Day-3_4_null_8,NEXUS_5,1.0,en].png | 4 ++-- ...tView-Night-3_5_null_0,NEXUS_5,1.0,en].png | 4 ++-- ...tView-Night-3_5_null_3,NEXUS_5,1.0,en].png | 4 ++-- ...tView-Night-3_5_null_5,NEXUS_5,1.0,en].png | 4 ++-- ...tView-Night-3_5_null_6,NEXUS_5,1.0,en].png | 4 ++-- ...tView-Night-3_5_null_7,NEXUS_5,1.0,en].png | 4 ++-- ...tView-Night-3_5_null_8,NEXUS_5,1.0,en].png | 4 ++-- ...trailingcontent_0_null,NEXUS_5,1.0,en].png | 4 ++-- ...customformatter_0_null,NEXUS_5,1.0,en].png | 4 ++-- ...trailingcontent_0_null,NEXUS_5,1.0,en].png | 4 ++-- ...line)-BothIcons_0_null,NEXUS_5,1.0,en].png | 4 ++-- ...railingCheckbox_0_null,NEXUS_5,1.0,en].png | 4 ++-- ...e)-TrailingIcon_0_null,NEXUS_5,1.0,en].png | 4 ++-- ...lingRadioButton_0_null,NEXUS_5,1.0,en].png | 4 ++-- ...-TrailingSwitch_0_null,NEXUS_5,1.0,en].png | 4 ++-- ...ines)-BothIcons_0_null,NEXUS_5,1.0,en].png | 4 ++-- ...)-LeadingSwitch_0_null,NEXUS_5,1.0,en].png | 4 ++-- ...railingCheckbox_0_null,NEXUS_5,1.0,en].png | 4 ++-- ...s)-TrailingIcon_0_null,NEXUS_5,1.0,en].png | 4 ++-- ...lingRadioButton_0_null,NEXUS_5,1.0,en].png | 4 ++-- ...-TrailingSwitch_0_null,NEXUS_5,1.0,en].png | 4 ++-- ...ines)-BothIcons_0_null,NEXUS_5,1.0,en].png | 4 ++-- ...LeadingCheckbox_0_null,NEXUS_5,1.0,en].png | 4 ++-- ...es)-LeadingIcon_0_null,NEXUS_5,1.0,en].png | 4 ++-- ...dingRadioButton_0_null,NEXUS_5,1.0,en].png | 4 ++-- ...)-LeadingSwitch_0_null,NEXUS_5,1.0,en].png | 4 ++-- ...(2lines)-Simple_0_null,NEXUS_5,1.0,en].png | 4 ++-- ...railingCheckbox_0_null,NEXUS_5,1.0,en].png | 4 ++-- ...s)-TrailingIcon_0_null,NEXUS_5,1.0,en].png | 4 ++-- ...lingRadioButton_0_null,NEXUS_5,1.0,en].png | 4 ++-- ...-TrailingSwitch_0_null,NEXUS_5,1.0,en].png | 4 ++-- 121 files changed, 262 insertions(+), 235 deletions(-) create mode 100644 changelog.d/+upgrade-material3-compose-to-1.2.0-beta02.misc diff --git a/changelog.d/+upgrade-material3-compose-to-1.2.0-beta02.misc b/changelog.d/+upgrade-material3-compose-to-1.2.0-beta02.misc new file mode 100644 index 0000000000..65f4b287f9 --- /dev/null +++ b/changelog.d/+upgrade-material3-compose-to-1.2.0-beta02.misc @@ -0,0 +1,3 @@ +Upgrade Material3 Compose to `1.2.0-beta02`. + +There is also a constraint on a transitive Compose Foundation dependency version (1.6.0-beta02) that fixes the timeline scrolling issue. diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 33efc9e9a8..b7dfcd5d44 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -93,7 +93,8 @@ androidx_preference = "androidx.preference:preference:1.2.1" androidx_webkit = "androidx.webkit:webkit:1.9.0" androidx_compose_bom = { module = "androidx.compose:compose-bom", version.ref = "compose_bom" } -androidx_compose_material3 = "androidx.compose.material3:material3:1.2.0-alpha11" # Keep using alpha11 for now as it breaks timeline scrolling a bit. +# When Material3 updates its transitive Compose dependencies, take a look at the constraints in `DependencyHandleScope.kt`. We may be able to remove the workaround there. +androidx_compose_material3 = "androidx.compose.material3:material3:1.2.0-beta02" androidx_compose_ui = { module = "androidx.compose.ui:ui" } androidx_compose_ui_tooling = { module = "androidx.compose.ui:ui-tooling" } androidx_compose_ui_tooling_preview = { module = "androidx.compose.ui:ui-tooling-preview" } diff --git a/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/components/tooltip/PlainTooltip.kt b/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/components/tooltip/PlainTooltip.kt index b61aa3dda2..af1e03e69f 100644 --- a/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/components/tooltip/PlainTooltip.kt +++ b/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/components/tooltip/PlainTooltip.kt @@ -16,6 +16,7 @@ package io.element.android.libraries.designsystem.components.tooltip +import androidx.compose.material3.CaretScope import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.TooltipDefaults import androidx.compose.runtime.Composable @@ -27,7 +28,7 @@ import androidx.compose.material3.PlainTooltip as M3PlainTooltip @OptIn(ExperimentalMaterial3Api::class) @Composable -fun PlainTooltip( +fun CaretScope.PlainTooltip( modifier: Modifier = Modifier, contentColor: Color = ElementTheme.colors.textOnSolidPrimary, containerColor: Color = ElementTheme.colors.bgActionPrimaryRest, diff --git a/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/components/tooltip/TooltipBox.kt b/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/components/tooltip/TooltipBox.kt index fc11758104..f469e32de6 100644 --- a/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/components/tooltip/TooltipBox.kt +++ b/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/components/tooltip/TooltipBox.kt @@ -16,6 +16,7 @@ package io.element.android.libraries.designsystem.components.tooltip +import androidx.compose.material3.CaretScope import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.TooltipState import androidx.compose.runtime.Composable @@ -27,7 +28,7 @@ import androidx.compose.material3.TooltipBox as M3TooltipBox @Composable fun TooltipBox( positionProvider: PopupPositionProvider, - tooltip: @Composable () -> Unit, + tooltip: @Composable CaretScope.() -> Unit, state: TooltipState, modifier: Modifier = Modifier, focusable: Boolean = true, diff --git a/plugins/src/main/kotlin/extension/DependencyHandleScope.kt b/plugins/src/main/kotlin/extension/DependencyHandleScope.kt index caa928c51d..1ba4b60b4d 100644 --- a/plugins/src/main/kotlin/extension/DependencyHandleScope.kt +++ b/plugins/src/main/kotlin/extension/DependencyHandleScope.kt @@ -17,13 +17,24 @@ package extension import org.gradle.accessors.dm.LibrariesForLibs +import org.gradle.api.Action +import org.gradle.api.artifacts.ExternalModuleDependency import org.gradle.api.logging.Logger +import org.gradle.api.provider.Provider import org.gradle.kotlin.dsl.DependencyHandlerScope +import org.gradle.kotlin.dsl.closureOf +import org.gradle.kotlin.dsl.exclude import org.gradle.kotlin.dsl.project import java.io.File private fun DependencyHandlerScope.implementation(dependency: Any) = dependencies.add("implementation", dependency) +// Implementation + config block +private fun DependencyHandlerScope.implementation( + dependency: Any, + config: Action +) = dependencies.add("implementation", dependency, closureOf { config.execute(this) }) + private fun DependencyHandlerScope.androidTestImplementation(dependency: Any) = dependencies.add("androidTestImplementation", dependency) private fun DependencyHandlerScope.debugImplementation(dependency: Any) = dependencies.add("debugImplementation", dependency) @@ -45,6 +56,16 @@ fun DependencyHandlerScope.composeDependencies(libs: LibrariesForLibs) { implementation(libs.androidx.compose.ui) implementation(libs.androidx.compose.material) implementation(libs.androidx.compose.material3) + + // Remove these constraints once `material3` updates its internal dependencies + constraints { + implementation("androidx.compose.foundation:foundation:1.6.0-beta02") { + because("The transitive version inside `material3` (1.6.0-beta01) causes a scrolling issue. " + + "See https://android.googlesource.com/platform/frameworks/support/+/2d15876146ccf201f7e15cacc78bfca762060624" + ) + } + } + implementation(libs.androidx.compose.material.icons) implementation(libs.androidx.compose.ui.tooling.preview) implementation(libs.androidx.activity.compose) diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.analytics.api.preferences_AnalyticsPreferencesView_null_AnalyticsPreferencesView-Day-0_1_null_0,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.analytics.api.preferences_AnalyticsPreferencesView_null_AnalyticsPreferencesView-Day-0_1_null_0,NEXUS_5,1.0,en].png index 5790bbb52e..127d644e9a 100644 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.analytics.api.preferences_AnalyticsPreferencesView_null_AnalyticsPreferencesView-Day-0_1_null_0,NEXUS_5,1.0,en].png +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.analytics.api.preferences_AnalyticsPreferencesView_null_AnalyticsPreferencesView-Day-0_1_null_0,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:5fc43706603ce52fa3495fa4e6dfa9aa684540a9dec996a5f705427d34ffb55c -size 23274 +oid sha256:6638cb923a57c8ee4a577626bef41c87da3ad5081a6bda6b4a303f094be30bfd +size 23181 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.analytics.api.preferences_AnalyticsPreferencesView_null_AnalyticsPreferencesView-Night-0_2_null_0,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.analytics.api.preferences_AnalyticsPreferencesView_null_AnalyticsPreferencesView-Night-0_2_null_0,NEXUS_5,1.0,en].png index acac72afff..c934db9816 100644 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.analytics.api.preferences_AnalyticsPreferencesView_null_AnalyticsPreferencesView-Night-0_2_null_0,NEXUS_5,1.0,en].png +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.analytics.api.preferences_AnalyticsPreferencesView_null_AnalyticsPreferencesView-Night-0_2_null_0,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:753cfd0885800b622e119565ac98d46d0d339d8440cf445fcb45d4af866884b9 -size 22371 +oid sha256:4ffb2f6bd00607dd9f84d9b9dd4014f4389d0a3dd73fea8881a867680c0aa47b +size 22301 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.poll.impl.create_CreatePollView_null_CreatePollView-Day-0_1_null_0,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.poll.impl.create_CreatePollView_null_CreatePollView-Day-0_1_null_0,NEXUS_5,1.0,en].png index 42cc37bc7e..d634450d0f 100644 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.poll.impl.create_CreatePollView_null_CreatePollView-Day-0_1_null_0,NEXUS_5,1.0,en].png +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.poll.impl.create_CreatePollView_null_CreatePollView-Day-0_1_null_0,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:a79a90406a98deaf70fd3234dd1f2bbd51060b1074a5a285d3315bc90191bcd6 -size 34775 +oid sha256:95deebee51ef59f77316e0cd1310e0c80083d40d033ac19c8e81dadb930457bb +size 34703 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.poll.impl.create_CreatePollView_null_CreatePollView-Day-0_1_null_1,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.poll.impl.create_CreatePollView_null_CreatePollView-Day-0_1_null_1,NEXUS_5,1.0,en].png index d369206aa9..721238e375 100644 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.poll.impl.create_CreatePollView_null_CreatePollView-Day-0_1_null_1,NEXUS_5,1.0,en].png +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.poll.impl.create_CreatePollView_null_CreatePollView-Day-0_1_null_1,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:2a638452c7d6554a534325b4141bf35aaeec817eec8ebbe50a4efab077164b88 -size 39183 +oid sha256:870b59448a52edbca99ccf63981f259d096652f84a745b2341a8e8e47f15fbfc +size 39135 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.poll.impl.create_CreatePollView_null_CreatePollView-Day-0_1_null_2,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.poll.impl.create_CreatePollView_null_CreatePollView-Day-0_1_null_2,NEXUS_5,1.0,en].png index 44fe8a5840..45c130db54 100644 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.poll.impl.create_CreatePollView_null_CreatePollView-Day-0_1_null_2,NEXUS_5,1.0,en].png +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.poll.impl.create_CreatePollView_null_CreatePollView-Day-0_1_null_2,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:d97257fbbd85d70a319795af9738a3773892d96c6b64e9e8793e693d70929e33 -size 44178 +oid sha256:2fe96d9c6a48832f2045972d1ecd4ca87e56094e9fa0ef863185657e4e4b395a +size 44156 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.poll.impl.create_CreatePollView_null_CreatePollView-Day-0_1_null_3,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.poll.impl.create_CreatePollView_null_CreatePollView-Day-0_1_null_3,NEXUS_5,1.0,en].png index 78f1085afe..38f96907dc 100644 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.poll.impl.create_CreatePollView_null_CreatePollView-Day-0_1_null_3,NEXUS_5,1.0,en].png +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.poll.impl.create_CreatePollView_null_CreatePollView-Day-0_1_null_3,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:70c14eee23c6654149623900aa1edea45ad52e09d21a602af56804f6b8c6d8fc -size 47182 +oid sha256:dd38023674b5f480a27edfc2dcf8df5fcd20678e3203244b17b7add08a203ed4 +size 47161 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.poll.impl.create_CreatePollView_null_CreatePollView-Day-0_1_null_4,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.poll.impl.create_CreatePollView_null_CreatePollView-Day-0_1_null_4,NEXUS_5,1.0,en].png index a32c442bfb..7e19472bcf 100644 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.poll.impl.create_CreatePollView_null_CreatePollView-Day-0_1_null_4,NEXUS_5,1.0,en].png +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.poll.impl.create_CreatePollView_null_CreatePollView-Day-0_1_null_4,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:2539cd3bb3a178fa3e64a7832811e693ebe5529c4923edb185af09f49d7f00ad -size 29604 +oid sha256:77f0d0a20a90d68adcf35a62fa5ed807e74f9820a7550ddf44ac969a79f2566d +size 29467 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.poll.impl.create_CreatePollView_null_CreatePollView-Day-0_1_null_5,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.poll.impl.create_CreatePollView_null_CreatePollView-Day-0_1_null_5,NEXUS_5,1.0,en].png index 9d35b240a3..682e334a9c 100644 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.poll.impl.create_CreatePollView_null_CreatePollView-Day-0_1_null_5,NEXUS_5,1.0,en].png +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.poll.impl.create_CreatePollView_null_CreatePollView-Day-0_1_null_5,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:1b133f65f39ef16d52f4f92e33cb1f38e2c7ac22d61a146ba54937b2d903d54b -size 124269 +oid sha256:0a4fb6ff3a6202d9b3a86e19d1a44811b57fd7c7cb160713afdc672cd0dc7916 +size 123668 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.poll.impl.create_CreatePollView_null_CreatePollView-Day-0_1_null_6,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.poll.impl.create_CreatePollView_null_CreatePollView-Day-0_1_null_6,NEXUS_5,1.0,en].png index dd72111031..b654a85479 100644 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.poll.impl.create_CreatePollView_null_CreatePollView-Day-0_1_null_6,NEXUS_5,1.0,en].png +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.poll.impl.create_CreatePollView_null_CreatePollView-Day-0_1_null_6,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:8e545dca45645bf7874d183697250ca6f8f916121e5a72a07409917a62d1dc94 -size 35440 +oid sha256:d4437d93f3343005397a4ae3e37c7c49b626efcd68febb19e8c0e9021a634f69 +size 35379 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.poll.impl.create_CreatePollView_null_CreatePollView-Day-0_1_null_7,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.poll.impl.create_CreatePollView_null_CreatePollView-Day-0_1_null_7,NEXUS_5,1.0,en].png index 6f8432a888..7307585945 100644 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.poll.impl.create_CreatePollView_null_CreatePollView-Day-0_1_null_7,NEXUS_5,1.0,en].png +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.poll.impl.create_CreatePollView_null_CreatePollView-Day-0_1_null_7,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:362bcdd3b7e32613da7b9f1a6a2dc23a097e8e9b671d185220d9a243326c5b4f -size 37556 +oid sha256:f12dee5614338df53f433f5c81f759096aef93ed7adee2144159c69018b19e9c +size 37864 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.poll.impl.create_CreatePollView_null_CreatePollView-Night-0_2_null_0,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.poll.impl.create_CreatePollView_null_CreatePollView-Night-0_2_null_0,NEXUS_5,1.0,en].png index 93b2003a01..1d9ee8da83 100644 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.poll.impl.create_CreatePollView_null_CreatePollView-Night-0_2_null_0,NEXUS_5,1.0,en].png +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.poll.impl.create_CreatePollView_null_CreatePollView-Night-0_2_null_0,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:bcb1ac2705ac87789c3fde971958bd4b719ce2e303ea80b93e3a1ca56959b880 -size 32882 +oid sha256:136344130e78e56c2bee0157ac2ede86daa5a4ff3817b792f4f49894ddc2a1d5 +size 32741 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.poll.impl.create_CreatePollView_null_CreatePollView-Night-0_2_null_1,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.poll.impl.create_CreatePollView_null_CreatePollView-Night-0_2_null_1,NEXUS_5,1.0,en].png index b90a1f6af0..724d5dac7b 100644 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.poll.impl.create_CreatePollView_null_CreatePollView-Night-0_2_null_1,NEXUS_5,1.0,en].png +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.poll.impl.create_CreatePollView_null_CreatePollView-Night-0_2_null_1,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:5bda72b3a7befebd49870718c7bfe305ea6fb9b9b96079ad481dd104d0ef05d4 -size 36429 +oid sha256:395c15bcdda264a05b22d63d17fc8e08a47f56fbb199e18beb11da412ffc4dcc +size 36353 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.poll.impl.create_CreatePollView_null_CreatePollView-Night-0_2_null_2,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.poll.impl.create_CreatePollView_null_CreatePollView-Night-0_2_null_2,NEXUS_5,1.0,en].png index 42aa83f958..e028c19801 100644 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.poll.impl.create_CreatePollView_null_CreatePollView-Night-0_2_null_2,NEXUS_5,1.0,en].png +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.poll.impl.create_CreatePollView_null_CreatePollView-Night-0_2_null_2,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:80d6f893a6d3d01518c381eb5e7a2ccd261d000ee64fa8eff81a6805f24f5bf5 -size 39383 +oid sha256:77e17ef33a5c3aabfa3ffcf4481173a353c3d6eaea65506f4925e9712d1e7fdf +size 39476 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.poll.impl.create_CreatePollView_null_CreatePollView-Night-0_2_null_3,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.poll.impl.create_CreatePollView_null_CreatePollView-Night-0_2_null_3,NEXUS_5,1.0,en].png index 386d8efc61..eef510b459 100644 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.poll.impl.create_CreatePollView_null_CreatePollView-Night-0_2_null_3,NEXUS_5,1.0,en].png +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.poll.impl.create_CreatePollView_null_CreatePollView-Night-0_2_null_3,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:2b5e4dc970dae62a44231387a2c77b355546553cb0147ca86d2e62fba3795009 -size 44321 +oid sha256:bc56d3a9c61f93d5d2606dda97e11025d8b95abc65c2bad28de5bddcfb2e0620 +size 44270 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.poll.impl.create_CreatePollView_null_CreatePollView-Night-0_2_null_4,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.poll.impl.create_CreatePollView_null_CreatePollView-Night-0_2_null_4,NEXUS_5,1.0,en].png index 7934af8a68..f10763d63d 100644 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.poll.impl.create_CreatePollView_null_CreatePollView-Night-0_2_null_4,NEXUS_5,1.0,en].png +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.poll.impl.create_CreatePollView_null_CreatePollView-Night-0_2_null_4,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:8b0e5e5d17571b37b764d699831a44d461aa4237ac3232bf9b1541351c0bdf29 -size 27871 +oid sha256:fed8b346d4d40f9b319d887ec10d012422ff5b40ea1bbd466e5534523d0edbfe +size 27537 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.poll.impl.create_CreatePollView_null_CreatePollView-Night-0_2_null_5,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.poll.impl.create_CreatePollView_null_CreatePollView-Night-0_2_null_5,NEXUS_5,1.0,en].png index 6f1ad447a9..f1f4698620 100644 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.poll.impl.create_CreatePollView_null_CreatePollView-Night-0_2_null_5,NEXUS_5,1.0,en].png +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.poll.impl.create_CreatePollView_null_CreatePollView-Night-0_2_null_5,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:be7fbaed8c51b8aaa13875db6b73eed0939beffd62565470dbd6a291fdcbbca7 -size 108688 +oid sha256:4df29f963b0bfed1a33839dcff1bfd679109bba1da0f96e853e1a87efe7eec33 +size 108056 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.poll.impl.create_CreatePollView_null_CreatePollView-Night-0_2_null_6,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.poll.impl.create_CreatePollView_null_CreatePollView-Night-0_2_null_6,NEXUS_5,1.0,en].png index 6b1952a412..fd249f1d3b 100644 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.poll.impl.create_CreatePollView_null_CreatePollView-Night-0_2_null_6,NEXUS_5,1.0,en].png +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.poll.impl.create_CreatePollView_null_CreatePollView-Night-0_2_null_6,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:0ccb4cce1db9083561047204aa570727c870a2d1974534fbfc8482b3eaf4fa53 -size 33628 +oid sha256:93d81771457c2a23f59bfe636ff7cc3a55a12e80cce54093c03ccca60df26318 +size 33491 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.poll.impl.create_CreatePollView_null_CreatePollView-Night-0_2_null_7,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.poll.impl.create_CreatePollView_null_CreatePollView-Night-0_2_null_7,NEXUS_5,1.0,en].png index e6c69623e8..a23bc22fd5 100644 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.poll.impl.create_CreatePollView_null_CreatePollView-Night-0_2_null_7,NEXUS_5,1.0,en].png +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.poll.impl.create_CreatePollView_null_CreatePollView-Night-0_2_null_7,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:9fd2419fbcfbf5df4847e47416f3717c1176c5e9e5b529503916f6413c47e5cf -size 32712 +oid sha256:b3334f14c4efc92702cdbcbd866ef6a12b9671c7b397e1db1fb4c6be1304d635 +size 33131 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.advanced_AdvancedSettingsView_null_AdvancedSettingsView-Day-1_2_null_0,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.advanced_AdvancedSettingsView_null_AdvancedSettingsView-Day-1_2_null_0,NEXUS_5,1.0,en].png index df29aa76c6..a5e5ee3ebe 100644 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.advanced_AdvancedSettingsView_null_AdvancedSettingsView-Day-1_2_null_0,NEXUS_5,1.0,en].png +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.advanced_AdvancedSettingsView_null_AdvancedSettingsView-Day-1_2_null_0,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:592c1cc5bc0e8ac2912d0cc9d0fa2aaeec1ba5f49a23415ff4abe16634f7c9f7 -size 39896 +oid sha256:b9792c65780ccbabc55476cd15f0ef1a00e43d4b49ded546350271f52bc50ac5 +size 39898 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.advanced_AdvancedSettingsView_null_AdvancedSettingsView-Day-1_2_null_1,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.advanced_AdvancedSettingsView_null_AdvancedSettingsView-Day-1_2_null_1,NEXUS_5,1.0,en].png index 06bad1718a..4e99b875cb 100644 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.advanced_AdvancedSettingsView_null_AdvancedSettingsView-Day-1_2_null_1,NEXUS_5,1.0,en].png +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.advanced_AdvancedSettingsView_null_AdvancedSettingsView-Day-1_2_null_1,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:504c3ab78b9e10fe8c26d003f487397835d1c548ec11e624bb1317500282d6a0 -size 39415 +oid sha256:33121ba1e716f4a22ba66a2648a1c66acbab8ffe721be2d52e556dd341818696 +size 39392 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.advanced_AdvancedSettingsView_null_AdvancedSettingsView-Day-1_2_null_2,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.advanced_AdvancedSettingsView_null_AdvancedSettingsView-Day-1_2_null_2,NEXUS_5,1.0,en].png index 6c581d5c97..cca7799a9b 100644 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.advanced_AdvancedSettingsView_null_AdvancedSettingsView-Day-1_2_null_2,NEXUS_5,1.0,en].png +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.advanced_AdvancedSettingsView_null_AdvancedSettingsView-Day-1_2_null_2,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:22939cc1060893e6440f755701303be0fb8c8c1c39256af1ce7b12a1289f7f4d -size 39391 +oid sha256:2081e18691471601c80bed114bc795c6fe4491186282db4a81f0fb186d286d30 +size 39402 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.advanced_AdvancedSettingsView_null_AdvancedSettingsView-Day-1_2_null_3,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.advanced_AdvancedSettingsView_null_AdvancedSettingsView-Day-1_2_null_3,NEXUS_5,1.0,en].png index 48b42a7ee4..336d6c8b81 100644 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.advanced_AdvancedSettingsView_null_AdvancedSettingsView-Day-1_2_null_3,NEXUS_5,1.0,en].png +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.advanced_AdvancedSettingsView_null_AdvancedSettingsView-Day-1_2_null_3,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:9e08bcbb2d09af6d796068a4c64ff5f03d73aadefe3a20f0a2793333f73291f4 -size 35414 +oid sha256:61201245ab79d39b505f27d9fd4d1a5842111bac1e067c2bd450f633c9e92ec4 +size 35497 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.advanced_AdvancedSettingsView_null_AdvancedSettingsView-Night-1_3_null_0,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.advanced_AdvancedSettingsView_null_AdvancedSettingsView-Night-1_3_null_0,NEXUS_5,1.0,en].png index 9652e4df09..01afa74c7f 100644 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.advanced_AdvancedSettingsView_null_AdvancedSettingsView-Night-1_3_null_0,NEXUS_5,1.0,en].png +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.advanced_AdvancedSettingsView_null_AdvancedSettingsView-Night-1_3_null_0,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:fa224e2d1273a69ea0a3d56765d2dd149b7d295f576c43c09c1eceee92a5c528 -size 37182 +oid sha256:5a24874553e4228ba8c254487c1bdd4d1a5556ecc2d4dfe26ace20548f5f9d38 +size 37203 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.advanced_AdvancedSettingsView_null_AdvancedSettingsView-Night-1_3_null_1,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.advanced_AdvancedSettingsView_null_AdvancedSettingsView-Night-1_3_null_1,NEXUS_5,1.0,en].png index cf646c4351..43cfc64ba6 100644 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.advanced_AdvancedSettingsView_null_AdvancedSettingsView-Night-1_3_null_1,NEXUS_5,1.0,en].png +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.advanced_AdvancedSettingsView_null_AdvancedSettingsView-Night-1_3_null_1,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:9a03a4ba4a0a52dfb0c90f4fde244776222df5d00b76f4a41259f13f7847d81e -size 36850 +oid sha256:08d8714914bef5a1e5f353c43d5b7dbec7ff5c549402c723a0e875e1a8de2181 +size 36807 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.advanced_AdvancedSettingsView_null_AdvancedSettingsView-Night-1_3_null_2,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.advanced_AdvancedSettingsView_null_AdvancedSettingsView-Night-1_3_null_2,NEXUS_5,1.0,en].png index 48ba4870ab..7dafa3459b 100644 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.advanced_AdvancedSettingsView_null_AdvancedSettingsView-Night-1_3_null_2,NEXUS_5,1.0,en].png +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.advanced_AdvancedSettingsView_null_AdvancedSettingsView-Night-1_3_null_2,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:adc64ea11ab2a5ac4e1533e24ba1c7a75cc05d1722b26f949a9d97853b75450b -size 36795 +oid sha256:3eb3cbf3f0eeced3753b4b574cfcf1e8a5d86e7789e970f0a07089656cd16a18 +size 36818 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.advanced_AdvancedSettingsView_null_AdvancedSettingsView-Night-1_3_null_3,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.advanced_AdvancedSettingsView_null_AdvancedSettingsView-Night-1_3_null_3,NEXUS_5,1.0,en].png index 49dfb9077a..83b3fee634 100644 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.advanced_AdvancedSettingsView_null_AdvancedSettingsView-Night-1_3_null_3,NEXUS_5,1.0,en].png +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.advanced_AdvancedSettingsView_null_AdvancedSettingsView-Night-1_3_null_3,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:cf35986b43c0565658655241243d0704000e79131eb4f2291c2da8d66f014eaa -size 31009 +oid sha256:0a74667729b5980edce4103b5ce38bd97dbb4df0e50642489a1822128b4dcd75 +size 31280 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.analytics_AnalyticsSettingsView_null_AnalyticsSettingsView-Day-2_3_null_0,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.analytics_AnalyticsSettingsView_null_AnalyticsSettingsView-Day-2_3_null_0,NEXUS_5,1.0,en].png index c8c9509170..c15c1daddb 100644 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.analytics_AnalyticsSettingsView_null_AnalyticsSettingsView-Day-2_3_null_0,NEXUS_5,1.0,en].png +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.analytics_AnalyticsSettingsView_null_AnalyticsSettingsView-Day-2_3_null_0,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:23f5026bb468e841c9647d6ccc2cdc6eac52b18e5ad21b2c45192f6519141ff0 -size 26376 +oid sha256:2fc96ed56a48c2feaaa712ce57253678d0d79f834423aa5b41315df9213b4da9 +size 26277 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.analytics_AnalyticsSettingsView_null_AnalyticsSettingsView-Night-2_4_null_0,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.analytics_AnalyticsSettingsView_null_AnalyticsSettingsView-Night-2_4_null_0,NEXUS_5,1.0,en].png index e8127ff0ec..2e17aa53e4 100644 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.analytics_AnalyticsSettingsView_null_AnalyticsSettingsView-Night-2_4_null_0,NEXUS_5,1.0,en].png +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.analytics_AnalyticsSettingsView_null_AnalyticsSettingsView-Night-2_4_null_0,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:a8923a5a2b15b5cca3c9c77ebd587b60c7dacd7d68d04d9f8f671de2175d997f -size 25180 +oid sha256:a09f0d8c68fb4af7dcd239f342ec2d68b3d3af4720e27277d4bfd6e37c15541e +size 25141 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.developer.tracing_ConfigureTracingView_null_ConfigureTracingView-Day-4_5_null_0,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.developer.tracing_ConfigureTracingView_null_ConfigureTracingView-Day-4_5_null_0,NEXUS_5,1.0,en].png index 95be5a188b..618fea5b46 100644 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.developer.tracing_ConfigureTracingView_null_ConfigureTracingView-Day-4_5_null_0,NEXUS_5,1.0,en].png +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.developer.tracing_ConfigureTracingView_null_ConfigureTracingView-Day-4_5_null_0,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:093a2b69dfa7bacf90a2cd7e1d6643f008539166563bf19e3e544560d8c5c345 -size 35370 +oid sha256:89c50b83f37d5850baaf523ee2741b1b685dafe5a31f738f323ddf97ac14a642 +size 35529 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.developer.tracing_ConfigureTracingView_null_ConfigureTracingView-Night-4_6_null_0,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.developer.tracing_ConfigureTracingView_null_ConfigureTracingView-Night-4_6_null_0,NEXUS_5,1.0,en].png index 78ec8a14c5..27721e2069 100644 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.developer.tracing_ConfigureTracingView_null_ConfigureTracingView-Night-4_6_null_0,NEXUS_5,1.0,en].png +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.developer.tracing_ConfigureTracingView_null_ConfigureTracingView-Night-4_6_null_0,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:7cf27bfc83479f38722ad245a48fb5f0d64d47fe58f703c639cd3a9732e7d588 -size 31637 +oid sha256:fe4cd184987d4b0a545a8f3ce82b6bdb86d3a93038c0b4728008125cc40c5c77 +size 31818 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.notifications.edit_DefaultNotificationSettingOption_null_DefaultNotificationSettingOption-Day-7_8_null,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.notifications.edit_DefaultNotificationSettingOption_null_DefaultNotificationSettingOption-Day-7_8_null,NEXUS_5,1.0,en].png index dc66dbf5c9..9a2c5a84b3 100644 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.notifications.edit_DefaultNotificationSettingOption_null_DefaultNotificationSettingOption-Day-7_8_null,NEXUS_5,1.0,en].png +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.notifications.edit_DefaultNotificationSettingOption_null_DefaultNotificationSettingOption-Day-7_8_null,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:decba5aecbaf17385c6b92396b48ba7e8cb1d68c8319bef3334415cd42fee828 -size 36034 +oid sha256:f38cda30a54ee8b4c4f95e6303c9cca43b06fa0ce4c2d690c992b2037537453f +size 35986 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.notifications.edit_DefaultNotificationSettingOption_null_DefaultNotificationSettingOption-Night-7_9_null,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.notifications.edit_DefaultNotificationSettingOption_null_DefaultNotificationSettingOption-Night-7_9_null,NEXUS_5,1.0,en].png index d0bf3ae9aa..cb7908ac46 100644 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.notifications.edit_DefaultNotificationSettingOption_null_DefaultNotificationSettingOption-Night-7_9_null,NEXUS_5,1.0,en].png +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.notifications.edit_DefaultNotificationSettingOption_null_DefaultNotificationSettingOption-Night-7_9_null,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:97aec529c58486f1686e6c15f0cb9ed5286ed169115d8053b734bc491f724a28 -size 33309 +oid sha256:41896059efcfa8b424cd80cf93f233a263498222a8a555b6eb8cfa9a5f62d941 +size 33347 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.notifications.edit_EditDefaultNotificationSettingView_null_EditDefaultNotificationSettingView-Day-8_9_null_0,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.notifications.edit_EditDefaultNotificationSettingView_null_EditDefaultNotificationSettingView-Day-8_9_null_0,NEXUS_5,1.0,en].png index af36db4a67..c943b96993 100644 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.notifications.edit_EditDefaultNotificationSettingView_null_EditDefaultNotificationSettingView-Day-8_9_null_0,NEXUS_5,1.0,en].png +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.notifications.edit_EditDefaultNotificationSettingView_null_EditDefaultNotificationSettingView-Day-8_9_null_0,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:b927c63f95092c5345ceb35506e160c9ce6ce0348bba33d258c390cd8bd158de -size 35825 +oid sha256:1aaf3d3282191d2e775ef8c8184ed7c56fdc34f8649e1ff8e7ad9da8b8cb4a9d +size 35806 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.notifications.edit_EditDefaultNotificationSettingView_null_EditDefaultNotificationSettingView-Day-8_9_null_1,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.notifications.edit_EditDefaultNotificationSettingView_null_EditDefaultNotificationSettingView-Day-8_9_null_1,NEXUS_5,1.0,en].png index f52f17c794..5fdf152997 100644 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.notifications.edit_EditDefaultNotificationSettingView_null_EditDefaultNotificationSettingView-Day-8_9_null_1,NEXUS_5,1.0,en].png +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.notifications.edit_EditDefaultNotificationSettingView_null_EditDefaultNotificationSettingView-Day-8_9_null_1,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:6886af0b4f9e674aafd2674c6b77e707a08fb4a0f626169581ed3245b4241972 -size 35751 +oid sha256:7076ab247512b4b0c0e631d060e193af0f4d741e5819dcf891368b2b1f3cd890 +size 35739 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.notifications.edit_EditDefaultNotificationSettingView_null_EditDefaultNotificationSettingView-Day-8_9_null_2,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.notifications.edit_EditDefaultNotificationSettingView_null_EditDefaultNotificationSettingView-Day-8_9_null_2,NEXUS_5,1.0,en].png index aa0300ea79..4f7db1bf02 100644 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.notifications.edit_EditDefaultNotificationSettingView_null_EditDefaultNotificationSettingView-Day-8_9_null_2,NEXUS_5,1.0,en].png +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.notifications.edit_EditDefaultNotificationSettingView_null_EditDefaultNotificationSettingView-Day-8_9_null_2,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:ef4a2ee8e94f57164b5834fa331c37a3bf7bee15aae17fa3c5fb2a9c82e3e3a9 -size 33508 +oid sha256:5168d33c67566213cab7f71ee0fc71f151172dc8c5065e302249c6bd01cb751c +size 33507 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.notifications.edit_EditDefaultNotificationSettingView_null_EditDefaultNotificationSettingView-Day-8_9_null_3,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.notifications.edit_EditDefaultNotificationSettingView_null_EditDefaultNotificationSettingView-Day-8_9_null_3,NEXUS_5,1.0,en].png index ab746a0a59..e080a71d7c 100644 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.notifications.edit_EditDefaultNotificationSettingView_null_EditDefaultNotificationSettingView-Day-8_9_null_3,NEXUS_5,1.0,en].png +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.notifications.edit_EditDefaultNotificationSettingView_null_EditDefaultNotificationSettingView-Day-8_9_null_3,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:c1acca39f67a574b9b467827515b2f3442b4bb532a6d2cf3ad611ae79098815d -size 36659 +oid sha256:c264a1541965790ed5661a3a319e6d6a87e48cc85a95a3590d9595ad39deb760 +size 36654 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.notifications.edit_EditDefaultNotificationSettingView_null_EditDefaultNotificationSettingView-Day-8_9_null_4,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.notifications.edit_EditDefaultNotificationSettingView_null_EditDefaultNotificationSettingView-Day-8_9_null_4,NEXUS_5,1.0,en].png index 5455f6dd66..affc28ddb6 100644 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.notifications.edit_EditDefaultNotificationSettingView_null_EditDefaultNotificationSettingView-Day-8_9_null_4,NEXUS_5,1.0,en].png +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.notifications.edit_EditDefaultNotificationSettingView_null_EditDefaultNotificationSettingView-Day-8_9_null_4,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:78eab361860e4b4153a680fad703dc61c69c80a28af0a90b0a6add85178eea4f -size 49828 +oid sha256:f65c369e8f8c9526910f375b1d4b7166d1025a143400c6d53f61f3ce6537d67f +size 49858 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.notifications.edit_EditDefaultNotificationSettingView_null_EditDefaultNotificationSettingView-Night-8_10_null_0,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.notifications.edit_EditDefaultNotificationSettingView_null_EditDefaultNotificationSettingView-Night-8_10_null_0,NEXUS_5,1.0,en].png index a199e849e1..a13c0bc646 100644 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.notifications.edit_EditDefaultNotificationSettingView_null_EditDefaultNotificationSettingView-Night-8_10_null_0,NEXUS_5,1.0,en].png +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.notifications.edit_EditDefaultNotificationSettingView_null_EditDefaultNotificationSettingView-Night-8_10_null_0,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:99b99dd9caaecaf34f5a354251833375456c43e4c31bb2dc020b8caa396fe7e3 -size 33088 +oid sha256:e89d557862545f7468cefd88593d0995c813dc8871a92c94552ce26f9ae4651b +size 33066 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.notifications.edit_EditDefaultNotificationSettingView_null_EditDefaultNotificationSettingView-Night-8_10_null_1,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.notifications.edit_EditDefaultNotificationSettingView_null_EditDefaultNotificationSettingView-Night-8_10_null_1,NEXUS_5,1.0,en].png index b20052234e..9c4e212b7e 100644 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.notifications.edit_EditDefaultNotificationSettingView_null_EditDefaultNotificationSettingView-Night-8_10_null_1,NEXUS_5,1.0,en].png +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.notifications.edit_EditDefaultNotificationSettingView_null_EditDefaultNotificationSettingView-Night-8_10_null_1,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:c427f18e4dcb5539069bcb6cb2d81160208a21fa5d1ca0c4086aed27b92013e8 -size 33043 +oid sha256:d0fa8bac7f79b1a4feb4b7e808afae0c6b897867539c234daa9faea1bf6daf6e +size 33021 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.notifications.edit_EditDefaultNotificationSettingView_null_EditDefaultNotificationSettingView-Night-8_10_null_2,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.notifications.edit_EditDefaultNotificationSettingView_null_EditDefaultNotificationSettingView-Night-8_10_null_2,NEXUS_5,1.0,en].png index 5c1fbe5dfd..bc7f9d3c2c 100644 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.notifications.edit_EditDefaultNotificationSettingView_null_EditDefaultNotificationSettingView-Night-8_10_null_2,NEXUS_5,1.0,en].png +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.notifications.edit_EditDefaultNotificationSettingView_null_EditDefaultNotificationSettingView-Night-8_10_null_2,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:5d3d53b374e9b59ec860951fbcd1ddb566c90b3debe335c5cba8f2d9e55f508d -size 30346 +oid sha256:c8f2cc0a8cf7303aef994db2d23efb83b7a8a1c74af39dcef61ae3cfd3277c65 +size 30350 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.notifications.edit_EditDefaultNotificationSettingView_null_EditDefaultNotificationSettingView-Night-8_10_null_3,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.notifications.edit_EditDefaultNotificationSettingView_null_EditDefaultNotificationSettingView-Night-8_10_null_3,NEXUS_5,1.0,en].png index a7f1ffde07..0048715eb9 100644 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.notifications.edit_EditDefaultNotificationSettingView_null_EditDefaultNotificationSettingView-Night-8_10_null_3,NEXUS_5,1.0,en].png +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.notifications.edit_EditDefaultNotificationSettingView_null_EditDefaultNotificationSettingView-Night-8_10_null_3,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:0c85782934a98034a75e507f9c4e8316c1aa00e5628ae7fe3092b7f58ae3540c -size 32286 +oid sha256:5dfc5747625a6743966a518dd693cd8c55899ca241005df8179167b1728c2589 +size 32274 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.notifications.edit_EditDefaultNotificationSettingView_null_EditDefaultNotificationSettingView-Night-8_10_null_4,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.notifications.edit_EditDefaultNotificationSettingView_null_EditDefaultNotificationSettingView-Night-8_10_null_4,NEXUS_5,1.0,en].png index f731a246d9..4877789704 100644 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.notifications.edit_EditDefaultNotificationSettingView_null_EditDefaultNotificationSettingView-Night-8_10_null_4,NEXUS_5,1.0,en].png +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.notifications.edit_EditDefaultNotificationSettingView_null_EditDefaultNotificationSettingView-Night-8_10_null_4,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:29160e672d2bda2cdb69b7a2c2357316696637db23dc1de0665cc80308303399 -size 47051 +oid sha256:19e89d8cab891198e62951c0b08ed1318a14347795a35b5e8d94f6358c9f1964 +size 47052 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.root_PreferencesRootViewDark_null_PreferencesRootViewDark--1_1_null_0,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.root_PreferencesRootViewDark_null_PreferencesRootViewDark--1_1_null_0,NEXUS_5,1.0,en].png index b2db57cdb8..c0bca93bc2 100644 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.root_PreferencesRootViewDark_null_PreferencesRootViewDark--1_1_null_0,NEXUS_5,1.0,en].png +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.root_PreferencesRootViewDark_null_PreferencesRootViewDark--1_1_null_0,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:781e626db4e9491d1fd9d8098a6e62ece4d7034e1447d168583bdc5a308f371d -size 45249 +oid sha256:307c4fe957488e38390e1b0b14458be0551e7b2409b2c9b6b1da3a99f8eae1a6 +size 45163 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.root_PreferencesRootViewDark_null_PreferencesRootViewDark--1_1_null_1,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.root_PreferencesRootViewDark_null_PreferencesRootViewDark--1_1_null_1,NEXUS_5,1.0,en].png index 5dfbf46f31..b667353d66 100644 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.root_PreferencesRootViewDark_null_PreferencesRootViewDark--1_1_null_1,NEXUS_5,1.0,en].png +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.root_PreferencesRootViewDark_null_PreferencesRootViewDark--1_1_null_1,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:3d158b7003c5f84d9aab2ca85bcdce6011ce7ce7c1eede42a343d460610eddeb -size 44573 +oid sha256:9c88869958081e9752a1a6b4cf4a0b457b834b72bd691a48c333f5ee9239efbc +size 44481 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.root_PreferencesRootViewLight_null_PreferencesRootViewLight--0_0_null_0,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.root_PreferencesRootViewLight_null_PreferencesRootViewLight--0_0_null_0,NEXUS_5,1.0,en].png index 8c46bc7976..d8d6afb70b 100644 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.root_PreferencesRootViewLight_null_PreferencesRootViewLight--0_0_null_0,NEXUS_5,1.0,en].png +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.root_PreferencesRootViewLight_null_PreferencesRootViewLight--0_0_null_0,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:c9d7de855fc1442535920061110c4b7dd71535f90dd77e55469fdec1941b5d9f -size 48266 +oid sha256:f81f3e28243e1d1db8625979d49a9dd29338aac7900f21d1002694b8091d6bb4 +size 48221 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.root_PreferencesRootViewLight_null_PreferencesRootViewLight--0_0_null_1,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.root_PreferencesRootViewLight_null_PreferencesRootViewLight--0_0_null_1,NEXUS_5,1.0,en].png index 65f2b0c30e..fc89804281 100644 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.root_PreferencesRootViewLight_null_PreferencesRootViewLight--0_0_null_1,NEXUS_5,1.0,en].png +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.root_PreferencesRootViewLight_null_PreferencesRootViewLight--0_0_null_1,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:bab34cb8a11b8056c5f4a0ad10003eec4c2f5dbb128b4339e12c5687c8ade2e5 -size 48167 +oid sha256:4c0f01d3a1a3cd7845b02dbefef3dbfe564ecc6a19c6a29b598065fe45d5edcd +size 48119 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl.members.details_RoomMemberDetailsViewDark_null_RoomMemberDetailsViewDark--3_3_null_5,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl.members.details_RoomMemberDetailsViewDark_null_RoomMemberDetailsViewDark--3_3_null_5,NEXUS_5,1.0,en].png index baca4fe9e0..860c619371 100644 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl.members.details_RoomMemberDetailsViewDark_null_RoomMemberDetailsViewDark--3_3_null_5,NEXUS_5,1.0,en].png +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl.members.details_RoomMemberDetailsViewDark_null_RoomMemberDetailsViewDark--3_3_null_5,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:52009b1f8c129638c82568c0d23822cbed4de45f6ce49062aa38a79dfedecbe8 -size 23041 +oid sha256:59eeb239a62ee386b9a162bf82fec97e8834ace6ad59b21efd445f9e736b54cf +size 23046 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl.members.details_RoomMemberDetailsViewLight_null_RoomMemberDetailsViewLight--2_2_null_5,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl.members.details_RoomMemberDetailsViewLight_null_RoomMemberDetailsViewLight--2_2_null_5,NEXUS_5,1.0,en].png index 86f5985e6f..dde18f02d3 100644 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl.members.details_RoomMemberDetailsViewLight_null_RoomMemberDetailsViewLight--2_2_null_5,NEXUS_5,1.0,en].png +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl.members.details_RoomMemberDetailsViewLight_null_RoomMemberDetailsViewLight--2_2_null_5,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:fd3964a31217ccef0ba53ab1f5341311b52746b20660461220375dcad3befcec -size 24194 +oid sha256:935e5fe6677faea88995128ce60f3ce014eb6f434f33eff372fce9bb9192d503 +size 24191 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl.notificationsettings_RoomNotificationSettings_null_RoomNotificationSettings-Day-4_5_null_0,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl.notificationsettings_RoomNotificationSettings_null_RoomNotificationSettings-Day-4_5_null_0,NEXUS_5,1.0,en].png index 7e3f549840..cc6fb20b61 100644 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl.notificationsettings_RoomNotificationSettings_null_RoomNotificationSettings-Day-4_5_null_0,NEXUS_5,1.0,en].png +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl.notificationsettings_RoomNotificationSettings_null_RoomNotificationSettings-Day-4_5_null_0,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:695a934529456a82e99371e9b53231ac02f6d235174927fbb346bf2a5375aceb -size 33962 +oid sha256:44096d9f97614b5e84cf5dd0d966f674b47b50da065daaaa4a70476b3ecdcf91 +size 33908 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl.notificationsettings_RoomNotificationSettings_null_RoomNotificationSettings-Day-4_5_null_1,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl.notificationsettings_RoomNotificationSettings_null_RoomNotificationSettings-Day-4_5_null_1,NEXUS_5,1.0,en].png index 83a9e17db0..1dea7481b0 100644 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl.notificationsettings_RoomNotificationSettings_null_RoomNotificationSettings-Day-4_5_null_1,NEXUS_5,1.0,en].png +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl.notificationsettings_RoomNotificationSettings_null_RoomNotificationSettings-Day-4_5_null_1,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:4e406c5e173add3b29c3ad7a10e968d3bffc4627c7895bd2080826b832652ce1 -size 37783 +oid sha256:605ab2a5cc9b2b10c09908a2f9dd3629f1731742909936ae180c74855e32eed8 +size 37695 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl.notificationsettings_RoomNotificationSettings_null_RoomNotificationSettings-Day-4_5_null_2,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl.notificationsettings_RoomNotificationSettings_null_RoomNotificationSettings-Day-4_5_null_2,NEXUS_5,1.0,en].png index 079518de5a..830c17b5a7 100644 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl.notificationsettings_RoomNotificationSettings_null_RoomNotificationSettings-Day-4_5_null_2,NEXUS_5,1.0,en].png +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl.notificationsettings_RoomNotificationSettings_null_RoomNotificationSettings-Day-4_5_null_2,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:52fe76d305e114d5eeab85b608c5d86307ccd6fa0f283f4a806d64163d17c7b0 -size 33985 +oid sha256:ccab888ebe0e5ed94f2cb00117e3d69a888ad656b985768dc08e7fddacdceee7 +size 34011 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl.notificationsettings_RoomNotificationSettings_null_RoomNotificationSettings-Day-4_5_null_3,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl.notificationsettings_RoomNotificationSettings_null_RoomNotificationSettings-Day-4_5_null_3,NEXUS_5,1.0,en].png index 2d44a91eb7..8ed21af54b 100644 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl.notificationsettings_RoomNotificationSettings_null_RoomNotificationSettings-Day-4_5_null_3,NEXUS_5,1.0,en].png +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl.notificationsettings_RoomNotificationSettings_null_RoomNotificationSettings-Day-4_5_null_3,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:6e91c8c83e1a793bb8e0d306b98a4737187a5a5df7a47c67ac6a716696cff3fc -size 41208 +oid sha256:1510614f000837b743b847e616f7e40e86a259846058c1c0ea7a41233392117b +size 41239 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl.notificationsettings_RoomNotificationSettings_null_RoomNotificationSettings-Day-4_5_null_4,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl.notificationsettings_RoomNotificationSettings_null_RoomNotificationSettings-Day-4_5_null_4,NEXUS_5,1.0,en].png index 079518de5a..830c17b5a7 100644 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl.notificationsettings_RoomNotificationSettings_null_RoomNotificationSettings-Day-4_5_null_4,NEXUS_5,1.0,en].png +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl.notificationsettings_RoomNotificationSettings_null_RoomNotificationSettings-Day-4_5_null_4,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:52fe76d305e114d5eeab85b608c5d86307ccd6fa0f283f4a806d64163d17c7b0 -size 33985 +oid sha256:ccab888ebe0e5ed94f2cb00117e3d69a888ad656b985768dc08e7fddacdceee7 +size 34011 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl.notificationsettings_RoomNotificationSettings_null_RoomNotificationSettings-Day-4_5_null_5,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl.notificationsettings_RoomNotificationSettings_null_RoomNotificationSettings-Day-4_5_null_5,NEXUS_5,1.0,en].png index 2d44a91eb7..8ed21af54b 100644 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl.notificationsettings_RoomNotificationSettings_null_RoomNotificationSettings-Day-4_5_null_5,NEXUS_5,1.0,en].png +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl.notificationsettings_RoomNotificationSettings_null_RoomNotificationSettings-Day-4_5_null_5,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:6e91c8c83e1a793bb8e0d306b98a4737187a5a5df7a47c67ac6a716696cff3fc -size 41208 +oid sha256:1510614f000837b743b847e616f7e40e86a259846058c1c0ea7a41233392117b +size 41239 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl.notificationsettings_RoomNotificationSettings_null_RoomNotificationSettings-Day-4_5_null_6,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl.notificationsettings_RoomNotificationSettings_null_RoomNotificationSettings-Day-4_5_null_6,NEXUS_5,1.0,en].png index 7e3f549840..cc6fb20b61 100644 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl.notificationsettings_RoomNotificationSettings_null_RoomNotificationSettings-Day-4_5_null_6,NEXUS_5,1.0,en].png +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl.notificationsettings_RoomNotificationSettings_null_RoomNotificationSettings-Day-4_5_null_6,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:695a934529456a82e99371e9b53231ac02f6d235174927fbb346bf2a5375aceb -size 33962 +oid sha256:44096d9f97614b5e84cf5dd0d966f674b47b50da065daaaa4a70476b3ecdcf91 +size 33908 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl.notificationsettings_RoomNotificationSettings_null_RoomNotificationSettings-Night-4_6_null_0,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl.notificationsettings_RoomNotificationSettings_null_RoomNotificationSettings-Night-4_6_null_0,NEXUS_5,1.0,en].png index c38576522a..f9df86aa2f 100644 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl.notificationsettings_RoomNotificationSettings_null_RoomNotificationSettings-Night-4_6_null_0,NEXUS_5,1.0,en].png +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl.notificationsettings_RoomNotificationSettings_null_RoomNotificationSettings-Night-4_6_null_0,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:a128bd56c653706f65f20dac1e4110b21259e76821821057fe1e829044a1d36a -size 31523 +oid sha256:ef6d0fe324b2f622732cfbda77b55bd5debaf058eadd278f820a23de7c164103 +size 31553 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl.notificationsettings_RoomNotificationSettings_null_RoomNotificationSettings-Night-4_6_null_1,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl.notificationsettings_RoomNotificationSettings_null_RoomNotificationSettings-Night-4_6_null_1,NEXUS_5,1.0,en].png index 3f54ca9fa5..8443ee647a 100644 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl.notificationsettings_RoomNotificationSettings_null_RoomNotificationSettings-Night-4_6_null_1,NEXUS_5,1.0,en].png +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl.notificationsettings_RoomNotificationSettings_null_RoomNotificationSettings-Night-4_6_null_1,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:65bd05d8176f7d65f10ee3183f221afc73a759962a2e6b95067d3830a93d876c -size 34766 +oid sha256:4af656ee89190d8b818e2dfa1c260afca60c4b5f3e24ec6f4d30fe0cd2ed267d +size 34758 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl.notificationsettings_RoomNotificationSettings_null_RoomNotificationSettings-Night-4_6_null_2,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl.notificationsettings_RoomNotificationSettings_null_RoomNotificationSettings-Night-4_6_null_2,NEXUS_5,1.0,en].png index 1b92bf8947..858a3576a3 100644 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl.notificationsettings_RoomNotificationSettings_null_RoomNotificationSettings-Night-4_6_null_2,NEXUS_5,1.0,en].png +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl.notificationsettings_RoomNotificationSettings_null_RoomNotificationSettings-Night-4_6_null_2,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:f00202b17ca6c89dfdefc616888ceeb7272cfdb452745e8e034d556764983f7d -size 30717 +oid sha256:fddde23759a830f0e0ed9bab9d1754970ce2b2e8ffa78c02c458b090dbbb76aa +size 30719 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl.notificationsettings_RoomNotificationSettings_null_RoomNotificationSettings-Night-4_6_null_3,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl.notificationsettings_RoomNotificationSettings_null_RoomNotificationSettings-Night-4_6_null_3,NEXUS_5,1.0,en].png index 52d4323c1b..e3d95f0f75 100644 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl.notificationsettings_RoomNotificationSettings_null_RoomNotificationSettings-Night-4_6_null_3,NEXUS_5,1.0,en].png +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl.notificationsettings_RoomNotificationSettings_null_RoomNotificationSettings-Night-4_6_null_3,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:fec18df4d767d669a62d9adcef3d919332fb3af72f5bf2df349acc3e964fa78e -size 36634 +oid sha256:c78c34bc3f0df68b9130263ac5d35ac1c8b6f98a0e9aa0316461b473653dedc5 +size 36730 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl.notificationsettings_RoomNotificationSettings_null_RoomNotificationSettings-Night-4_6_null_4,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl.notificationsettings_RoomNotificationSettings_null_RoomNotificationSettings-Night-4_6_null_4,NEXUS_5,1.0,en].png index 1b92bf8947..858a3576a3 100644 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl.notificationsettings_RoomNotificationSettings_null_RoomNotificationSettings-Night-4_6_null_4,NEXUS_5,1.0,en].png +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl.notificationsettings_RoomNotificationSettings_null_RoomNotificationSettings-Night-4_6_null_4,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:f00202b17ca6c89dfdefc616888ceeb7272cfdb452745e8e034d556764983f7d -size 30717 +oid sha256:fddde23759a830f0e0ed9bab9d1754970ce2b2e8ffa78c02c458b090dbbb76aa +size 30719 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl.notificationsettings_RoomNotificationSettings_null_RoomNotificationSettings-Night-4_6_null_5,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl.notificationsettings_RoomNotificationSettings_null_RoomNotificationSettings-Night-4_6_null_5,NEXUS_5,1.0,en].png index 52d4323c1b..e3d95f0f75 100644 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl.notificationsettings_RoomNotificationSettings_null_RoomNotificationSettings-Night-4_6_null_5,NEXUS_5,1.0,en].png +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl.notificationsettings_RoomNotificationSettings_null_RoomNotificationSettings-Night-4_6_null_5,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:fec18df4d767d669a62d9adcef3d919332fb3af72f5bf2df349acc3e964fa78e -size 36634 +oid sha256:c78c34bc3f0df68b9130263ac5d35ac1c8b6f98a0e9aa0316461b473653dedc5 +size 36730 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl.notificationsettings_RoomNotificationSettings_null_RoomNotificationSettings-Night-4_6_null_6,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl.notificationsettings_RoomNotificationSettings_null_RoomNotificationSettings-Night-4_6_null_6,NEXUS_5,1.0,en].png index c38576522a..f9df86aa2f 100644 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl.notificationsettings_RoomNotificationSettings_null_RoomNotificationSettings-Night-4_6_null_6,NEXUS_5,1.0,en].png +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl.notificationsettings_RoomNotificationSettings_null_RoomNotificationSettings-Night-4_6_null_6,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:a128bd56c653706f65f20dac1e4110b21259e76821821057fe1e829044a1d36a -size 31523 +oid sha256:ef6d0fe324b2f622732cfbda77b55bd5debaf058eadd278f820a23de7c164103 +size 31553 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl.notificationsettings_RoomPrivacyOption_null_RoomPrivacyOption-Day-3_4_null,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl.notificationsettings_RoomPrivacyOption_null_RoomPrivacyOption-Day-3_4_null,NEXUS_5,1.0,en].png index a0944fea6b..c6d3aa92c7 100644 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl.notificationsettings_RoomPrivacyOption_null_RoomPrivacyOption-Day-3_4_null,NEXUS_5,1.0,en].png +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl.notificationsettings_RoomPrivacyOption_null_RoomPrivacyOption-Day-3_4_null,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:aa7de6ce541afcabc79fc1554809c217fd4f8bc83ed2c324342a9d28b9f34717 -size 31001 +oid sha256:3a3cb6371045e712f494857cd35268724936558550e7dc41344581fd2a1936c3 +size 31012 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl.notificationsettings_RoomPrivacyOption_null_RoomPrivacyOption-Night-3_5_null,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl.notificationsettings_RoomPrivacyOption_null_RoomPrivacyOption-Night-3_5_null,NEXUS_5,1.0,en].png index d9f5079c1a..a4e863f338 100644 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl.notificationsettings_RoomPrivacyOption_null_RoomPrivacyOption-Night-3_5_null,NEXUS_5,1.0,en].png +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl.notificationsettings_RoomPrivacyOption_null_RoomPrivacyOption-Night-3_5_null,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:9c7bdc732cc76ffcded6903e533ccb64d57d671f02a62093e63d0375fe0c680c -size 29016 +oid sha256:ee41b24ea7b2ca8b7c9fa568c0a66537ec9d39c7fc80bf99bfda1592156ec174 +size 29041 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl.notificationsettings_UserDefinedRoomNotificationSettings_null_UserDefinedRoomNotificationSettings-Day-5_6_null_0,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl.notificationsettings_UserDefinedRoomNotificationSettings_null_UserDefinedRoomNotificationSettings-Day-5_6_null_0,NEXUS_5,1.0,en].png index 4833897e83..d9c14068b9 100644 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl.notificationsettings_UserDefinedRoomNotificationSettings_null_UserDefinedRoomNotificationSettings-Day-5_6_null_0,NEXUS_5,1.0,en].png +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl.notificationsettings_UserDefinedRoomNotificationSettings_null_UserDefinedRoomNotificationSettings-Day-5_6_null_0,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:78cb940e6edfe0591071224fc7a8dcf32472633f56c38d55647dff40b042894b -size 24303 +oid sha256:ffb71a4dbd1324963ead4b188986a6c90dc6755a5d49e520c5aa74d3cce00384 +size 24290 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl.notificationsettings_UserDefinedRoomNotificationSettings_null_UserDefinedRoomNotificationSettings-Night-5_7_null_0,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl.notificationsettings_UserDefinedRoomNotificationSettings_null_UserDefinedRoomNotificationSettings-Night-5_7_null_0,NEXUS_5,1.0,en].png index edb45cf46d..43e51c8aaf 100644 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl.notificationsettings_UserDefinedRoomNotificationSettings_null_UserDefinedRoomNotificationSettings-Night-5_7_null_0,NEXUS_5,1.0,en].png +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl.notificationsettings_UserDefinedRoomNotificationSettings_null_UserDefinedRoomNotificationSettings-Night-5_7_null_0,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:52992127004c26595f2bfeb50c657a5628b18ffc10b8e6b260203504f44756fa -size 22787 +oid sha256:132d77ede5c96774b958b79ec3143c99a66734b04659796351a7b127ab3e2243 +size 22852 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl_RoomDetailsDark_null_RoomDetailsDark--1_1_null_0,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl_RoomDetailsDark_null_RoomDetailsDark--1_1_null_0,NEXUS_5,1.0,en].png index 7306748ca0..7cbf2f7f48 100644 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl_RoomDetailsDark_null_RoomDetailsDark--1_1_null_0,NEXUS_5,1.0,en].png +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl_RoomDetailsDark_null_RoomDetailsDark--1_1_null_0,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:d21e45a40de75a8ffc30e574f3f9a1f308616c5b9bf25de36d5277db5911c373 -size 52396 +oid sha256:703fd7531d62f1fc4be44fd223665abf3a8c533cd473300b605fde27ce72c273 +size 52403 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl_RoomDetailsDark_null_RoomDetailsDark--1_1_null_1,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl_RoomDetailsDark_null_RoomDetailsDark--1_1_null_1,NEXUS_5,1.0,en].png index e4e301ae45..50d98b9276 100644 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl_RoomDetailsDark_null_RoomDetailsDark--1_1_null_1,NEXUS_5,1.0,en].png +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl_RoomDetailsDark_null_RoomDetailsDark--1_1_null_1,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:55ffd8384b2b9bb21530512b0794afae3312a3344522973c200009f22b319a1b -size 48550 +oid sha256:345e007ece378018d657a4ee35b2698913cb5e843eeea6c5c511597032979083 +size 48555 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl_RoomDetailsDark_null_RoomDetailsDark--1_1_null_2,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl_RoomDetailsDark_null_RoomDetailsDark--1_1_null_2,NEXUS_5,1.0,en].png index c0a735b901..fed86aaff3 100644 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl_RoomDetailsDark_null_RoomDetailsDark--1_1_null_2,NEXUS_5,1.0,en].png +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl_RoomDetailsDark_null_RoomDetailsDark--1_1_null_2,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:998426a2ef42b3fcba4d833a94192ff84cdfca078e4e4beae76054677a517a20 -size 32722 +oid sha256:dba006c9bd847ccb9eafd5decd491058016f16dcb1daeed5bc8c142b2d8a6da3 +size 32717 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl_RoomDetailsDark_null_RoomDetailsDark--1_1_null_3,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl_RoomDetailsDark_null_RoomDetailsDark--1_1_null_3,NEXUS_5,1.0,en].png index 7306748ca0..7cbf2f7f48 100644 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl_RoomDetailsDark_null_RoomDetailsDark--1_1_null_3,NEXUS_5,1.0,en].png +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl_RoomDetailsDark_null_RoomDetailsDark--1_1_null_3,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:d21e45a40de75a8ffc30e574f3f9a1f308616c5b9bf25de36d5277db5911c373 -size 52396 +oid sha256:703fd7531d62f1fc4be44fd223665abf3a8c533cd473300b605fde27ce72c273 +size 52403 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl_RoomDetailsDark_null_RoomDetailsDark--1_1_null_4,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl_RoomDetailsDark_null_RoomDetailsDark--1_1_null_4,NEXUS_5,1.0,en].png index 429e87b82f..61a263ab0a 100644 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl_RoomDetailsDark_null_RoomDetailsDark--1_1_null_4,NEXUS_5,1.0,en].png +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl_RoomDetailsDark_null_RoomDetailsDark--1_1_null_4,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:4bf9b92e7f604738b91e09975c5ebfaee171a1c5aee7dce9f1b0a21ddac5cbc4 -size 50201 +oid sha256:dea742464c55cbb29188c7f944ed68b887daf09429a1c61c6a6d610332749a6c +size 50212 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl_RoomDetailsDark_null_RoomDetailsDark--1_1_null_7,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl_RoomDetailsDark_null_RoomDetailsDark--1_1_null_7,NEXUS_5,1.0,en].png index 7306748ca0..7cbf2f7f48 100644 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl_RoomDetailsDark_null_RoomDetailsDark--1_1_null_7,NEXUS_5,1.0,en].png +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl_RoomDetailsDark_null_RoomDetailsDark--1_1_null_7,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:d21e45a40de75a8ffc30e574f3f9a1f308616c5b9bf25de36d5277db5911c373 -size 52396 +oid sha256:703fd7531d62f1fc4be44fd223665abf3a8c533cd473300b605fde27ce72c273 +size 52403 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl_RoomDetailsDark_null_RoomDetailsDark--1_1_null_8,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl_RoomDetailsDark_null_RoomDetailsDark--1_1_null_8,NEXUS_5,1.0,en].png index 534f9f2a3a..dffa826a6c 100644 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl_RoomDetailsDark_null_RoomDetailsDark--1_1_null_8,NEXUS_5,1.0,en].png +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl_RoomDetailsDark_null_RoomDetailsDark--1_1_null_8,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:9992ccb1e020cb09e29c36285fc6acde477ccb2c53b5ab36d8fd6c19fbaf392c -size 52236 +oid sha256:dd08c741a1ac7de4bf60c30b42d9fa085ec4c11a9d95e8988131a4e9215ac88c +size 52239 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl_RoomDetails_null_RoomDetails--0_0_null_0,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl_RoomDetails_null_RoomDetails--0_0_null_0,NEXUS_5,1.0,en].png index 6bb74c767d..c19ffb2865 100644 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl_RoomDetails_null_RoomDetails--0_0_null_0,NEXUS_5,1.0,en].png +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl_RoomDetails_null_RoomDetails--0_0_null_0,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:8a9cbc71ab3bc94c2bf38d89f453f9c14ed94fba96ab2c1cba5abe8169e4157c -size 53609 +oid sha256:f0ba3767a5696b9b57786ac56a8a23828062aaa9ffde62e0f9f3226edcf95841 +size 53594 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl_RoomDetails_null_RoomDetails--0_0_null_1,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl_RoomDetails_null_RoomDetails--0_0_null_1,NEXUS_5,1.0,en].png index 88c9263e98..067e66075b 100644 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl_RoomDetails_null_RoomDetails--0_0_null_1,NEXUS_5,1.0,en].png +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl_RoomDetails_null_RoomDetails--0_0_null_1,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:4f32621601d9acf2db4072cc990e655b2c6733a0429107e0c3525ceaa5ef18a4 -size 51222 +oid sha256:a4a2a602f024a9bc0d03aada3c91c1d3013f84bf6de6443ce4b7ce040df0212d +size 51262 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl_RoomDetails_null_RoomDetails--0_0_null_2,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl_RoomDetails_null_RoomDetails--0_0_null_2,NEXUS_5,1.0,en].png index b1894d9d16..aa9b67672b 100644 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl_RoomDetails_null_RoomDetails--0_0_null_2,NEXUS_5,1.0,en].png +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl_RoomDetails_null_RoomDetails--0_0_null_2,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:47df27bc44852fbf357b45b995365edc29d3d8ecebf1d5c93149416835b71b9a -size 34381 +oid sha256:85b10ff2a36e5bcbf8f24c429be6cb4aac76f9e36a19c4af07534870c6b80d3e +size 34360 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl_RoomDetails_null_RoomDetails--0_0_null_3,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl_RoomDetails_null_RoomDetails--0_0_null_3,NEXUS_5,1.0,en].png index 6bb74c767d..c19ffb2865 100644 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl_RoomDetails_null_RoomDetails--0_0_null_3,NEXUS_5,1.0,en].png +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl_RoomDetails_null_RoomDetails--0_0_null_3,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:8a9cbc71ab3bc94c2bf38d89f453f9c14ed94fba96ab2c1cba5abe8169e4157c -size 53609 +oid sha256:f0ba3767a5696b9b57786ac56a8a23828062aaa9ffde62e0f9f3226edcf95841 +size 53594 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl_RoomDetails_null_RoomDetails--0_0_null_4,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl_RoomDetails_null_RoomDetails--0_0_null_4,NEXUS_5,1.0,en].png index 9832639e4c..802d8d353e 100644 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl_RoomDetails_null_RoomDetails--0_0_null_4,NEXUS_5,1.0,en].png +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl_RoomDetails_null_RoomDetails--0_0_null_4,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:2b59de4767530724d5d4bf6e38f6b198db7fe1c88863efaae28933536de6e13c -size 51552 +oid sha256:319b14b73b8e57004fb8528815ddeacb123f245beee5009831b0f151aab9ad1b +size 51560 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl_RoomDetails_null_RoomDetails--0_0_null_7,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl_RoomDetails_null_RoomDetails--0_0_null_7,NEXUS_5,1.0,en].png index 6bb74c767d..c19ffb2865 100644 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl_RoomDetails_null_RoomDetails--0_0_null_7,NEXUS_5,1.0,en].png +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl_RoomDetails_null_RoomDetails--0_0_null_7,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:8a9cbc71ab3bc94c2bf38d89f453f9c14ed94fba96ab2c1cba5abe8169e4157c -size 53609 +oid sha256:f0ba3767a5696b9b57786ac56a8a23828062aaa9ffde62e0f9f3226edcf95841 +size 53594 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl_RoomDetails_null_RoomDetails--0_0_null_8,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl_RoomDetails_null_RoomDetails--0_0_null_8,NEXUS_5,1.0,en].png index 7bc1e268c6..37f403fc71 100644 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl_RoomDetails_null_RoomDetails--0_0_null_8,NEXUS_5,1.0,en].png +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl_RoomDetails_null_RoomDetails--0_0_null_8,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:920cbdf29ae6d68182bf0e819878f894d6878f9b347bf6a3945c601ca696f0f8 -size 53391 +oid sha256:d3818906c06db9eae696b5891ccdccec16b8b4ed56c2dfaea506656736c2f917 +size 53377 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.securebackup.impl.root_SecureBackupRootView_null_SecureBackupRootView-Day-3_4_null_0,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.securebackup.impl.root_SecureBackupRootView_null_SecureBackupRootView-Day-3_4_null_0,NEXUS_5,1.0,en].png index 35f3978407..8ebe25663e 100644 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.securebackup.impl.root_SecureBackupRootView_null_SecureBackupRootView-Day-3_4_null_0,NEXUS_5,1.0,en].png +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.securebackup.impl.root_SecureBackupRootView_null_SecureBackupRootView-Day-3_4_null_0,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:157d7e71b29ed9fcf5b9d7169820183f947524ee109fd9c7de73d356405cb1a5 -size 41472 +oid sha256:3a7f593e3909ea3e881cef0ea7a6e25a9a4be3479d0409be55194547161372bf +size 41391 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.securebackup.impl.root_SecureBackupRootView_null_SecureBackupRootView-Day-3_4_null_3,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.securebackup.impl.root_SecureBackupRootView_null_SecureBackupRootView-Day-3_4_null_3,NEXUS_5,1.0,en].png index 4df26e43d7..df3ddb0ce2 100644 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.securebackup.impl.root_SecureBackupRootView_null_SecureBackupRootView-Day-3_4_null_3,NEXUS_5,1.0,en].png +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.securebackup.impl.root_SecureBackupRootView_null_SecureBackupRootView-Day-3_4_null_3,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:e6dd323965929e2da99f8f0c2a33db09ecfd89804fc0f09a9852ee70ae5047cb -size 47989 +oid sha256:a6baa85d5b8b544b53ea864739cc77f3bb96d26bbdb6956b74dda70255888086 +size 47999 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.securebackup.impl.root_SecureBackupRootView_null_SecureBackupRootView-Day-3_4_null_5,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.securebackup.impl.root_SecureBackupRootView_null_SecureBackupRootView-Day-3_4_null_5,NEXUS_5,1.0,en].png index 35f3978407..8ebe25663e 100644 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.securebackup.impl.root_SecureBackupRootView_null_SecureBackupRootView-Day-3_4_null_5,NEXUS_5,1.0,en].png +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.securebackup.impl.root_SecureBackupRootView_null_SecureBackupRootView-Day-3_4_null_5,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:157d7e71b29ed9fcf5b9d7169820183f947524ee109fd9c7de73d356405cb1a5 -size 41472 +oid sha256:3a7f593e3909ea3e881cef0ea7a6e25a9a4be3479d0409be55194547161372bf +size 41391 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.securebackup.impl.root_SecureBackupRootView_null_SecureBackupRootView-Day-3_4_null_6,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.securebackup.impl.root_SecureBackupRootView_null_SecureBackupRootView-Day-3_4_null_6,NEXUS_5,1.0,en].png index b3ff9c85af..d9cfec35ae 100644 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.securebackup.impl.root_SecureBackupRootView_null_SecureBackupRootView-Day-3_4_null_6,NEXUS_5,1.0,en].png +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.securebackup.impl.root_SecureBackupRootView_null_SecureBackupRootView-Day-3_4_null_6,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:8c06dfd2c060f6e94dde6b5eabe3f3e64fd36246c5c8b4f2c4472b4e27084bd0 -size 26338 +oid sha256:3bde78253bb21d2d5edc97f80ca6f7ae8cd0a710b5544803c998d3cec5b4fef2 +size 26273 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.securebackup.impl.root_SecureBackupRootView_null_SecureBackupRootView-Day-3_4_null_7,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.securebackup.impl.root_SecureBackupRootView_null_SecureBackupRootView-Day-3_4_null_7,NEXUS_5,1.0,en].png index 35f3978407..8ebe25663e 100644 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.securebackup.impl.root_SecureBackupRootView_null_SecureBackupRootView-Day-3_4_null_7,NEXUS_5,1.0,en].png +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.securebackup.impl.root_SecureBackupRootView_null_SecureBackupRootView-Day-3_4_null_7,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:157d7e71b29ed9fcf5b9d7169820183f947524ee109fd9c7de73d356405cb1a5 -size 41472 +oid sha256:3a7f593e3909ea3e881cef0ea7a6e25a9a4be3479d0409be55194547161372bf +size 41391 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.securebackup.impl.root_SecureBackupRootView_null_SecureBackupRootView-Day-3_4_null_8,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.securebackup.impl.root_SecureBackupRootView_null_SecureBackupRootView-Day-3_4_null_8,NEXUS_5,1.0,en].png index 14f108d258..7e29d8a767 100644 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.securebackup.impl.root_SecureBackupRootView_null_SecureBackupRootView-Day-3_4_null_8,NEXUS_5,1.0,en].png +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.securebackup.impl.root_SecureBackupRootView_null_SecureBackupRootView-Day-3_4_null_8,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:1ed7f0090053318b0051e3cbe8a42a356a6019659460e0ddbd9dbcd7d3b7f397 -size 31937 +oid sha256:32309b5e76458bba374dfaff461f927eb752b316ae88ed8480393d951cc9f08f +size 31847 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.securebackup.impl.root_SecureBackupRootView_null_SecureBackupRootView-Night-3_5_null_0,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.securebackup.impl.root_SecureBackupRootView_null_SecureBackupRootView-Night-3_5_null_0,NEXUS_5,1.0,en].png index b56733b351..e00972462d 100644 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.securebackup.impl.root_SecureBackupRootView_null_SecureBackupRootView-Night-3_5_null_0,NEXUS_5,1.0,en].png +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.securebackup.impl.root_SecureBackupRootView_null_SecureBackupRootView-Night-3_5_null_0,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:75372f01fcd2cbad5802a505c1150ec6e14484cf89ab700e6ec2e5c5f9e16a8a -size 39453 +oid sha256:c9120fdfd75820c68d972ee3f6a01486b844fbfa6b200ee070ac109998fe76a6 +size 39339 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.securebackup.impl.root_SecureBackupRootView_null_SecureBackupRootView-Night-3_5_null_3,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.securebackup.impl.root_SecureBackupRootView_null_SecureBackupRootView-Night-3_5_null_3,NEXUS_5,1.0,en].png index 7eb2c617d0..54686aed66 100644 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.securebackup.impl.root_SecureBackupRootView_null_SecureBackupRootView-Night-3_5_null_3,NEXUS_5,1.0,en].png +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.securebackup.impl.root_SecureBackupRootView_null_SecureBackupRootView-Night-3_5_null_3,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:8dc4996be5af5a42d91e9f0fb371c821247264d980bde56e870441750fb439e0 -size 45328 +oid sha256:db5e8d9d9b78fb46ca40261fd5abce652b3dd29623205ef3935ced21278812f1 +size 45352 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.securebackup.impl.root_SecureBackupRootView_null_SecureBackupRootView-Night-3_5_null_5,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.securebackup.impl.root_SecureBackupRootView_null_SecureBackupRootView-Night-3_5_null_5,NEXUS_5,1.0,en].png index b56733b351..e00972462d 100644 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.securebackup.impl.root_SecureBackupRootView_null_SecureBackupRootView-Night-3_5_null_5,NEXUS_5,1.0,en].png +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.securebackup.impl.root_SecureBackupRootView_null_SecureBackupRootView-Night-3_5_null_5,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:75372f01fcd2cbad5802a505c1150ec6e14484cf89ab700e6ec2e5c5f9e16a8a -size 39453 +oid sha256:c9120fdfd75820c68d972ee3f6a01486b844fbfa6b200ee070ac109998fe76a6 +size 39339 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.securebackup.impl.root_SecureBackupRootView_null_SecureBackupRootView-Night-3_5_null_6,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.securebackup.impl.root_SecureBackupRootView_null_SecureBackupRootView-Night-3_5_null_6,NEXUS_5,1.0,en].png index ad47b678e1..0983cab044 100644 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.securebackup.impl.root_SecureBackupRootView_null_SecureBackupRootView-Night-3_5_null_6,NEXUS_5,1.0,en].png +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.securebackup.impl.root_SecureBackupRootView_null_SecureBackupRootView-Night-3_5_null_6,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:bb6d0f7866767b529ed58e642d45cde89da0535b2d024921dde19d47808206a2 -size 25094 +oid sha256:ee7588bd823e9d59ee5797d2ce41b64d933ead7fd3ca9c09b99b40ce007f9e7e +size 25006 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.securebackup.impl.root_SecureBackupRootView_null_SecureBackupRootView-Night-3_5_null_7,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.securebackup.impl.root_SecureBackupRootView_null_SecureBackupRootView-Night-3_5_null_7,NEXUS_5,1.0,en].png index b56733b351..e00972462d 100644 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.securebackup.impl.root_SecureBackupRootView_null_SecureBackupRootView-Night-3_5_null_7,NEXUS_5,1.0,en].png +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.securebackup.impl.root_SecureBackupRootView_null_SecureBackupRootView-Night-3_5_null_7,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:75372f01fcd2cbad5802a505c1150ec6e14484cf89ab700e6ec2e5c5f9e16a8a -size 39453 +oid sha256:c9120fdfd75820c68d972ee3f6a01486b844fbfa6b200ee070ac109998fe76a6 +size 39339 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.securebackup.impl.root_SecureBackupRootView_null_SecureBackupRootView-Night-3_5_null_8,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.securebackup.impl.root_SecureBackupRootView_null_SecureBackupRootView-Night-3_5_null_8,NEXUS_5,1.0,en].png index 88c330d340..6c3b95dd8f 100644 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.securebackup.impl.root_SecureBackupRootView_null_SecureBackupRootView-Night-3_5_null_8,NEXUS_5,1.0,en].png +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.securebackup.impl.root_SecureBackupRootView_null_SecureBackupRootView-Night-3_5_null_8,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:4fd29e5953cd9782b7748beae7078011147129cecfcadadd7fc04533f7fdd3f5 -size 30053 +oid sha256:4c70eb14daac4d7d3eceb3c60ad2547ead74a3e5b282f324e9d2e3d503c01d3d +size 29926 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[l.designsystem.components.list_MutipleSelectionListItemSelectedTrailingContent_null_Listitems_MultipleselectionListitem-selectionintrailingcontent_0_null,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[l.designsystem.components.list_MutipleSelectionListItemSelectedTrailingContent_null_Listitems_MultipleselectionListitem-selectionintrailingcontent_0_null,NEXUS_5,1.0,en].png index ec20ff6d63..02d6abe00e 100644 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[l.designsystem.components.list_MutipleSelectionListItemSelectedTrailingContent_null_Listitems_MultipleselectionListitem-selectionintrailingcontent_0_null,NEXUS_5,1.0,en].png +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[l.designsystem.components.list_MutipleSelectionListItemSelectedTrailingContent_null_Listitems_MultipleselectionListitem-selectionintrailingcontent_0_null,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:3a0eb132bfaf1c90c6507c12b25150fb29e260ae3bd0a5760f5fb2e9483fda26 -size 14814 +oid sha256:1e933541422476dbb3005b41f15bed9c496994038ca1e184a3ab7e5bd10a1b1a +size 14840 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[l.designsystem.components.list_SingleSelectionListItemCustomFormattert_null_Listitems_SingleselectionListitem-customformatter_0_null,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[l.designsystem.components.list_SingleSelectionListItemCustomFormattert_null_Listitems_SingleselectionListitem-customformatter_0_null,NEXUS_5,1.0,en].png index 3d0c5e4a60..75c35c0aef 100644 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[l.designsystem.components.list_SingleSelectionListItemCustomFormattert_null_Listitems_SingleselectionListitem-customformatter_0_null,NEXUS_5,1.0,en].png +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[l.designsystem.components.list_SingleSelectionListItemCustomFormattert_null_Listitems_SingleselectionListitem-customformatter_0_null,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:624a00c3098b821482dcdb9529db12cfcf46dc82e136d8b255561125e932862b -size 19467 +oid sha256:b190eb5cc3b94192df7875a67808923909556b010aca26942e06668cd5da0926 +size 19469 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[l.designsystem.components.list_SingleSelectionListItemSelectedInTrailingContent_null_Listitems_SingleselectionListitem-selectionintrailingcontent_0_null,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[l.designsystem.components.list_SingleSelectionListItemSelectedInTrailingContent_null_Listitems_SingleselectionListitem-selectionintrailingcontent_0_null,NEXUS_5,1.0,en].png index 41bc1be58d..e76ecdc0ca 100644 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[l.designsystem.components.list_SingleSelectionListItemSelectedInTrailingContent_null_Listitems_SingleselectionListitem-selectionintrailingcontent_0_null,NEXUS_5,1.0,en].png +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[l.designsystem.components.list_SingleSelectionListItemSelectedInTrailingContent_null_Listitems_SingleselectionListitem-selectionintrailingcontent_0_null,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:a2ffe9b836ee6dc753f7e6faf10814d7a52611cd1ff9d11a539cc045fdafc1db -size 17227 +oid sha256:508b80ed156ebc2ccf195470716ef635f2ac539d0d9ea08ea2c7263d51359b2a +size 17196 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[l.designsystem.theme.components_ListItemSingleLineBothIcons_null_Listitems_Listitem(1line)-BothIcons_0_null,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[l.designsystem.theme.components_ListItemSingleLineBothIcons_null_Listitems_Listitem(1line)-BothIcons_0_null,NEXUS_5,1.0,en].png index 93f7aafb6a..6b25b95fc2 100644 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[l.designsystem.theme.components_ListItemSingleLineBothIcons_null_Listitems_Listitem(1line)-BothIcons_0_null,NEXUS_5,1.0,en].png +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[l.designsystem.theme.components_ListItemSingleLineBothIcons_null_Listitems_Listitem(1line)-BothIcons_0_null,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:72de6bcb547e59838b8ff5b5a990a421303ed3c9d42e792e76ef74e2abfb4f7f -size 11796 +oid sha256:40dc538cc402212b5773c911b7a745dda517daab6857d40443111b479c4c0e0a +size 11799 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[l.designsystem.theme.components_ListItemSingleLineTrailingCheckBox_null_Listitems_Listitem(1line)-TrailingCheckbox_0_null,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[l.designsystem.theme.components_ListItemSingleLineTrailingCheckBox_null_Listitems_Listitem(1line)-TrailingCheckbox_0_null,NEXUS_5,1.0,en].png index 901ada774e..4702ca344b 100644 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[l.designsystem.theme.components_ListItemSingleLineTrailingCheckBox_null_Listitems_Listitem(1line)-TrailingCheckbox_0_null,NEXUS_5,1.0,en].png +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[l.designsystem.theme.components_ListItemSingleLineTrailingCheckBox_null_Listitems_Listitem(1line)-TrailingCheckbox_0_null,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:8c8574785958bacf0eb45b3d135d3caae7c6fe045df773b5f7b6f03dce942130 -size 8584 +oid sha256:591a0a1615045c701ae46a227dc5b4f6ce6de24b02cb8207d6a22f795e481067 +size 8551 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[l.designsystem.theme.components_ListItemSingleLineTrailingIcon_null_Listitems_Listitem(1line)-TrailingIcon_0_null,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[l.designsystem.theme.components_ListItemSingleLineTrailingIcon_null_Listitems_Listitem(1line)-TrailingIcon_0_null,NEXUS_5,1.0,en].png index 0ae8d95be4..ea2e4b8b8f 100644 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[l.designsystem.theme.components_ListItemSingleLineTrailingIcon_null_Listitems_Listitem(1line)-TrailingIcon_0_null,NEXUS_5,1.0,en].png +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[l.designsystem.theme.components_ListItemSingleLineTrailingIcon_null_Listitems_Listitem(1line)-TrailingIcon_0_null,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:354685b1a042ebcee89e5afbf9c45954d6615242d55fb07ad7a0b6638bee1570 -size 10034 +oid sha256:0dba13e8f7515785485731fa0e6ffe8dcd950a038030970b9d4bf68031e8d781 +size 10035 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[l.designsystem.theme.components_ListItemSingleLineTrailingRadioButton_null_Listitems_Listitem(1line)-TrailingRadioButton_0_null,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[l.designsystem.theme.components_ListItemSingleLineTrailingRadioButton_null_Listitems_Listitem(1line)-TrailingRadioButton_0_null,NEXUS_5,1.0,en].png index 39306b89a3..fc5b11f399 100644 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[l.designsystem.theme.components_ListItemSingleLineTrailingRadioButton_null_Listitems_Listitem(1line)-TrailingRadioButton_0_null,NEXUS_5,1.0,en].png +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[l.designsystem.theme.components_ListItemSingleLineTrailingRadioButton_null_Listitems_Listitem(1line)-TrailingRadioButton_0_null,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:8d5d62ab71228dd0042560487fc754066a71309d28884184ee5f0e4383885f07 -size 9990 +oid sha256:270538751aa40a82dc396ea812e39220635e77a9bc98079ff379d979840225e6 +size 9976 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[l.designsystem.theme.components_ListItemSingleLineTrailingSwitch_null_Listitems_Listitem(1line)-TrailingSwitch_0_null,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[l.designsystem.theme.components_ListItemSingleLineTrailingSwitch_null_Listitems_Listitem(1line)-TrailingSwitch_0_null,NEXUS_5,1.0,en].png index 946961f399..c1725b1e91 100644 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[l.designsystem.theme.components_ListItemSingleLineTrailingSwitch_null_Listitems_Listitem(1line)-TrailingSwitch_0_null,NEXUS_5,1.0,en].png +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[l.designsystem.theme.components_ListItemSingleLineTrailingSwitch_null_Listitems_Listitem(1line)-TrailingSwitch_0_null,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:3b956cd168b4698d187236b0a9684f090c1ea4ab02371ac821d167c8b94a7ad2 -size 12351 +oid sha256:927992271bc2538ba03225268eb8173a49faab1b965f8afdcdb69b040e1c855b +size 12412 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[l.designsystem.theme.components_ListItemThreeLinesBothIcons_null_Listitems_Listitem(3lines)-BothIcons_0_null,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[l.designsystem.theme.components_ListItemThreeLinesBothIcons_null_Listitems_Listitem(3lines)-BothIcons_0_null,NEXUS_5,1.0,en].png index cc80e94ce4..cdf2625dea 100644 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[l.designsystem.theme.components_ListItemThreeLinesBothIcons_null_Listitems_Listitem(3lines)-BothIcons_0_null,NEXUS_5,1.0,en].png +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[l.designsystem.theme.components_ListItemThreeLinesBothIcons_null_Listitems_Listitem(3lines)-BothIcons_0_null,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:1d291b3f0d64c7d6ca9cf39daf65959aafd6438e3a16392459ea2d65e7e9ac4d -size 28279 +oid sha256:4e8cd9b62dbf66835ca31488b23ddc0d7eddc24aff989f74f9d08f5a570c51da +size 28264 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[l.designsystem.theme.components_ListItemThreeLinesLeadingSwitch_null_Listitems_Listitem(3lines)-LeadingSwitch_0_null,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[l.designsystem.theme.components_ListItemThreeLinesLeadingSwitch_null_Listitems_Listitem(3lines)-LeadingSwitch_0_null,NEXUS_5,1.0,en].png index c34ecc4fa6..d950af3bbe 100644 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[l.designsystem.theme.components_ListItemThreeLinesLeadingSwitch_null_Listitems_Listitem(3lines)-LeadingSwitch_0_null,NEXUS_5,1.0,en].png +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[l.designsystem.theme.components_ListItemThreeLinesLeadingSwitch_null_Listitems_Listitem(3lines)-LeadingSwitch_0_null,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:3f523d5c94ef05f62337494dfec70cd671bbc30359c4ef403796324c3821e835 -size 28706 +oid sha256:089ddf983b2c0df22caa26ecb486810b90d7c59682b3594fe254fa39fc00f5a4 +size 28643 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[l.designsystem.theme.components_ListItemThreeLinesTrailingCheckBox_null_Listitems_Listitem(3lines)-TrailingCheckbox_0_null,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[l.designsystem.theme.components_ListItemThreeLinesTrailingCheckBox_null_Listitems_Listitem(3lines)-TrailingCheckbox_0_null,NEXUS_5,1.0,en].png index 21b2c1f1ad..ff4fd8adbf 100644 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[l.designsystem.theme.components_ListItemThreeLinesTrailingCheckBox_null_Listitems_Listitem(3lines)-TrailingCheckbox_0_null,NEXUS_5,1.0,en].png +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[l.designsystem.theme.components_ListItemThreeLinesTrailingCheckBox_null_Listitems_Listitem(3lines)-TrailingCheckbox_0_null,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:46f8f65468d81744980f72e9e472c8aae86cfa5ba1ef8b02260aa2c925c0ef31 -size 25848 +oid sha256:d0b99df7aad067aa874e1d15503cf8396f30d07e2eb36975cd82d9207139101b +size 25812 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[l.designsystem.theme.components_ListItemThreeLinesTrailingIcon_null_Listitems_Listitem(3lines)-TrailingIcon_0_null,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[l.designsystem.theme.components_ListItemThreeLinesTrailingIcon_null_Listitems_Listitem(3lines)-TrailingIcon_0_null,NEXUS_5,1.0,en].png index d205083740..fff1be641b 100644 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[l.designsystem.theme.components_ListItemThreeLinesTrailingIcon_null_Listitems_Listitem(3lines)-TrailingIcon_0_null,NEXUS_5,1.0,en].png +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[l.designsystem.theme.components_ListItemThreeLinesTrailingIcon_null_Listitems_Listitem(3lines)-TrailingIcon_0_null,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:5b2280812773385a3aeee9d090b2ce6a5bb1e25a426d88ed7c9e33be300262be -size 26942 +oid sha256:83c59bc2e1fd4f37eb4449c4bd5b44894fd8b1b02ea6f8badf907c219d500faa +size 26927 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[l.designsystem.theme.components_ListItemThreeLinesTrailingRadioButton_null_Listitems_Listitem(3lines)-TrailingRadioButton_0_null,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[l.designsystem.theme.components_ListItemThreeLinesTrailingRadioButton_null_Listitems_Listitem(3lines)-TrailingRadioButton_0_null,NEXUS_5,1.0,en].png index 2831d074c7..4943bb3517 100644 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[l.designsystem.theme.components_ListItemThreeLinesTrailingRadioButton_null_Listitems_Listitem(3lines)-TrailingRadioButton_0_null,NEXUS_5,1.0,en].png +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[l.designsystem.theme.components_ListItemThreeLinesTrailingRadioButton_null_Listitems_Listitem(3lines)-TrailingRadioButton_0_null,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:b5b7661174bf47510f3a639030aa85187d7b3c41facadc94cf02e15e976f5923 -size 26836 +oid sha256:3cf0730bf5fb2b58b699f9527663cdb3e772b1fcf26b3410c288d31ec7bf8d59 +size 26777 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[l.designsystem.theme.components_ListItemThreeLinesTrailingSwitch_null_Listitems_Listitem(3lines)-TrailingSwitch_0_null,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[l.designsystem.theme.components_ListItemThreeLinesTrailingSwitch_null_Listitems_Listitem(3lines)-TrailingSwitch_0_null,NEXUS_5,1.0,en].png index ff8ce22514..d14ad2d497 100644 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[l.designsystem.theme.components_ListItemThreeLinesTrailingSwitch_null_Listitems_Listitem(3lines)-TrailingSwitch_0_null,NEXUS_5,1.0,en].png +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[l.designsystem.theme.components_ListItemThreeLinesTrailingSwitch_null_Listitems_Listitem(3lines)-TrailingSwitch_0_null,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:3dbba64c730837cc376dca1b37a65ae1335199c3209ad1ae7c28aa55377a778e -size 28588 +oid sha256:684a875d6bb070f49128799f670d2a2fb2852880048c9413ad9a5f0d563c8cf7 +size 28518 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[l.designsystem.theme.components_ListItemTwoLinesBothIcons_null_Listitems_Listitem(2lines)-BothIcons_0_null,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[l.designsystem.theme.components_ListItemTwoLinesBothIcons_null_Listitems_Listitem(2lines)-BothIcons_0_null,NEXUS_5,1.0,en].png index 821fe8cac7..858cf9a710 100644 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[l.designsystem.theme.components_ListItemTwoLinesBothIcons_null_Listitems_Listitem(2lines)-BothIcons_0_null,NEXUS_5,1.0,en].png +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[l.designsystem.theme.components_ListItemTwoLinesBothIcons_null_Listitems_Listitem(2lines)-BothIcons_0_null,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:d41f40195166fd9fe6d4b20c967d263d8ee3805931d2ec74c6671dd8d02af7b6 -size 21619 +oid sha256:7f34b5d4a735aa4e7480a9d5e5d6fb7fae2df7e189955c76f73e5a9e3b572c34 +size 22119 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[l.designsystem.theme.components_ListItemTwoLinesLeadingCheckbox_null_Listitems_Listitem(2lines)-LeadingCheckbox_0_null,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[l.designsystem.theme.components_ListItemTwoLinesLeadingCheckbox_null_Listitems_Listitem(2lines)-LeadingCheckbox_0_null,NEXUS_5,1.0,en].png index 5efbc81b17..be319133b2 100644 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[l.designsystem.theme.components_ListItemTwoLinesLeadingCheckbox_null_Listitems_Listitem(2lines)-LeadingCheckbox_0_null,NEXUS_5,1.0,en].png +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[l.designsystem.theme.components_ListItemTwoLinesLeadingCheckbox_null_Listitems_Listitem(2lines)-LeadingCheckbox_0_null,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:ca93eef86e2215ccfa04e632589fd90dec23388c393a7c55d757a365c54fd054 -size 19173 +oid sha256:f0756ac69c6a6a69d603fbc6799aea18bdc9d61e13dba138b3d78aca612a243a +size 19655 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[l.designsystem.theme.components_ListItemTwoLinesLeadingIcon_null_Listitems_Listitem(2lines)-LeadingIcon_0_null,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[l.designsystem.theme.components_ListItemTwoLinesLeadingIcon_null_Listitems_Listitem(2lines)-LeadingIcon_0_null,NEXUS_5,1.0,en].png index bbf2b87535..8ca7b0010f 100644 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[l.designsystem.theme.components_ListItemTwoLinesLeadingIcon_null_Listitems_Listitem(2lines)-LeadingIcon_0_null,NEXUS_5,1.0,en].png +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[l.designsystem.theme.components_ListItemTwoLinesLeadingIcon_null_Listitems_Listitem(2lines)-LeadingIcon_0_null,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:1064cc1d43235ceb8b0372e17399cb22269523df8bb1353e1068ed6386c2c4e8 -size 21702 +oid sha256:654aa911d45e015e6d60bd63a5d8e723a22a581c8fe2657299cfce162c765635 +size 21858 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[l.designsystem.theme.components_ListItemTwoLinesLeadingRadioButton_null_Listitems_Listitem(2lines)-LeadingRadioButton_0_null,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[l.designsystem.theme.components_ListItemTwoLinesLeadingRadioButton_null_Listitems_Listitem(2lines)-LeadingRadioButton_0_null,NEXUS_5,1.0,en].png index 5dd9c252a2..71dc274515 100644 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[l.designsystem.theme.components_ListItemTwoLinesLeadingRadioButton_null_Listitems_Listitem(2lines)-LeadingRadioButton_0_null,NEXUS_5,1.0,en].png +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[l.designsystem.theme.components_ListItemTwoLinesLeadingRadioButton_null_Listitems_Listitem(2lines)-LeadingRadioButton_0_null,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:4f76b18b75b3eff14677c046d725953e86030b113f01fda8bf29cc83705e23f7 -size 20472 +oid sha256:bef0e84ebd7a2ee8f0b906cfd60b4bf998ae31f1a1ae709aa7b301a553ec45f6 +size 20924 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[l.designsystem.theme.components_ListItemTwoLinesLeadingSwitch_null_Listitems_Listitem(2lines)-LeadingSwitch_0_null,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[l.designsystem.theme.components_ListItemTwoLinesLeadingSwitch_null_Listitems_Listitem(2lines)-LeadingSwitch_0_null,NEXUS_5,1.0,en].png index 0d02fc72e6..43a6e2c6c3 100644 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[l.designsystem.theme.components_ListItemTwoLinesLeadingSwitch_null_Listitems_Listitem(2lines)-LeadingSwitch_0_null,NEXUS_5,1.0,en].png +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[l.designsystem.theme.components_ListItemTwoLinesLeadingSwitch_null_Listitems_Listitem(2lines)-LeadingSwitch_0_null,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:f1689a328667fa1d7269b827b7e9bef415a642c5cf5163477730a37f95cd3931 -size 22746 +oid sha256:e2b0c050d0ce48eb74b0f3b7a49a696265d900ff4ea947861983329bee3f72f5 +size 23152 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[l.designsystem.theme.components_ListItemTwoLinesSimple_null_Listitems_Listitem(2lines)-Simple_0_null,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[l.designsystem.theme.components_ListItemTwoLinesSimple_null_Listitems_Listitem(2lines)-Simple_0_null,NEXUS_5,1.0,en].png index 6b27c15e4f..ac818a9450 100644 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[l.designsystem.theme.components_ListItemTwoLinesSimple_null_Listitems_Listitem(2lines)-Simple_0_null,NEXUS_5,1.0,en].png +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[l.designsystem.theme.components_ListItemTwoLinesSimple_null_Listitems_Listitem(2lines)-Simple_0_null,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:d9dec4ea21a07697fccf7d6d5f6f9132089d56d6debec66502754bc88aa9a149 -size 21247 +oid sha256:dcd0e857be61ddce5c9c5a9665af7dd8676c1ff329402cb7f775692ceca0b685 +size 21541 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[l.designsystem.theme.components_ListItemTwoLinesTrailingCheckBox_null_Listitems_Listitem(2lines)-TrailingCheckbox_0_null,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[l.designsystem.theme.components_ListItemTwoLinesTrailingCheckBox_null_Listitems_Listitem(2lines)-TrailingCheckbox_0_null,NEXUS_5,1.0,en].png index 197baadaf0..23dcd5f309 100644 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[l.designsystem.theme.components_ListItemTwoLinesTrailingCheckBox_null_Listitems_Listitem(2lines)-TrailingCheckbox_0_null,NEXUS_5,1.0,en].png +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[l.designsystem.theme.components_ListItemTwoLinesTrailingCheckBox_null_Listitems_Listitem(2lines)-TrailingCheckbox_0_null,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:14302bebf36302001f4694b3594b5616a3e332be52572051ba55866416fa626b -size 19313 +oid sha256:1334c03325a6ebe8c0f2d27c7f6626446c743fa3d17af4b2bd6fb5986afe5076 +size 19702 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[l.designsystem.theme.components_ListItemTwoLinesTrailingIcon_null_Listitems_Listitem(2lines)-TrailingIcon_0_null,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[l.designsystem.theme.components_ListItemTwoLinesTrailingIcon_null_Listitems_Listitem(2lines)-TrailingIcon_0_null,NEXUS_5,1.0,en].png index 6639da3de0..0a613b9b51 100644 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[l.designsystem.theme.components_ListItemTwoLinesTrailingIcon_null_Listitems_Listitem(2lines)-TrailingIcon_0_null,NEXUS_5,1.0,en].png +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[l.designsystem.theme.components_ListItemTwoLinesTrailingIcon_null_Listitems_Listitem(2lines)-TrailingIcon_0_null,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:b7f05e42db99e98b190d4b3f85eeb159cdb91cf04f7f0233ac5b6ff34988cb5f -size 21685 +oid sha256:ed9480916c159c556f3c5220a2c05c006370402ab1f2f3b0fce01cf0c4f0afda +size 21987 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[l.designsystem.theme.components_ListItemTwoLinesTrailingRadioButton_null_Listitems_Listitem(2lines)-TrailingRadioButton_0_null,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[l.designsystem.theme.components_ListItemTwoLinesTrailingRadioButton_null_Listitems_Listitem(2lines)-TrailingRadioButton_0_null,NEXUS_5,1.0,en].png index cfdf6934db..7a73c1f738 100644 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[l.designsystem.theme.components_ListItemTwoLinesTrailingRadioButton_null_Listitems_Listitem(2lines)-TrailingRadioButton_0_null,NEXUS_5,1.0,en].png +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[l.designsystem.theme.components_ListItemTwoLinesTrailingRadioButton_null_Listitems_Listitem(2lines)-TrailingRadioButton_0_null,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:383fe0be9d0e110735642e663be3cb8e39960900e306b0eadd836c62cab5a7de -size 20606 +oid sha256:f43526d34541f6c51b3bb0c837b94cd9a18a38053a95e3975c9c3ec7fd47c23f +size 20941 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[l.designsystem.theme.components_ListItemTwoLinesTrailingSwitch_null_Listitems_Listitem(2lines)-TrailingSwitch_0_null,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[l.designsystem.theme.components_ListItemTwoLinesTrailingSwitch_null_Listitems_Listitem(2lines)-TrailingSwitch_0_null,NEXUS_5,1.0,en].png index d0b15538f0..c063763cf0 100644 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[l.designsystem.theme.components_ListItemTwoLinesTrailingSwitch_null_Listitems_Listitem(2lines)-TrailingSwitch_0_null,NEXUS_5,1.0,en].png +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[l.designsystem.theme.components_ListItemTwoLinesTrailingSwitch_null_Listitems_Listitem(2lines)-TrailingSwitch_0_null,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:792ca2bab34a395065d912cd6827f0da7b79a2df49b59bf54646c86527e78116 -size 22673 +oid sha256:0cc89eeb8021d9bb63896c15ef0e08d615e3852075afd8d29312f54fc862af09 +size 23084 From f9c1892f2f5f81fcff96a7307edc8b5d5e182289 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Thu, 18 Jan 2024 10:57:53 +0100 Subject: [PATCH 021/127] SessionData: add the passphrase. --- .../signedout/impl/SignedOutStateProvider.kt | 1 + .../libraries/matrix/impl/mapper/Session.kt | 2 ++ .../libraries/sessionstorage/api/SessionData.kt | 1 + .../sessionstorage/impl/SessionDataMapper.kt | 2 ++ .../impl/src/main/sqldelight/databases/5.db | Bin 0 -> 12288 bytes .../libraries/matrix/session/SessionData.sq | 4 +++- .../impl/src/main/sqldelight/migrations/4.sqm | 3 +++ 7 files changed, 12 insertions(+), 1 deletion(-) create mode 100644 libraries/session-storage/impl/src/main/sqldelight/databases/5.db create mode 100644 libraries/session-storage/impl/src/main/sqldelight/migrations/4.sqm diff --git a/features/signedout/impl/src/main/kotlin/io/element/android/features/signedout/impl/SignedOutStateProvider.kt b/features/signedout/impl/src/main/kotlin/io/element/android/features/signedout/impl/SignedOutStateProvider.kt index 0182e87cf3..df3549b0f8 100644 --- a/features/signedout/impl/src/main/kotlin/io/element/android/features/signedout/impl/SignedOutStateProvider.kt +++ b/features/signedout/impl/src/main/kotlin/io/element/android/features/signedout/impl/SignedOutStateProvider.kt @@ -50,5 +50,6 @@ fun aSessionData( loginTimestamp = null, isTokenValid = isTokenValid, loginType = LoginType.UNKNOWN, + passphrase = null, ) } diff --git a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/mapper/Session.kt b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/mapper/Session.kt index fe21a460c8..aea838b705 100644 --- a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/mapper/Session.kt +++ b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/mapper/Session.kt @@ -24,6 +24,7 @@ import java.util.Date internal fun Session.toSessionData( isTokenValid: Boolean, loginType: LoginType, + passphrase: String?, ) = SessionData( userId = userId, deviceId = deviceId, @@ -35,4 +36,5 @@ internal fun Session.toSessionData( loginTimestamp = Date(), isTokenValid = isTokenValid, loginType = loginType, + passphrase = passphrase, ) diff --git a/libraries/session-storage/api/src/main/kotlin/io/element/android/libraries/sessionstorage/api/SessionData.kt b/libraries/session-storage/api/src/main/kotlin/io/element/android/libraries/sessionstorage/api/SessionData.kt index 25a48c0efe..7189442716 100644 --- a/libraries/session-storage/api/src/main/kotlin/io/element/android/libraries/sessionstorage/api/SessionData.kt +++ b/libraries/session-storage/api/src/main/kotlin/io/element/android/libraries/sessionstorage/api/SessionData.kt @@ -29,4 +29,5 @@ data class SessionData( val loginTimestamp: Date?, val isTokenValid: Boolean, val loginType: LoginType, + val passphrase: String?, ) diff --git a/libraries/session-storage/impl/src/main/kotlin/io/element/android/libraries/sessionstorage/impl/SessionDataMapper.kt b/libraries/session-storage/impl/src/main/kotlin/io/element/android/libraries/sessionstorage/impl/SessionDataMapper.kt index 1a81647f5c..3824def48c 100644 --- a/libraries/session-storage/impl/src/main/kotlin/io/element/android/libraries/sessionstorage/impl/SessionDataMapper.kt +++ b/libraries/session-storage/impl/src/main/kotlin/io/element/android/libraries/sessionstorage/impl/SessionDataMapper.kt @@ -33,6 +33,7 @@ internal fun SessionData.toDbModel(): DbSessionData { loginTimestamp = loginTimestamp?.time, isTokenValid = if (isTokenValid) 1L else 0L, loginType = loginType.name, + passphrase = passphrase, ) } @@ -48,5 +49,6 @@ internal fun DbSessionData.toApiModel(): SessionData { loginTimestamp = loginTimestamp?.let { Date(it) }, isTokenValid = isTokenValid == 1L, loginType = LoginType.fromName(loginType ?: LoginType.UNKNOWN.name), + passphrase = passphrase, ) } diff --git a/libraries/session-storage/impl/src/main/sqldelight/databases/5.db b/libraries/session-storage/impl/src/main/sqldelight/databases/5.db new file mode 100644 index 0000000000000000000000000000000000000000..c6cf5ebef0910c8dcd0aab58d56993bb5f0f4517 GIT binary patch literal 12288 zcmeI#O;5rw7zgkUUqeFl=JiRqXd)(v-bI~;I8k93Igz?mX&f82)5zI_pTm#hC-G}| zwB15PqapD~{!Kb4&-3)AhwzVEp-5uo)Vnf9QCYJ}vwS3Wh*Oz(IeowpjN^;VZo-0o(U z6^ch0h@W|Rj0b^P*-!37{C%1{ti+8Hy8ji=f9@v(VU~Urs-vRc>U1PS8Q-=?ad57Z zr%{%Z*H$XT!%&1IV=@!iQ`2^~&nUT-u`kWkDIW}}(e&M8xAk{bEvrgo7+AI`OYCIH zGC%4iH~Ske@FjQX9@RUZPt|3{-a9vv1%V^5P$##AOHafKmY;|fB*y_009WhszA{m g4EO(8eZ4pr1Rwwb2tWV=5P$##AOHafKp+$N1d1T5+5i9m literal 0 HcmV?d00001 diff --git a/libraries/session-storage/impl/src/main/sqldelight/io/element/android/libraries/matrix/session/SessionData.sq b/libraries/session-storage/impl/src/main/sqldelight/io/element/android/libraries/matrix/session/SessionData.sq index d6d16cb6e2..c33b4d7c7e 100644 --- a/libraries/session-storage/impl/src/main/sqldelight/io/element/android/libraries/matrix/session/SessionData.sq +++ b/libraries/session-storage/impl/src/main/sqldelight/io/element/android/libraries/matrix/session/SessionData.sq @@ -21,7 +21,9 @@ CREATE TABLE SessionData ( oidcData TEXT, -- added in version 4 isTokenValid INTEGER NOT NULL DEFAULT 1, - loginType TEXT + loginType TEXT, + -- added in version 5 + passphrase TEXT ); diff --git a/libraries/session-storage/impl/src/main/sqldelight/migrations/4.sqm b/libraries/session-storage/impl/src/main/sqldelight/migrations/4.sqm new file mode 100644 index 0000000000..144d56959f --- /dev/null +++ b/libraries/session-storage/impl/src/main/sqldelight/migrations/4.sqm @@ -0,0 +1,3 @@ +-- Migrate DB from version 4 + +ALTER TABLE SessionData ADD COLUMN passphrase TEXT; From 3a91f830da8f37aff86a4a91747974cdbfe5f611 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Thu, 18 Jan 2024 11:48:17 +0100 Subject: [PATCH 022/127] Encrypt databases used by the Rust SDK. The passphrase is stored in the SessionData, so that a Session created by Element Android can be restored. Existing sessions will have a null passphrase and will continue to work. New session will use a passphrase, only on Nightly and Debug build for now. --- changelog.d/2219.misc | 1 + .../libraries/matrix/impl/RustMatrixClient.kt | 2 ++ .../matrix/impl/RustMatrixClientFactory.kt | 1 + .../auth/RustMatrixAuthenticationService.kt | 34 ++++++++++++++++++- .../impl/keys/DefaultPassphraseGenerator.kt | 34 +++++++++++++++++++ .../matrix/impl/keys/PassphraseGenerator.kt | 25 ++++++++++++++ .../android/samples/minimal/MainActivity.kt | 4 ++- .../minimal/NullPassphraseGenerator.kt | 23 +++++++++++++ .../android/samples/minimal/Singleton.kt | 2 +- 9 files changed, 123 insertions(+), 3 deletions(-) create mode 100644 changelog.d/2219.misc create mode 100644 libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/keys/DefaultPassphraseGenerator.kt create mode 100644 libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/keys/PassphraseGenerator.kt create mode 100644 samples/minimal/src/main/kotlin/io/element/android/samples/minimal/NullPassphraseGenerator.kt diff --git a/changelog.d/2219.misc b/changelog.d/2219.misc new file mode 100644 index 0000000000..c8c11e8105 --- /dev/null +++ b/changelog.d/2219.misc @@ -0,0 +1 @@ +Encrypt databases used by the Rust SDK on Nightly and Debug builds. diff --git a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/RustMatrixClient.kt b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/RustMatrixClient.kt index 94e0eb56e4..8971fd78d8 100644 --- a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/RustMatrixClient.kt +++ b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/RustMatrixClient.kt @@ -144,6 +144,7 @@ class RustMatrixClient( val newData = client.session().toSessionData( isTokenValid = false, loginType = existingData.loginType, + passphrase = existingData.passphrase, ) sessionStore.updateData(newData) } @@ -161,6 +162,7 @@ class RustMatrixClient( val newData = client.session().toSessionData( isTokenValid = existingData.isTokenValid, loginType = existingData.loginType, + passphrase = existingData.passphrase, ) sessionStore.updateData(newData) } diff --git a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/RustMatrixClientFactory.kt b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/RustMatrixClientFactory.kt index 53aa560b97..0f1c47445b 100644 --- a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/RustMatrixClientFactory.kt +++ b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/RustMatrixClientFactory.kt @@ -44,6 +44,7 @@ class RustMatrixClientFactory @Inject constructor( .basePath(baseDirectory.absolutePath) .homeserverUrl(sessionData.homeserverUrl) .username(sessionData.userId) + .passphrase(sessionData.passphrase) .userAgent(userAgentProvider.provide()) // FIXME Quick and dirty fix for stopping version requests on startup https://github.com/matrix-org/matrix-rust-sdk/pull/1376 .serverVersions(listOf("v1.0", "v1.1", "v1.2", "v1.3", "v1.4", "v1.5")) diff --git a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/auth/RustMatrixAuthenticationService.kt b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/auth/RustMatrixAuthenticationService.kt index bfce2b3ec2..b777988783 100644 --- a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/auth/RustMatrixAuthenticationService.kt +++ b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/auth/RustMatrixAuthenticationService.kt @@ -19,6 +19,8 @@ package io.element.android.libraries.matrix.impl.auth import com.squareup.anvil.annotations.ContributesBinding import io.element.android.libraries.core.coroutine.CoroutineDispatchers import io.element.android.libraries.core.extensions.mapFailure +import io.element.android.libraries.core.meta.BuildMeta +import io.element.android.libraries.core.meta.BuildType import io.element.android.libraries.di.AppScope import io.element.android.libraries.di.SingleIn import io.element.android.libraries.matrix.api.MatrixClient @@ -28,6 +30,7 @@ import io.element.android.libraries.matrix.api.auth.OidcDetails import io.element.android.libraries.matrix.api.core.SessionId import io.element.android.libraries.matrix.impl.RustMatrixClientFactory import io.element.android.libraries.matrix.impl.exception.mapClientException +import io.element.android.libraries.matrix.impl.keys.PassphraseGenerator import io.element.android.libraries.matrix.impl.mapper.toSessionData import io.element.android.libraries.network.useragent.UserAgentProvider import io.element.android.libraries.sessionstorage.api.LoggedInState @@ -39,6 +42,7 @@ import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.withContext import org.matrix.rustcomponents.sdk.OidcAuthenticationData import org.matrix.rustcomponents.sdk.use +import timber.log.Timber import java.io.File import javax.inject.Inject import org.matrix.rustcomponents.sdk.AuthenticationService as RustAuthenticationService @@ -51,10 +55,15 @@ class RustMatrixAuthenticationService @Inject constructor( private val sessionStore: SessionStore, userAgentProvider: UserAgentProvider, private val rustMatrixClientFactory: RustMatrixClientFactory, + private val passphraseGenerator: PassphraseGenerator, + private val buildMeta: BuildMeta, ) : MatrixAuthenticationService { + // Passphrase which will be used for new sessions. Existing sessions will use the passphrase + // stored in the SessionData. + private val pendingPassphrase = getDatabasePassphrase() private val authService: RustAuthenticationService = RustAuthenticationService( basePath = baseDirectory.absolutePath, - passphrase = null, + passphrase = pendingPassphrase, userAgent = userAgentProvider.provide(), oidcConfiguration = oidcConfiguration, customSlidingSyncProxy = null, @@ -76,6 +85,12 @@ class RustMatrixAuthenticationService @Inject constructor( val sessionData = sessionStore.getSession(sessionId.value) if (sessionData != null) { if (sessionData.isTokenValid) { + // Use the sessionData.passphrase, which can be null for a previously created session + if (sessionData.passphrase == null) { + Timber.w("Restoring a session without a passphrase") + } else { + Timber.w("Restoring a session with a passphrase") + } rustMatrixClientFactory.create(sessionData) } else { error("Token is not valid") @@ -88,6 +103,21 @@ class RustMatrixAuthenticationService @Inject constructor( } } + private fun getDatabasePassphrase(): String? { + // TODO Remove this if block at some point + // Return a passphrase only for debug and nightly build for now + if (buildMeta.buildType == BuildType.RELEASE) { + Timber.w("New sessions will not be encrypted with a passphrase (release build)") + return null + } + + val passphrase = passphraseGenerator.generatePassphrase() + if (passphrase != null) { + Timber.w("New sessions will be encrypted with a passphrase") + } + return passphrase + } + override fun getHomeserverDetails(): StateFlow = currentHomeserver override suspend fun setHomeserver(homeserver: String): Result = @@ -111,6 +141,7 @@ class RustMatrixAuthenticationService @Inject constructor( it.session().toSessionData( isTokenValid = true, loginType = LoginType.PASSWORD, + passphrase = pendingPassphrase, ) } sessionStore.storeData(sessionData) @@ -158,6 +189,7 @@ class RustMatrixAuthenticationService @Inject constructor( it.session().toSessionData( isTokenValid = true, loginType = LoginType.OIDC, + passphrase = pendingPassphrase ) } pendingOidcAuthenticationData?.close() diff --git a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/keys/DefaultPassphraseGenerator.kt b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/keys/DefaultPassphraseGenerator.kt new file mode 100644 index 0000000000..7e72dfeb55 --- /dev/null +++ b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/keys/DefaultPassphraseGenerator.kt @@ -0,0 +1,34 @@ +/* + * 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 io.element.android.libraries.matrix.impl.keys + +import android.util.Base64 +import com.squareup.anvil.annotations.ContributesBinding +import io.element.android.libraries.di.AppScope +import java.security.SecureRandom +import javax.inject.Inject + +private const val SECRET_SIZE = 256 + +@ContributesBinding(AppScope::class) +class DefaultPassphraseGenerator @Inject constructor() : PassphraseGenerator { + override fun generatePassphrase(): String? { + val key = ByteArray(size = SECRET_SIZE) + SecureRandom().nextBytes(key) + return Base64.encodeToString(key, Base64.NO_PADDING or Base64.NO_WRAP) + } +} diff --git a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/keys/PassphraseGenerator.kt b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/keys/PassphraseGenerator.kt new file mode 100644 index 0000000000..2b62a36d07 --- /dev/null +++ b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/keys/PassphraseGenerator.kt @@ -0,0 +1,25 @@ +/* + * 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 io.element.android.libraries.matrix.impl.keys + +interface PassphraseGenerator { + /** + * Generate a passphrase to encrypt the databases of a session. + * Return null to not encrypt the databases. + */ + fun generatePassphrase(): String? +} diff --git a/samples/minimal/src/main/kotlin/io/element/android/samples/minimal/MainActivity.kt b/samples/minimal/src/main/kotlin/io/element/android/samples/minimal/MainActivity.kt index 4d5c9aa216..30f5d2afe9 100644 --- a/samples/minimal/src/main/kotlin/io/element/android/samples/minimal/MainActivity.kt +++ b/samples/minimal/src/main/kotlin/io/element/android/samples/minimal/MainActivity.kt @@ -55,7 +55,9 @@ class MainActivity : ComponentActivity() { sessionStore = sessionStore, userAgentProvider = userAgentProvider, clock = DefaultSystemClock(), - ) + ), + passphraseGenerator = NullPassphraseGenerator(), + buildMeta = Singleton.buildMeta, ) } diff --git a/samples/minimal/src/main/kotlin/io/element/android/samples/minimal/NullPassphraseGenerator.kt b/samples/minimal/src/main/kotlin/io/element/android/samples/minimal/NullPassphraseGenerator.kt new file mode 100644 index 0000000000..ab0117fd38 --- /dev/null +++ b/samples/minimal/src/main/kotlin/io/element/android/samples/minimal/NullPassphraseGenerator.kt @@ -0,0 +1,23 @@ +/* + * 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 io.element.android.samples.minimal + +import io.element.android.libraries.matrix.impl.keys.PassphraseGenerator + +class NullPassphraseGenerator : PassphraseGenerator { + override fun generatePassphrase(): String? = null +} diff --git a/samples/minimal/src/main/kotlin/io/element/android/samples/minimal/Singleton.kt b/samples/minimal/src/main/kotlin/io/element/android/samples/minimal/Singleton.kt index fc8fe81d8a..fc146d1ff3 100644 --- a/samples/minimal/src/main/kotlin/io/element/android/samples/minimal/Singleton.kt +++ b/samples/minimal/src/main/kotlin/io/element/android/samples/minimal/Singleton.kt @@ -29,7 +29,7 @@ import kotlinx.coroutines.MainScope import kotlinx.coroutines.plus object Singleton { - private val buildMeta = BuildMeta( + val buildMeta = BuildMeta( isDebuggable = true, buildType = BuildType.DEBUG, applicationName = "EAX-Minimal", From 877ed3c7ac1c3fcd3f7e3da09ae4e25437ecad99 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Thu, 18 Jan 2024 12:44:20 +0100 Subject: [PATCH 023/127] Fix test. --- .../sessionstorage/impl/DatabaseSessionStoreTests.kt | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/libraries/session-storage/impl/src/test/kotlin/io/element/android/libraries/sessionstorage/impl/DatabaseSessionStoreTests.kt b/libraries/session-storage/impl/src/test/kotlin/io/element/android/libraries/sessionstorage/impl/DatabaseSessionStoreTests.kt index a195c46c5c..760eefd20c 100644 --- a/libraries/session-storage/impl/src/test/kotlin/io/element/android/libraries/sessionstorage/impl/DatabaseSessionStoreTests.kt +++ b/libraries/session-storage/impl/src/test/kotlin/io/element/android/libraries/sessionstorage/impl/DatabaseSessionStoreTests.kt @@ -44,6 +44,7 @@ class DatabaseSessionStoreTests { oidcData = "aOidcData", isTokenValid = 1, loginType = LoginType.UNKNOWN.name, + passphrase = null, ) @OptIn(ExperimentalCoroutinesApi::class) @@ -137,6 +138,7 @@ class DatabaseSessionStoreTests { oidcData = "aOidcData", isTokenValid = 1, loginType = null, + passphrase = "aPassphrase", ) val secondSessionData = SessionData( userId = "userId", @@ -149,6 +151,7 @@ class DatabaseSessionStoreTests { oidcData = "aOidcDataAltered", isTokenValid = 1, loginType = null, + passphrase = "aPassphraseAltered", ) assertThat(firstSessionData.userId).isEqualTo(secondSessionData.userId) assertThat(firstSessionData.loginTimestamp).isNotEqualTo(secondSessionData.loginTimestamp) @@ -168,5 +171,6 @@ class DatabaseSessionStoreTests { // Check that alteredSession.loginTimestamp is not altered, so equal to firstSessionData.loginTimestamp assertThat(alteredSession.loginTimestamp).isEqualTo(firstSessionData.loginTimestamp) assertThat(alteredSession.oidcData).isEqualTo(secondSessionData.oidcData) + assertThat(alteredSession.passphrase).isEqualTo(secondSessionData.passphrase) } } From 6ecce81f45d4704af69608e87785fb761c4cc210 Mon Sep 17 00:00:00 2001 From: Jorge Martin Espinosa Date: Thu, 18 Jan 2024 16:22:25 +0100 Subject: [PATCH 024/127] Try mitigating unexpected logouts (#2251) * Try mitigating unexpected logouts. Try making getting/storing session data use a Mutex for synchronization. Also added some more logs so we can understand exactly where it's failing. --- .../+try-mitigating-unexpected-logouts.misc | 3 ++ .../libraries/matrix/impl/RustMatrixClient.kt | 18 ++++++++- .../impl/DatabaseSessionStore.kt | 39 ++++++++++++------- 3 files changed, 45 insertions(+), 15 deletions(-) create mode 100644 changelog.d/+try-mitigating-unexpected-logouts.misc diff --git a/changelog.d/+try-mitigating-unexpected-logouts.misc b/changelog.d/+try-mitigating-unexpected-logouts.misc new file mode 100644 index 0000000000..e9b675ad71 --- /dev/null +++ b/changelog.d/+try-mitigating-unexpected-logouts.misc @@ -0,0 +1,3 @@ +Try mitigating unexpected logouts by making getting/storing session data use a Mutex for synchronization. + +Also added some more logs so we can understand exactly where it's failing. diff --git a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/RustMatrixClient.kt b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/RustMatrixClient.kt index 94e0eb56e4..d7aff653f8 100644 --- a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/RustMatrixClient.kt +++ b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/RustMatrixClient.kt @@ -139,6 +139,8 @@ class RustMatrixClient( // TODO handle isSoftLogout parameter. appCoroutineScope.launch { val existingData = sessionStore.getSession(client.userId()) + val anonymizedToken = existingData?.accessToken?.takeLast(4) + Timber.d("Removing session data with token: '...$anonymizedToken'.") if (existingData != null) { // Set isTokenValid to false val newData = client.session().toSessionData( @@ -146,8 +148,15 @@ class RustMatrixClient( loginType = existingData.loginType, ) sessionStore.updateData(newData) + Timber.d("Removed session data with token: '...$anonymizedToken'.") + } else { + Timber.d("No session data found.") } doLogout(doRequest = false, removeSession = false, ignoreSdkError = false) + }.invokeOnCompletion { + if (it != null) { + Timber.e(it, "Failed to remove session data.") + } } } else { Timber.v("didReceiveAuthError -> already cleaning up") @@ -158,11 +167,18 @@ class RustMatrixClient( Timber.w("didRefreshTokens()") appCoroutineScope.launch { val existingData = sessionStore.getSession(client.userId()) ?: return@launch + val anonymizedToken = client.session().accessToken.takeLast(4) + Timber.d("Saving new session data with token: '...$anonymizedToken'. Was token valid: ${existingData.isTokenValid}") val newData = client.session().toSessionData( - isTokenValid = existingData.isTokenValid, + isTokenValid = true, loginType = existingData.loginType, ) sessionStore.updateData(newData) + Timber.d("Saved new session data with token: '...$anonymizedToken'.") + }.invokeOnCompletion { + if (it != null) { + Timber.e(it, "Failed to save new session data.") + } } } } diff --git a/libraries/session-storage/impl/src/main/kotlin/io/element/android/libraries/sessionstorage/impl/DatabaseSessionStore.kt b/libraries/session-storage/impl/src/main/kotlin/io/element/android/libraries/sessionstorage/impl/DatabaseSessionStore.kt index 23d362d0b5..5ccf62c61d 100644 --- a/libraries/session-storage/impl/src/main/kotlin/io/element/android/libraries/sessionstorage/impl/DatabaseSessionStore.kt +++ b/libraries/session-storage/impl/src/main/kotlin/io/element/android/libraries/sessionstorage/impl/DatabaseSessionStore.kt @@ -28,6 +28,8 @@ import io.element.android.libraries.sessionstorage.api.SessionData import io.element.android.libraries.sessionstorage.api.SessionStore import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.map +import kotlinx.coroutines.sync.Mutex +import kotlinx.coroutines.sync.withLock import timber.log.Timber import javax.inject.Inject @@ -37,6 +39,8 @@ class DatabaseSessionStore @Inject constructor( private val database: SessionDatabase, private val dispatchers: CoroutineDispatchers, ) : SessionStore { + private val sessionDataMutex = Mutex() + override fun isLoggedIn(): Flow { return database.sessionDataQueries.selectFirst() .asFlow() @@ -53,11 +57,11 @@ class DatabaseSessionStore @Inject constructor( } } - override suspend fun storeData(sessionData: SessionData) { + override suspend fun storeData(sessionData: SessionData) = sessionDataMutex.withLock { database.sessionDataQueries.insertSessionData(sessionData.toDbModel()) } - override suspend fun updateData(sessionData: SessionData) { + override suspend fun updateData(sessionData: SessionData) = sessionDataMutex.withLock { val result = database.sessionDataQueries.selectByUserId(sessionData.userId) .executeAsOneOrNull() ?.toApiModel() @@ -66,8 +70,7 @@ class DatabaseSessionStore @Inject constructor( Timber.e("User ${sessionData.userId} not found in session database") return } - - // Copy new data from SDK, but keep login timestamp + // Copy new data from SDK, but keep login timestamp database.sessionDataQueries.updateSession( sessionData.copy( loginTimestamp = result.loginTimestamp, @@ -76,21 +79,27 @@ class DatabaseSessionStore @Inject constructor( } override suspend fun getLatestSession(): SessionData? { - return database.sessionDataQueries.selectFirst() - .executeAsOneOrNull() - ?.toApiModel() + return sessionDataMutex.withLock { + database.sessionDataQueries.selectFirst() + .executeAsOneOrNull() + ?.toApiModel() + } } override suspend fun getSession(sessionId: String): SessionData? { - return database.sessionDataQueries.selectByUserId(sessionId) - .executeAsOneOrNull() - ?.toApiModel() + return sessionDataMutex.withLock { + database.sessionDataQueries.selectByUserId(sessionId) + .executeAsOneOrNull() + ?.toApiModel() + } } override suspend fun getAllSessions(): List { - return database.sessionDataQueries.selectAll() - .executeAsList() - .map { it.toApiModel() } + return sessionDataMutex.withLock { + database.sessionDataQueries.selectAll() + .executeAsList() + .map { it.toApiModel() } + } } override fun sessionsFlow(): Flow> { @@ -102,6 +111,8 @@ class DatabaseSessionStore @Inject constructor( } override suspend fun removeSession(sessionId: String) { - database.sessionDataQueries.removeSession(sessionId) + sessionDataMutex.withLock { + database.sessionDataQueries.removeSession(sessionId) + } } } From 53fce3e148460b73a5211cba449de3c306586945 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Thu, 18 Jan 2024 17:40:08 +0100 Subject: [PATCH 025/127] Apply the plugin `com.autonomousapps.dependency-analysis` only to the root project. --- .../kotlin/io.element.android-compose-application.gradle.kts | 1 - .../main/kotlin/io.element.android-compose-library.gradle.kts | 1 - plugins/src/main/kotlin/io.element.android-library.gradle.kts | 1 - 3 files changed, 3 deletions(-) diff --git a/plugins/src/main/kotlin/io.element.android-compose-application.gradle.kts b/plugins/src/main/kotlin/io.element.android-compose-application.gradle.kts index 2ac8fb8b72..80bc0f884e 100644 --- a/plugins/src/main/kotlin/io.element.android-compose-application.gradle.kts +++ b/plugins/src/main/kotlin/io.element.android-compose-application.gradle.kts @@ -27,7 +27,6 @@ val libs = the() plugins { id("com.android.application") id("kotlin-android") - id("com.autonomousapps.dependency-analysis") } android { diff --git a/plugins/src/main/kotlin/io.element.android-compose-library.gradle.kts b/plugins/src/main/kotlin/io.element.android-compose-library.gradle.kts index 3176856339..3194505e4e 100644 --- a/plugins/src/main/kotlin/io.element.android-compose-library.gradle.kts +++ b/plugins/src/main/kotlin/io.element.android-compose-library.gradle.kts @@ -27,7 +27,6 @@ val libs = the() plugins { id("com.android.library") id("kotlin-android") - id("com.autonomousapps.dependency-analysis") } android { diff --git a/plugins/src/main/kotlin/io.element.android-library.gradle.kts b/plugins/src/main/kotlin/io.element.android-library.gradle.kts index 572168b0c4..f3a84031e6 100644 --- a/plugins/src/main/kotlin/io.element.android-library.gradle.kts +++ b/plugins/src/main/kotlin/io.element.android-library.gradle.kts @@ -25,7 +25,6 @@ val libs = the() plugins { id("com.android.library") id("kotlin-android") - id("com.autonomousapps.dependency-analysis") } android { From 4c51609be390c84c6fd2cfcef28b91a0249e4184 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 18 Jan 2024 19:37:23 +0000 Subject: [PATCH 026/127] Update dependency com.google.firebase:firebase-bom to v32.7.1 --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index b7dfcd5d44..eda7b6e8be 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -62,7 +62,7 @@ kotlin_gradle_plugin = { module = "org.jetbrains.kotlin:kotlin-gradle-plugin", v kover_gradle_plugin = { module = "org.jetbrains.kotlinx:kover-gradle-plugin", version.ref = "kover" } gms_google_services = "com.google.gms:google-services:4.4.0" # https://firebase.google.com/docs/android/setup#available-libraries -google_firebase_bom = "com.google.firebase:firebase-bom:32.7.0" +google_firebase_bom = "com.google.firebase:firebase-bom:32.7.1" firebase_appdistribution_gradle = { module = "com.google.firebase:firebase-appdistribution-gradle", version.ref = "firebaseAppDistribution" } autonomousapps_dependencyanalysis_plugin = { module = "com.autonomousapps:dependency-analysis-gradle-plugin", version.ref = "dependencyAnalysis" } From d9b0f8a2523f7bb4b4389233b5ea88a9248318cf Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 19 Jan 2024 00:33:08 +0000 Subject: [PATCH 027/127] Update kotlin --- gradle/libs.versions.toml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index b7dfcd5d44..7cb7d6c52a 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -4,8 +4,8 @@ [versions] # Project android_gradle_plugin = "8.2.1" -kotlin = "1.9.21" -ksp = "1.9.21-1.0.16" +kotlin = "1.9.22" +ksp = "1.9.22-1.0.17" firebaseAppDistribution = "4.0.1" # AndroidX @@ -19,7 +19,7 @@ media3 = "1.2.1" # Compose compose_bom = "2023.10.01" -composecompiler = "1.5.7" +composecompiler = "1.5.8" # Coroutines coroutines = "1.7.3" From e2614318f4856c23217027a43ff73ee145bbf258 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 19 Jan 2024 08:39:39 +0100 Subject: [PATCH 028/127] Update dependency com.squareup:kotlinpoet to v1.16.0 (#2253) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index b7dfcd5d44..7f801b48c1 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -170,7 +170,7 @@ maplibre = "org.maplibre.gl:android-sdk:10.2.0" maplibre_ktx = "org.maplibre.gl:android-sdk-ktx-v7:2.0.2" maplibre_annotation = "org.maplibre.gl:android-plugin-annotation-v9:2.0.2" opusencoder = "io.element.android:opusencoder:1.1.0" -kotlinpoet = "com.squareup:kotlinpoet:1.15.3" +kotlinpoet = "com.squareup:kotlinpoet:1.16.0" # Analytics posthog = "com.posthog:posthog-android:3.1.3" From 27ed057475b8fbfd5fc17e94db13e1e5bd5de5c6 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 19 Jan 2024 09:00:32 +0000 Subject: [PATCH 029/127] Update dependency org.matrix.rustcomponents:sdk-android to v0.1.84 --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 595ddc94d0..8476fa313d 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -153,7 +153,7 @@ jsoup = "org.jsoup:jsoup:1.17.2" appyx_core = { module = "com.bumble.appyx:core", version.ref = "appyx" } molecule-runtime = "app.cash.molecule:molecule-runtime:1.3.2" timber = "com.jakewharton.timber:timber:5.0.1" -matrix_sdk = "org.matrix.rustcomponents:sdk-android:0.1.83" +matrix_sdk = "org.matrix.rustcomponents:sdk-android:0.1.84" matrix_richtexteditor = { module = "io.element.android:wysiwyg", version.ref = "wysiwyg" } matrix_richtexteditor_compose = { module = "io.element.android:wysiwyg-compose", version.ref = "wysiwyg" } sqldelight-driver-android = { module = "app.cash.sqldelight:android-driver", version.ref = "sqldelight" } From 48b90fd317f5e9e6c79ffb14b12d45734049898f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jorge=20Mart=C3=ADn?= Date: Fri, 19 Jan 2024 10:02:09 +0100 Subject: [PATCH 030/127] Adapt changes from SDK 0.1.84 --- .../element/android/libraries/matrix/impl/RustMatrixClient.kt | 4 ++-- .../notificationsettings/RustNotificationSettingsService.kt | 2 +- .../libraries/matrix/impl/timeline/RoomTimelineExtensions.kt | 2 +- .../libraries/matrix/impl/timeline/RustMatrixTimeline.kt | 4 ++-- .../android/libraries/matrix/impl/timeline/TimelineDiffExt.kt | 2 +- .../impl/timeline/item/event/EventTimelineItemMapper.kt | 2 +- 6 files changed, 8 insertions(+), 8 deletions(-) diff --git a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/RustMatrixClient.kt b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/RustMatrixClient.kt index d7aff653f8..7ad62297ba 100644 --- a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/RustMatrixClient.kt +++ b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/RustMatrixClient.kt @@ -242,10 +242,10 @@ class RustMatrixClient( } } - private fun pairOfRoom(roomId: RoomId): Pair? { + private suspend fun pairOfRoom(roomId: RoomId): Pair? { val cachedRoomListItem = innerRoomListService.roomOrNull(roomId.value) // Keep using fullRoomBlocking for now as it's faster. - val fullRoom = cachedRoomListItem?.fullRoomBlocking() + val fullRoom = cachedRoomListItem?.fullRoom() return if (cachedRoomListItem == null || fullRoom == null) { Timber.d("No room cached for $roomId") null diff --git a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/notificationsettings/RustNotificationSettingsService.kt b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/notificationsettings/RustNotificationSettingsService.kt index 2eee0a324e..bfe2ef2c15 100644 --- a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/notificationsettings/RustNotificationSettingsService.kt +++ b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/notificationsettings/RustNotificationSettingsService.kt @@ -143,6 +143,6 @@ class RustNotificationSettingsService( override suspend fun canHomeServerPushEncryptedEventsToDevice(): Result = runCatching { - notificationSettings.canHomeserverPushEncryptedEventToDevice() + notificationSettings.canPushEncryptedEventToDevice() } } diff --git a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/timeline/RoomTimelineExtensions.kt b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/timeline/RoomTimelineExtensions.kt index 8eb2f999d1..f8109259d5 100644 --- a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/timeline/RoomTimelineExtensions.kt +++ b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/timeline/RoomTimelineExtensions.kt @@ -27,13 +27,13 @@ import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.buffer import kotlinx.coroutines.flow.callbackFlow import kotlinx.coroutines.flow.catch -import org.matrix.rustcomponents.sdk.BackPaginationStatus import org.matrix.rustcomponents.sdk.BackPaginationStatusListener import org.matrix.rustcomponents.sdk.Timeline import org.matrix.rustcomponents.sdk.TimelineDiff import org.matrix.rustcomponents.sdk.TimelineItem import org.matrix.rustcomponents.sdk.TimelineListener import timber.log.Timber +import uniffi.matrix_sdk_ui.BackPaginationStatus internal fun Timeline.timelineDiffFlow(onInitialList: suspend (List) -> Unit): Flow> = callbackFlow { diff --git a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/timeline/RustMatrixTimeline.kt b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/timeline/RustMatrixTimeline.kt index 1841aa4b59..f33e0606e7 100644 --- a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/timeline/RustMatrixTimeline.kt +++ b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/timeline/RustMatrixTimeline.kt @@ -45,13 +45,13 @@ import kotlinx.coroutines.flow.mapLatest import kotlinx.coroutines.flow.onEach import kotlinx.coroutines.launch import kotlinx.coroutines.withContext -import org.matrix.rustcomponents.sdk.BackPaginationStatus -import org.matrix.rustcomponents.sdk.EventItemOrigin import org.matrix.rustcomponents.sdk.PaginationOptions import org.matrix.rustcomponents.sdk.Timeline import org.matrix.rustcomponents.sdk.TimelineDiff import org.matrix.rustcomponents.sdk.TimelineItem import timber.log.Timber +import uniffi.matrix_sdk_ui.BackPaginationStatus +import uniffi.matrix_sdk_ui.EventItemOrigin import java.util.Date import java.util.concurrent.atomic.AtomicBoolean diff --git a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/timeline/TimelineDiffExt.kt b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/timeline/TimelineDiffExt.kt index 59165463bb..406d9615ce 100644 --- a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/timeline/TimelineDiffExt.kt +++ b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/timeline/TimelineDiffExt.kt @@ -16,10 +16,10 @@ package io.element.android.libraries.matrix.impl.timeline -import org.matrix.rustcomponents.sdk.EventItemOrigin import org.matrix.rustcomponents.sdk.TimelineChange import org.matrix.rustcomponents.sdk.TimelineDiff import org.matrix.rustcomponents.sdk.TimelineItem +import uniffi.matrix_sdk_ui.EventItemOrigin /** * Tries to get an event origin from the TimelineDiff. diff --git a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/timeline/item/event/EventTimelineItemMapper.kt b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/timeline/item/event/EventTimelineItemMapper.kt index 1cfbb11e02..ed56d4a8d0 100644 --- a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/timeline/item/event/EventTimelineItemMapper.kt +++ b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/timeline/item/event/EventTimelineItemMapper.kt @@ -31,12 +31,12 @@ import kotlinx.collections.immutable.ImmutableList import kotlinx.collections.immutable.persistentListOf import kotlinx.collections.immutable.toImmutableList import org.matrix.rustcomponents.sdk.Reaction -import org.matrix.rustcomponents.sdk.EventItemOrigin as RustEventItemOrigin import org.matrix.rustcomponents.sdk.EventSendState as RustEventSendState import org.matrix.rustcomponents.sdk.EventTimelineItem as RustEventTimelineItem import org.matrix.rustcomponents.sdk.EventTimelineItemDebugInfo as RustEventTimelineItemDebugInfo import org.matrix.rustcomponents.sdk.ProfileDetails as RustProfileDetails import org.matrix.rustcomponents.sdk.Receipt as RustReceipt +import uniffi.matrix_sdk_ui.EventItemOrigin as RustEventItemOrigin class EventTimelineItemMapper(private val contentMapper: TimelineEventContentMapper = TimelineEventContentMapper()) { fun map(eventTimelineItem: RustEventTimelineItem): EventTimelineItem = eventTimelineItem.use { From ea90b2b83355a387039fe681e57a4cec9fad183f Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Fri, 19 Jan 2024 13:24:50 +0100 Subject: [PATCH 031/127] Remove obsolete comment. --- .../io/element/android/libraries/matrix/impl/RustMatrixClient.kt | 1 - 1 file changed, 1 deletion(-) diff --git a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/RustMatrixClient.kt b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/RustMatrixClient.kt index 7ad62297ba..a7b13c0b8d 100644 --- a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/RustMatrixClient.kt +++ b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/RustMatrixClient.kt @@ -244,7 +244,6 @@ class RustMatrixClient( private suspend fun pairOfRoom(roomId: RoomId): Pair? { val cachedRoomListItem = innerRoomListService.roomOrNull(roomId.value) - // Keep using fullRoomBlocking for now as it's faster. val fullRoom = cachedRoomListItem?.fullRoom() return if (cachedRoomListItem == null || fullRoom == null) { Timber.d("No room cached for $roomId") From 0656376ce2885b56bf20c03ece26f87b57a6b8e7 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 19 Jan 2024 13:33:56 +0000 Subject: [PATCH 032/127] Update dependency com.posthog:posthog-android to v3.1.4 --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 70881ca385..1b4dd4c122 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -173,7 +173,7 @@ opusencoder = "io.element.android:opusencoder:1.1.0" kotlinpoet = "com.squareup:kotlinpoet:1.16.0" # Analytics -posthog = "com.posthog:posthog-android:3.1.3" +posthog = "com.posthog:posthog-android:3.1.4" sentry = "io.sentry:sentry-android:7.2.0" matrix_analytics_events = "com.github.matrix-org:matrix-analytics-events:aa14cbcdf81af2746d20a71779ec751f971e1d7f" From 35e5df04f51e4e48f6a941ee706f3e6de346d359 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Fri, 19 Jan 2024 15:54:06 +0100 Subject: [PATCH 033/127] Add tombstoned to the shared dict. --- .idea/dictionaries/shared.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/.idea/dictionaries/shared.xml b/.idea/dictionaries/shared.xml index c1f91b8411..c792687763 100644 --- a/.idea/dictionaries/shared.xml +++ b/.idea/dictionaries/shared.xml @@ -16,6 +16,7 @@ snackbar swipeable textfields + tombstoned From 4c86126eaedf201a233c8aa470f7055e6fa9f081 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Fri, 19 Jan 2024 15:55:26 +0100 Subject: [PATCH 034/127] Rename `aRoomSummaryDetail` to `aRoomSummaryDetails` --- .../impl/forward/ForwardMessagesPresenterTests.kt | 6 +++--- .../EditDefaultNotificationSettingsPresenterTests.kt | 4 ++-- .../libraries/matrix/test/room/RoomSummaryFixture.kt | 4 ++-- .../libraries/roomselect/impl/RoomSelectPresenterTests.kt | 8 ++++---- 4 files changed, 11 insertions(+), 11 deletions(-) diff --git a/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/forward/ForwardMessagesPresenterTests.kt b/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/forward/ForwardMessagesPresenterTests.kt index cf084700ca..c9acdba508 100644 --- a/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/forward/ForwardMessagesPresenterTests.kt +++ b/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/forward/ForwardMessagesPresenterTests.kt @@ -23,7 +23,7 @@ import com.google.common.truth.Truth.assertThat import io.element.android.libraries.matrix.api.core.EventId import io.element.android.libraries.matrix.test.AN_EVENT_ID import io.element.android.libraries.matrix.test.room.FakeMatrixRoom -import io.element.android.libraries.matrix.test.room.aRoomSummaryDetail +import io.element.android.libraries.matrix.test.room.aRoomSummaryDetails import io.element.android.tests.testutils.WarmUpRule import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.test.runTest @@ -54,7 +54,7 @@ class ForwardMessagesPresenterTests { presenter.present() }.test { skipItems(1) - val summary = aRoomSummaryDetail() + val summary = aRoomSummaryDetails() presenter.onRoomSelected(listOf(summary.roomId)) val forwardingState = awaitItem() assertThat(forwardingState.isForwarding).isTrue() @@ -74,7 +74,7 @@ class ForwardMessagesPresenterTests { // Test failed forwarding room.givenForwardEventResult(Result.failure(Throwable("error"))) skipItems(1) - val summary = aRoomSummaryDetail() + val summary = aRoomSummaryDetails() presenter.onRoomSelected(listOf(summary.roomId)) skipItems(1) val failedForwardState = awaitItem() diff --git a/features/preferences/impl/src/test/kotlin/io/element/android/features/preferences/impl/notifications/EditDefaultNotificationSettingsPresenterTests.kt b/features/preferences/impl/src/test/kotlin/io/element/android/features/preferences/impl/notifications/EditDefaultNotificationSettingsPresenterTests.kt index 25b5aa4532..c4368b3ab2 100644 --- a/features/preferences/impl/src/test/kotlin/io/element/android/features/preferences/impl/notifications/EditDefaultNotificationSettingsPresenterTests.kt +++ b/features/preferences/impl/src/test/kotlin/io/element/android/features/preferences/impl/notifications/EditDefaultNotificationSettingsPresenterTests.kt @@ -29,7 +29,7 @@ import io.element.android.libraries.matrix.test.A_THROWABLE import io.element.android.libraries.matrix.test.FakeMatrixClient import io.element.android.libraries.matrix.test.notificationsettings.FakeNotificationSettingsService import io.element.android.libraries.matrix.test.room.FakeMatrixRoom -import io.element.android.libraries.matrix.test.room.aRoomSummaryDetail +import io.element.android.libraries.matrix.test.room.aRoomSummaryDetails import io.element.android.libraries.matrix.test.roomlist.FakeRoomListService import io.element.android.tests.testutils.awaitLastSequentialItem import io.element.android.tests.testutils.consumeItemsUntilPredicate @@ -72,7 +72,7 @@ class EditDefaultNotificationSettingsPresenterTests { moleculeFlow(RecompositionMode.Immediate) { presenter.present() }.test { - roomListService.postAllRooms(listOf(RoomSummary.Filled(aRoomSummaryDetail(notificationMode = RoomNotificationMode.ALL_MESSAGES)))) + roomListService.postAllRooms(listOf(RoomSummary.Filled(aRoomSummaryDetails(notificationMode = RoomNotificationMode.ALL_MESSAGES)))) val loadedState = consumeItemsUntilPredicate { state -> state.roomsWithUserDefinedMode.any { it.details.notificationMode == RoomNotificationMode.ALL_MESSAGES } }.last() diff --git a/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/room/RoomSummaryFixture.kt b/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/room/RoomSummaryFixture.kt index 79d3acb58b..fc7463c0e0 100644 --- a/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/room/RoomSummaryFixture.kt +++ b/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/room/RoomSummaryFixture.kt @@ -40,7 +40,7 @@ fun aRoomSummaryFilled( unreadNotificationCount: Int = 2, notificationMode: RoomNotificationMode? = null, ) = RoomSummary.Filled( - aRoomSummaryDetail( + aRoomSummaryDetails( roomId = roomId, name = name, isDirect = isDirect, @@ -52,7 +52,7 @@ fun aRoomSummaryFilled( ) ) -fun aRoomSummaryDetail( +fun aRoomSummaryDetails( roomId: RoomId = A_ROOM_ID, name: String = A_ROOM_NAME, isDirect: Boolean = false, diff --git a/libraries/roomselect/impl/src/test/kotlin/io/element/android/libraries/roomselect/impl/RoomSelectPresenterTests.kt b/libraries/roomselect/impl/src/test/kotlin/io/element/android/libraries/roomselect/impl/RoomSelectPresenterTests.kt index 72ab751c39..868c00d42e 100644 --- a/libraries/roomselect/impl/src/test/kotlin/io/element/android/libraries/roomselect/impl/RoomSelectPresenterTests.kt +++ b/libraries/roomselect/impl/src/test/kotlin/io/element/android/libraries/roomselect/impl/RoomSelectPresenterTests.kt @@ -23,7 +23,7 @@ import com.google.common.truth.Truth.assertThat import io.element.android.libraries.designsystem.theme.components.SearchBarResultState import io.element.android.libraries.matrix.api.roomlist.RoomSummary import io.element.android.libraries.matrix.test.FakeMatrixClient -import io.element.android.libraries.matrix.test.room.aRoomSummaryDetail +import io.element.android.libraries.matrix.test.room.aRoomSummaryDetails import io.element.android.libraries.matrix.test.roomlist.FakeRoomListService import io.element.android.libraries.roomselect.api.RoomSelectMode import io.element.android.tests.testutils.WarmUpRule @@ -72,7 +72,7 @@ class RoomSelectPresenterTests { @Test fun `present - update query`() = runTest { val roomListService = FakeRoomListService().apply { - postAllRooms(listOf(RoomSummary.Filled(aRoomSummaryDetail()))) + postAllRooms(listOf(RoomSummary.Filled(aRoomSummaryDetails()))) } val client = FakeMatrixClient(roomListService = roomListService) val presenter = aPresenter(client = client) @@ -80,7 +80,7 @@ class RoomSelectPresenterTests { presenter.present() }.test { val initialState = awaitItem() - assertThat(awaitItem().resultState as? SearchBarResultState.Results).isEqualTo(SearchBarResultState.Results(listOf(aRoomSummaryDetail()))) + assertThat(awaitItem().resultState as? SearchBarResultState.Results).isEqualTo(SearchBarResultState.Results(listOf(aRoomSummaryDetails()))) initialState.eventSink(RoomSelectEvents.UpdateQuery("string not contained")) assertThat(awaitItem().query).isEqualTo("string not contained") @@ -96,7 +96,7 @@ class RoomSelectPresenterTests { }.test { val initialState = awaitItem() skipItems(1) - val summary = aRoomSummaryDetail() + val summary = aRoomSummaryDetails() initialState.eventSink(RoomSelectEvents.SetSelectedRoom(summary)) assertThat(awaitItem().selectedRooms).isEqualTo(persistentListOf(summary)) From d1c7520065037921c80a07bdbc3a393e55893fed Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Fri, 19 Jan 2024 15:56:51 +0100 Subject: [PATCH 035/127] Rename `avatarURLString` to `avatarUrl` --- .../features/invitelist/impl/InviteListPresenter.kt | 2 +- .../features/invitelist/impl/InviteListPresenterTests.kt | 6 +++--- .../messages/impl/forward/ForwardMessagesStateProvider.kt | 4 ++-- .../edit/EditDefaultNotificationSettingStateProvider.kt | 2 +- .../edit/EditDefaultNotificationSettingView.kt | 2 +- .../roomlist/impl/datasource/RoomListDataSource.kt | 2 +- .../android/libraries/matrix/api/roomlist/RoomSummary.kt | 2 +- .../matrix/impl/roomlist/RoomSummaryDetailsFactory.kt | 2 +- .../libraries/matrix/test/room/RoomSummaryFixture.kt | 8 ++++---- .../libraries/matrix/ui/components/SelectedRoom.kt | 4 ++-- .../libraries/roomselect/impl/RoomSelectStateProvider.kt | 4 ++-- .../android/libraries/roomselect/impl/RoomSelectView.kt | 2 +- 12 files changed, 20 insertions(+), 20 deletions(-) diff --git a/features/invitelist/impl/src/main/kotlin/io/element/android/features/invitelist/impl/InviteListPresenter.kt b/features/invitelist/impl/src/main/kotlin/io/element/android/features/invitelist/impl/InviteListPresenter.kt index f2dd87ff05..33ecb36913 100644 --- a/features/invitelist/impl/src/main/kotlin/io/element/android/features/invitelist/impl/InviteListPresenter.kt +++ b/features/invitelist/impl/src/main/kotlin/io/element/android/features/invitelist/impl/InviteListPresenter.kt @@ -169,7 +169,7 @@ class InviteListPresenter @Inject constructor( AvatarData( id = roomId.value, name = name, - url = avatarURLString, + url = avatarUrl, size = AvatarSize.RoomInviteItem, ) } diff --git a/features/invitelist/impl/src/test/kotlin/io/element/android/features/invitelist/impl/InviteListPresenterTests.kt b/features/invitelist/impl/src/test/kotlin/io/element/android/features/invitelist/impl/InviteListPresenterTests.kt index a3bafdb034..e691fc4029 100644 --- a/features/invitelist/impl/src/test/kotlin/io/element/android/features/invitelist/impl/InviteListPresenterTests.kt +++ b/features/invitelist/impl/src/test/kotlin/io/element/android/features/invitelist/impl/InviteListPresenterTests.kt @@ -428,7 +428,7 @@ class InviteListPresenterTests { RoomSummaryDetails( roomId = A_ROOM_ID, name = A_ROOM_NAME, - avatarURLString = null, + avatarUrl = null, isDirect = false, lastMessage = null, lastMessageTimestamp = null, @@ -457,7 +457,7 @@ class InviteListPresenterTests { RoomSummaryDetails( roomId = A_ROOM_ID, name = A_ROOM_NAME, - avatarURLString = null, + avatarUrl = null, isDirect = true, lastMessage = null, lastMessageTimestamp = null, @@ -483,7 +483,7 @@ class InviteListPresenterTests { RoomSummaryDetails( roomId = id, name = A_ROOM_NAME, - avatarURLString = null, + avatarUrl = null, isDirect = false, lastMessage = null, lastMessageTimestamp = null, diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/forward/ForwardMessagesStateProvider.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/forward/ForwardMessagesStateProvider.kt index 3029a174fc..7366e2453a 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/forward/ForwardMessagesStateProvider.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/forward/ForwardMessagesStateProvider.kt @@ -62,7 +62,7 @@ fun aRoomDetailsState( name: String = "roomName", canonicalAlias: String? = null, isDirect: Boolean = true, - avatarURLString: String? = null, + avatarUrl: String? = null, lastMessage: RoomMessage? = null, lastMessageTimestamp: Long? = null, unreadNotificationCount: Int = 0, @@ -72,7 +72,7 @@ fun aRoomDetailsState( name = name, canonicalAlias = canonicalAlias, isDirect = isDirect, - avatarURLString = avatarURLString, + avatarUrl = avatarUrl, lastMessage = lastMessage, lastMessageTimestamp = lastMessageTimestamp, unreadNotificationCount = unreadNotificationCount, diff --git a/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/notifications/edit/EditDefaultNotificationSettingStateProvider.kt b/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/notifications/edit/EditDefaultNotificationSettingStateProvider.kt index 0c4ef95c6c..cdf5845dff 100644 --- a/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/notifications/edit/EditDefaultNotificationSettingStateProvider.kt +++ b/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/notifications/edit/EditDefaultNotificationSettingStateProvider.kt @@ -52,7 +52,7 @@ private fun aRoomSummary() = RoomSummary.Filled( RoomSummaryDetails( roomId = RoomId("!roomId:domain"), name = "Room", - avatarURLString = null, + avatarUrl = null, isDirect = false, lastMessage = null, lastMessageTimestamp = null, diff --git a/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/notifications/edit/EditDefaultNotificationSettingView.kt b/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/notifications/edit/EditDefaultNotificationSettingView.kt index e67eb280af..1579af2b03 100644 --- a/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/notifications/edit/EditDefaultNotificationSettingView.kt +++ b/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/notifications/edit/EditDefaultNotificationSettingView.kt @@ -95,7 +95,7 @@ fun EditDefaultNotificationSettingView( val avatarData = AvatarData( id = summary.identifier(), name = summary.details.name, - url = summary.details.avatarURLString, + url = summary.details.avatarUrl, size = AvatarSize.CustomRoomNotificationSetting, ) ListItem( diff --git a/features/roomlist/impl/src/main/kotlin/io/element/android/features/roomlist/impl/datasource/RoomListDataSource.kt b/features/roomlist/impl/src/main/kotlin/io/element/android/features/roomlist/impl/datasource/RoomListDataSource.kt index 8db08dac39..e477ef8eeb 100644 --- a/features/roomlist/impl/src/main/kotlin/io/element/android/features/roomlist/impl/datasource/RoomListDataSource.kt +++ b/features/roomlist/impl/src/main/kotlin/io/element/android/features/roomlist/impl/datasource/RoomListDataSource.kt @@ -146,7 +146,7 @@ class RoomListDataSource @Inject constructor( val avatarData = AvatarData( id = roomSummary.identifier(), name = roomSummary.details.name, - url = roomSummary.details.avatarURLString, + url = roomSummary.details.avatarUrl, size = AvatarSize.RoomListItem, ) val roomIdentifier = roomSummary.identifier() diff --git a/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/roomlist/RoomSummary.kt b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/roomlist/RoomSummary.kt index a644fa9f85..68e799a405 100644 --- a/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/roomlist/RoomSummary.kt +++ b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/roomlist/RoomSummary.kt @@ -38,7 +38,7 @@ data class RoomSummaryDetails( val name: String, val canonicalAlias: String? = null, val isDirect: Boolean, - val avatarURLString: String?, + val avatarUrl: String?, val lastMessage: RoomMessage?, val lastMessageTimestamp: Long?, val unreadNotificationCount: Int, diff --git a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/roomlist/RoomSummaryDetailsFactory.kt b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/roomlist/RoomSummaryDetailsFactory.kt index f31d9d1208..b384430fb3 100644 --- a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/roomlist/RoomSummaryDetailsFactory.kt +++ b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/roomlist/RoomSummaryDetailsFactory.kt @@ -34,7 +34,7 @@ class RoomSummaryDetailsFactory(private val roomMessageFactory: RoomMessageFacto name = roomInfo.name ?: roomInfo.id, canonicalAlias = roomInfo.canonicalAlias, isDirect = roomInfo.isDirect, - avatarURLString = roomInfo.avatarUrl, + avatarUrl = roomInfo.avatarUrl, unreadNotificationCount = roomInfo.notificationCount.toInt(), lastMessage = latestRoomMessage, lastMessageTimestamp = latestRoomMessage?.originServerTs, diff --git a/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/room/RoomSummaryFixture.kt b/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/room/RoomSummaryFixture.kt index fc7463c0e0..7b0269334b 100644 --- a/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/room/RoomSummaryFixture.kt +++ b/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/room/RoomSummaryFixture.kt @@ -34,7 +34,7 @@ fun aRoomSummaryFilled( roomId: RoomId = A_ROOM_ID, name: String = A_ROOM_NAME, isDirect: Boolean = false, - avatarURLString: String? = null, + avatarUrl: String? = null, lastMessage: RoomMessage? = aRoomMessage(), lastMessageTimestamp: Long? = null, unreadNotificationCount: Int = 2, @@ -44,7 +44,7 @@ fun aRoomSummaryFilled( roomId = roomId, name = name, isDirect = isDirect, - avatarURLString = avatarURLString, + avatarUrl = avatarUrl, lastMessage = lastMessage, lastMessageTimestamp = lastMessageTimestamp, unreadNotificationCount = unreadNotificationCount, @@ -56,7 +56,7 @@ fun aRoomSummaryDetails( roomId: RoomId = A_ROOM_ID, name: String = A_ROOM_NAME, isDirect: Boolean = false, - avatarURLString: String? = null, + avatarUrl: String? = null, lastMessage: RoomMessage? = aRoomMessage(), lastMessageTimestamp: Long? = null, unreadNotificationCount: Int = 2, @@ -65,7 +65,7 @@ fun aRoomSummaryDetails( roomId = roomId, name = name, isDirect = isDirect, - avatarURLString = avatarURLString, + avatarUrl = avatarUrl, lastMessage = lastMessage, lastMessageTimestamp = lastMessageTimestamp, unreadNotificationCount = unreadNotificationCount, diff --git a/libraries/matrixui/src/main/kotlin/io/element/android/libraries/matrix/ui/components/SelectedRoom.kt b/libraries/matrixui/src/main/kotlin/io/element/android/libraries/matrix/ui/components/SelectedRoom.kt index 02767e10bb..1195499e5b 100644 --- a/libraries/matrixui/src/main/kotlin/io/element/android/libraries/matrix/ui/components/SelectedRoom.kt +++ b/libraries/matrixui/src/main/kotlin/io/element/android/libraries/matrix/ui/components/SelectedRoom.kt @@ -60,7 +60,7 @@ fun SelectedRoom( Column( horizontalAlignment = Alignment.CenterHorizontally, ) { - Avatar(AvatarData(roomSummary.roomId.value, roomSummary.name, roomSummary.avatarURLString, AvatarSize.SelectedRoom)) + Avatar(AvatarData(roomSummary.roomId.value, roomSummary.name, roomSummary.avatarUrl, AvatarSize.SelectedRoom)) Text( text = roomSummary.name, overflow = TextOverflow.Ellipsis, @@ -99,7 +99,7 @@ internal fun SelectedRoomPreview() = ElementPreview { name = "roomName", canonicalAlias = null, isDirect = true, - avatarURLString = null, + avatarUrl = null, lastMessage = null, lastMessageTimestamp = null, unreadNotificationCount = 0, diff --git a/libraries/roomselect/impl/src/main/kotlin/io/element/android/libraries/roomselect/impl/RoomSelectStateProvider.kt b/libraries/roomselect/impl/src/main/kotlin/io/element/android/libraries/roomselect/impl/RoomSelectStateProvider.kt index 032dc4a8d0..297f891831 100644 --- a/libraries/roomselect/impl/src/main/kotlin/io/element/android/libraries/roomselect/impl/RoomSelectStateProvider.kt +++ b/libraries/roomselect/impl/src/main/kotlin/io/element/android/libraries/roomselect/impl/RoomSelectStateProvider.kt @@ -75,7 +75,7 @@ private fun aRoomDetailsState( name: String = "roomName", canonicalAlias: String? = null, isDirect: Boolean = true, - avatarURLString: String? = null, + avatarUrl: String? = null, lastMessage: RoomMessage? = null, lastMessageTimestamp: Long? = null, unreadNotificationCount: Int = 0, @@ -85,7 +85,7 @@ private fun aRoomDetailsState( name = name, canonicalAlias = canonicalAlias, isDirect = isDirect, - avatarURLString = avatarURLString, + avatarUrl = avatarUrl, lastMessage = lastMessage, lastMessageTimestamp = lastMessageTimestamp, unreadNotificationCount = unreadNotificationCount, diff --git a/libraries/roomselect/impl/src/main/kotlin/io/element/android/libraries/roomselect/impl/RoomSelectView.kt b/libraries/roomselect/impl/src/main/kotlin/io/element/android/libraries/roomselect/impl/RoomSelectView.kt index 83b3608eae..d7453ec264 100644 --- a/libraries/roomselect/impl/src/main/kotlin/io/element/android/libraries/roomselect/impl/RoomSelectView.kt +++ b/libraries/roomselect/impl/src/main/kotlin/io/element/android/libraries/roomselect/impl/RoomSelectView.kt @@ -223,7 +223,7 @@ private fun RoomSummaryView( avatarData = AvatarData( id = summary.roomId.value, name = summary.name, - url = summary.avatarURLString, + url = summary.avatarUrl, size = AvatarSize.RoomSelectRoomListItem, ), ) From be0da18a7b404b2f4ec189df23fb1fce844e6232 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Fri, 19 Jan 2024 15:59:50 +0100 Subject: [PATCH 036/127] Rename `userAvatarURLString` to `userAvatarUrl` --- .../features/roomlist/impl/RoomListPresenterTests.kt | 2 +- .../io/element/android/libraries/matrix/api/MatrixClient.kt | 2 +- .../android/libraries/matrix/api/user/CurrentUser.kt | 4 ++-- .../android/libraries/matrix/impl/RustMatrixClient.kt | 2 +- .../android/libraries/matrix/test/FakeMatrixClient.kt | 6 +++--- .../impl/notifications/DefaultNotificationDrawerManager.kt | 2 +- 6 files changed, 9 insertions(+), 9 deletions(-) diff --git a/features/roomlist/impl/src/test/kotlin/io/element/android/features/roomlist/impl/RoomListPresenterTests.kt b/features/roomlist/impl/src/test/kotlin/io/element/android/features/roomlist/impl/RoomListPresenterTests.kt index f56379f186..0efb2b7da5 100644 --- a/features/roomlist/impl/src/test/kotlin/io/element/android/features/roomlist/impl/RoomListPresenterTests.kt +++ b/features/roomlist/impl/src/test/kotlin/io/element/android/features/roomlist/impl/RoomListPresenterTests.kt @@ -122,7 +122,7 @@ class RoomListPresenterTests { fun `present - should start with no user and then load user with error`() = runTest { val matrixClient = FakeMatrixClient( userDisplayName = Result.failure(AN_EXCEPTION), - userAvatarURLString = Result.failure(AN_EXCEPTION), + userAvatarUrl = Result.failure(AN_EXCEPTION), ) val scope = CoroutineScope(coroutineContext + SupervisorJob()) val presenter = createRoomListPresenter(client = matrixClient, coroutineScope = scope) diff --git a/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/MatrixClient.kt b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/MatrixClient.kt index dc452f1514..e5ae0c9571 100644 --- a/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/MatrixClient.kt +++ b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/MatrixClient.kt @@ -72,7 +72,7 @@ interface MatrixClient : Closeable { */ suspend fun logout(ignoreSdkError: Boolean): String? suspend fun loadUserDisplayName(): Result - suspend fun loadUserAvatarURLString(): Result + suspend fun loadUserAvatarUrl(): Result suspend fun getAccountManagementUrl(action: AccountManagementAction?): Result suspend fun uploadMedia(mimeType: String, data: ByteArray, progressCallback: ProgressCallback?): Result fun roomMembershipObserver(): RoomMembershipObserver diff --git a/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/user/CurrentUser.kt b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/user/CurrentUser.kt index 3968b058d9..56b61e4cde 100644 --- a/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/user/CurrentUser.kt +++ b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/user/CurrentUser.kt @@ -19,11 +19,11 @@ package io.element.android.libraries.matrix.api.user import io.element.android.libraries.matrix.api.MatrixClient /** - * Get the current user, as [MatrixUser], using [MatrixClient.loadUserAvatarURLString] + * Get the current user, as [MatrixUser], using [MatrixClient.loadUserAvatarUrl] * and [MatrixClient.loadUserDisplayName]. */ suspend fun MatrixClient.getCurrentUser(): MatrixUser { - val userAvatarUrl = loadUserAvatarURLString().getOrNull() + val userAvatarUrl = loadUserAvatarUrl().getOrNull() val userDisplayName = loadUserDisplayName().getOrNull() return MatrixUser( userId = sessionId, diff --git a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/RustMatrixClient.kt b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/RustMatrixClient.kt index a7b13c0b8d..9bee32a488 100644 --- a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/RustMatrixClient.kt +++ b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/RustMatrixClient.kt @@ -426,7 +426,7 @@ class RustMatrixClient( } } - override suspend fun loadUserAvatarURLString(): Result = withContext(sessionDispatcher) { + override suspend fun loadUserAvatarUrl(): Result = withContext(sessionDispatcher) { runCatching { client.avatarUrl() } diff --git a/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/FakeMatrixClient.kt b/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/FakeMatrixClient.kt index a8d1d09818..0c4704c410 100644 --- a/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/FakeMatrixClient.kt +++ b/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/FakeMatrixClient.kt @@ -48,7 +48,7 @@ import kotlinx.coroutines.delay class FakeMatrixClient( override val sessionId: SessionId = A_SESSION_ID, private val userDisplayName: Result = Result.success(A_USER_NAME), - private val userAvatarURLString: Result = Result.success(AN_AVATAR_URL), + private val userAvatarUrl: Result = Result.success(AN_AVATAR_URL), override val roomListService: RoomListService = FakeRoomListService(), override val mediaLoader: MatrixMediaLoader = FakeMediaLoader(), private val sessionVerificationService: FakeSessionVerificationService = FakeSessionVerificationService(), @@ -135,8 +135,8 @@ class FakeMatrixClient( return userDisplayName } - override suspend fun loadUserAvatarURLString(): Result { - return userAvatarURLString + override suspend fun loadUserAvatarUrl(): Result { + return userAvatarUrl } override suspend fun getAccountManagementUrl(action: AccountManagementAction?): Result { diff --git a/libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/notifications/DefaultNotificationDrawerManager.kt b/libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/notifications/DefaultNotificationDrawerManager.kt index 904a6bf2ea..9d12d7bd6c 100644 --- a/libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/notifications/DefaultNotificationDrawerManager.kt +++ b/libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/notifications/DefaultNotificationDrawerManager.kt @@ -297,7 +297,7 @@ class DefaultNotificationDrawerManager @Inject constructor( operation = { // myUserDisplayName cannot be empty else NotificationCompat.MessagingStyle() will crash val myUserDisplayName = client.loadUserDisplayName().getOrNull() ?: sessionId.value - val userAvatarUrl = client.loadUserAvatarURLString().getOrNull() + val userAvatarUrl = client.loadUserAvatarUrl().getOrNull() MatrixUser( userId = sessionId, displayName = myUserDisplayName, From 2c691d527bf1723bf396a8c393a019c191ff4f35 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Fri, 19 Jan 2024 16:11:10 +0100 Subject: [PATCH 037/127] Remove `RoomSummaryDetails.lastMessageTimestamp` and replace by a getter on `lastMessage` --- .../features/invitelist/impl/InviteListPresenterTests.kt | 3 --- .../messages/impl/forward/ForwardMessagesStateProvider.kt | 2 -- .../edit/EditDefaultNotificationSettingStateProvider.kt | 1 - .../android/libraries/matrix/api/roomlist/RoomSummary.kt | 5 +++-- .../matrix/impl/roomlist/RoomSummaryDetailsFactory.kt | 1 - .../android/libraries/matrix/test/room/RoomSummaryFixture.kt | 4 ---- .../android/libraries/matrix/ui/components/SelectedRoom.kt | 1 - .../libraries/roomselect/impl/RoomSelectStateProvider.kt | 2 -- 8 files changed, 3 insertions(+), 16 deletions(-) diff --git a/features/invitelist/impl/src/test/kotlin/io/element/android/features/invitelist/impl/InviteListPresenterTests.kt b/features/invitelist/impl/src/test/kotlin/io/element/android/features/invitelist/impl/InviteListPresenterTests.kt index e691fc4029..9ba0181e45 100644 --- a/features/invitelist/impl/src/test/kotlin/io/element/android/features/invitelist/impl/InviteListPresenterTests.kt +++ b/features/invitelist/impl/src/test/kotlin/io/element/android/features/invitelist/impl/InviteListPresenterTests.kt @@ -431,7 +431,6 @@ class InviteListPresenterTests { avatarUrl = null, isDirect = false, lastMessage = null, - lastMessageTimestamp = null, unreadNotificationCount = 0, inviter = RoomMember( userId = A_USER_ID, @@ -460,7 +459,6 @@ class InviteListPresenterTests { avatarUrl = null, isDirect = true, lastMessage = null, - lastMessageTimestamp = null, unreadNotificationCount = 0, inviter = RoomMember( userId = A_USER_ID, @@ -486,7 +484,6 @@ class InviteListPresenterTests { avatarUrl = null, isDirect = false, lastMessage = null, - lastMessageTimestamp = null, unreadNotificationCount = 0, ) ) diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/forward/ForwardMessagesStateProvider.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/forward/ForwardMessagesStateProvider.kt index 7366e2453a..729714e626 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/forward/ForwardMessagesStateProvider.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/forward/ForwardMessagesStateProvider.kt @@ -64,7 +64,6 @@ fun aRoomDetailsState( isDirect: Boolean = true, avatarUrl: String? = null, lastMessage: RoomMessage? = null, - lastMessageTimestamp: Long? = null, unreadNotificationCount: Int = 0, inviter: RoomMember? = null, ) = RoomSummaryDetails( @@ -74,7 +73,6 @@ fun aRoomDetailsState( isDirect = isDirect, avatarUrl = avatarUrl, lastMessage = lastMessage, - lastMessageTimestamp = lastMessageTimestamp, unreadNotificationCount = unreadNotificationCount, inviter = inviter, ) diff --git a/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/notifications/edit/EditDefaultNotificationSettingStateProvider.kt b/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/notifications/edit/EditDefaultNotificationSettingStateProvider.kt index cdf5845dff..c76cb97df9 100644 --- a/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/notifications/edit/EditDefaultNotificationSettingStateProvider.kt +++ b/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/notifications/edit/EditDefaultNotificationSettingStateProvider.kt @@ -55,7 +55,6 @@ private fun aRoomSummary() = RoomSummary.Filled( avatarUrl = null, isDirect = false, lastMessage = null, - lastMessageTimestamp = null, unreadNotificationCount = 0, notificationMode = RoomNotificationMode.MENTIONS_AND_KEYWORDS_ONLY, ) diff --git a/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/roomlist/RoomSummary.kt b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/roomlist/RoomSummary.kt index 68e799a405..681f33d45b 100644 --- a/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/roomlist/RoomSummary.kt +++ b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/roomlist/RoomSummary.kt @@ -40,10 +40,11 @@ data class RoomSummaryDetails( val isDirect: Boolean, val avatarUrl: String?, val lastMessage: RoomMessage?, - val lastMessageTimestamp: Long?, val unreadNotificationCount: Int, val inviter: RoomMember? = null, val notificationMode: RoomNotificationMode? = null, val hasOngoingCall: Boolean = false, val isDm: Boolean = false, -) +) { + val lastMessageTimestamp = lastMessage?.originServerTs +} diff --git a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/roomlist/RoomSummaryDetailsFactory.kt b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/roomlist/RoomSummaryDetailsFactory.kt index b384430fb3..81e2e578ed 100644 --- a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/roomlist/RoomSummaryDetailsFactory.kt +++ b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/roomlist/RoomSummaryDetailsFactory.kt @@ -37,7 +37,6 @@ class RoomSummaryDetailsFactory(private val roomMessageFactory: RoomMessageFacto avatarUrl = roomInfo.avatarUrl, unreadNotificationCount = roomInfo.notificationCount.toInt(), lastMessage = latestRoomMessage, - lastMessageTimestamp = latestRoomMessage?.originServerTs, inviter = roomInfo.inviter?.let(RoomMemberMapper::map), notificationMode = roomInfo.userDefinedNotificationMode?.let(RoomNotificationSettingsMapper::mapMode), hasOngoingCall = roomInfo.hasRoomCall, diff --git a/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/room/RoomSummaryFixture.kt b/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/room/RoomSummaryFixture.kt index 7b0269334b..11161ff3ae 100644 --- a/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/room/RoomSummaryFixture.kt +++ b/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/room/RoomSummaryFixture.kt @@ -36,7 +36,6 @@ fun aRoomSummaryFilled( isDirect: Boolean = false, avatarUrl: String? = null, lastMessage: RoomMessage? = aRoomMessage(), - lastMessageTimestamp: Long? = null, unreadNotificationCount: Int = 2, notificationMode: RoomNotificationMode? = null, ) = RoomSummary.Filled( @@ -46,7 +45,6 @@ fun aRoomSummaryFilled( isDirect = isDirect, avatarUrl = avatarUrl, lastMessage = lastMessage, - lastMessageTimestamp = lastMessageTimestamp, unreadNotificationCount = unreadNotificationCount, notificationMode = notificationMode, ) @@ -58,7 +56,6 @@ fun aRoomSummaryDetails( isDirect: Boolean = false, avatarUrl: String? = null, lastMessage: RoomMessage? = aRoomMessage(), - lastMessageTimestamp: Long? = null, unreadNotificationCount: Int = 2, notificationMode: RoomNotificationMode? = null, ) = RoomSummaryDetails( @@ -67,7 +64,6 @@ fun aRoomSummaryDetails( isDirect = isDirect, avatarUrl = avatarUrl, lastMessage = lastMessage, - lastMessageTimestamp = lastMessageTimestamp, unreadNotificationCount = unreadNotificationCount, notificationMode = notificationMode ) diff --git a/libraries/matrixui/src/main/kotlin/io/element/android/libraries/matrix/ui/components/SelectedRoom.kt b/libraries/matrixui/src/main/kotlin/io/element/android/libraries/matrix/ui/components/SelectedRoom.kt index 1195499e5b..8d603f54eb 100644 --- a/libraries/matrixui/src/main/kotlin/io/element/android/libraries/matrix/ui/components/SelectedRoom.kt +++ b/libraries/matrixui/src/main/kotlin/io/element/android/libraries/matrix/ui/components/SelectedRoom.kt @@ -101,7 +101,6 @@ internal fun SelectedRoomPreview() = ElementPreview { isDirect = true, avatarUrl = null, lastMessage = null, - lastMessageTimestamp = null, unreadNotificationCount = 0, inviter = null, ), diff --git a/libraries/roomselect/impl/src/main/kotlin/io/element/android/libraries/roomselect/impl/RoomSelectStateProvider.kt b/libraries/roomselect/impl/src/main/kotlin/io/element/android/libraries/roomselect/impl/RoomSelectStateProvider.kt index 297f891831..afa056fb21 100644 --- a/libraries/roomselect/impl/src/main/kotlin/io/element/android/libraries/roomselect/impl/RoomSelectStateProvider.kt +++ b/libraries/roomselect/impl/src/main/kotlin/io/element/android/libraries/roomselect/impl/RoomSelectStateProvider.kt @@ -77,7 +77,6 @@ private fun aRoomDetailsState( isDirect: Boolean = true, avatarUrl: String? = null, lastMessage: RoomMessage? = null, - lastMessageTimestamp: Long? = null, unreadNotificationCount: Int = 0, inviter: RoomMember? = null, ) = RoomSummaryDetails( @@ -87,7 +86,6 @@ private fun aRoomDetailsState( isDirect = isDirect, avatarUrl = avatarUrl, lastMessage = lastMessage, - lastMessageTimestamp = lastMessageTimestamp, unreadNotificationCount = unreadNotificationCount, inviter = inviter, ) From ecb000b8edb904f8f43e017526f82d44e80d150f Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Fri, 19 Jan 2024 16:16:57 +0100 Subject: [PATCH 038/127] Remove `hasOngoingCall` to `hasRoomCall` to match SDK name. --- .../android/features/roomlist/impl/components/RoomSummaryRow.kt | 2 +- .../features/roomlist/impl/datasource/RoomListDataSource.kt | 2 +- .../android/features/roomlist/impl/model/RoomListRoomSummary.kt | 2 +- .../features/roomlist/impl/model/RoomListRoomSummaryProvider.kt | 2 +- .../android/libraries/matrix/api/roomlist/RoomSummary.kt | 2 +- .../libraries/matrix/impl/roomlist/RoomSummaryDetailsFactory.kt | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/features/roomlist/impl/src/main/kotlin/io/element/android/features/roomlist/impl/components/RoomSummaryRow.kt b/features/roomlist/impl/src/main/kotlin/io/element/android/features/roomlist/impl/components/RoomSummaryRow.kt index effea847d0..9f34beb7e5 100644 --- a/features/roomlist/impl/src/main/kotlin/io/element/android/features/roomlist/impl/components/RoomSummaryRow.kt +++ b/features/roomlist/impl/src/main/kotlin/io/element/android/features/roomlist/impl/components/RoomSummaryRow.kt @@ -173,7 +173,7 @@ private fun RowScope.LastMessageAndIndicatorRow(room: RoomListRoomSummary) { verticalAlignment = Alignment.CenterVertically, ) { // Video call - if (room.hasOngoingCall) { + if (room.hasRoomCall) { Icon( modifier = Modifier.size(16.dp), imageVector = CompoundIcons.VideoCallSolid, diff --git a/features/roomlist/impl/src/main/kotlin/io/element/android/features/roomlist/impl/datasource/RoomListDataSource.kt b/features/roomlist/impl/src/main/kotlin/io/element/android/features/roomlist/impl/datasource/RoomListDataSource.kt index e477ef8eeb..8b6bfba05b 100644 --- a/features/roomlist/impl/src/main/kotlin/io/element/android/features/roomlist/impl/datasource/RoomListDataSource.kt +++ b/features/roomlist/impl/src/main/kotlin/io/element/android/features/roomlist/impl/datasource/RoomListDataSource.kt @@ -161,7 +161,7 @@ class RoomListDataSource @Inject constructor( }.orEmpty(), avatarData = avatarData, notificationMode = roomSummary.details.notificationMode, - hasOngoingCall = roomSummary.details.hasOngoingCall, + hasRoomCall = roomSummary.details.hasRoomCall, isDm = roomSummary.details.isDm, ) } diff --git a/features/roomlist/impl/src/main/kotlin/io/element/android/features/roomlist/impl/model/RoomListRoomSummary.kt b/features/roomlist/impl/src/main/kotlin/io/element/android/features/roomlist/impl/model/RoomListRoomSummary.kt index ecb3aa6a96..404488e6c5 100644 --- a/features/roomlist/impl/src/main/kotlin/io/element/android/features/roomlist/impl/model/RoomListRoomSummary.kt +++ b/features/roomlist/impl/src/main/kotlin/io/element/android/features/roomlist/impl/model/RoomListRoomSummary.kt @@ -33,6 +33,6 @@ data class RoomListRoomSummary( val avatarData: AvatarData = AvatarData(id, name, size = AvatarSize.RoomListItem), val isPlaceholder: Boolean = false, val notificationMode: RoomNotificationMode? = null, - val hasOngoingCall: Boolean = false, + val hasRoomCall: Boolean = false, val isDm: Boolean = false, ) diff --git a/features/roomlist/impl/src/main/kotlin/io/element/android/features/roomlist/impl/model/RoomListRoomSummaryProvider.kt b/features/roomlist/impl/src/main/kotlin/io/element/android/features/roomlist/impl/model/RoomListRoomSummaryProvider.kt index 2649704427..1bb88699a2 100644 --- a/features/roomlist/impl/src/main/kotlin/io/element/android/features/roomlist/impl/model/RoomListRoomSummaryProvider.kt +++ b/features/roomlist/impl/src/main/kotlin/io/element/android/features/roomlist/impl/model/RoomListRoomSummaryProvider.kt @@ -40,7 +40,7 @@ open class RoomListRoomSummaryProvider : PreviewParameterProvider Date: Fri, 19 Jan 2024 16:46:14 +0100 Subject: [PATCH 039/127] Remove `notificationMode` to `userDefinedNotificationMode` to match SDK name. --- .../edit/EditDefaultNotificationSettingStateProvider.kt | 2 +- .../edit/EditDefaultNotificationSettingView.kt | 2 +- .../EditDefaultNotificationSettingsPresenterTests.kt | 4 ++-- .../features/roomlist/impl/components/RoomSummaryRow.kt | 2 +- .../features/roomlist/impl/datasource/RoomListDataSource.kt | 2 +- .../features/roomlist/impl/model/RoomListRoomSummary.kt | 2 +- .../roomlist/impl/model/RoomListRoomSummaryProvider.kt | 6 +++--- .../features/roomlist/impl/RoomListPresenterTests.kt | 4 ++-- .../android/libraries/matrix/api/roomlist/RoomSummary.kt | 2 +- .../matrix/impl/roomlist/RoomSummaryDetailsFactory.kt | 2 +- .../libraries/matrix/test/room/RoomSummaryFixture.kt | 2 +- 11 files changed, 15 insertions(+), 15 deletions(-) diff --git a/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/notifications/edit/EditDefaultNotificationSettingStateProvider.kt b/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/notifications/edit/EditDefaultNotificationSettingStateProvider.kt index c76cb97df9..a2571293e9 100644 --- a/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/notifications/edit/EditDefaultNotificationSettingStateProvider.kt +++ b/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/notifications/edit/EditDefaultNotificationSettingStateProvider.kt @@ -56,6 +56,6 @@ private fun aRoomSummary() = RoomSummary.Filled( isDirect = false, lastMessage = null, unreadNotificationCount = 0, - notificationMode = RoomNotificationMode.MENTIONS_AND_KEYWORDS_ONLY, + userDefinedNotificationMode = RoomNotificationMode.MENTIONS_AND_KEYWORDS_ONLY, ) ) diff --git a/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/notifications/edit/EditDefaultNotificationSettingView.kt b/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/notifications/edit/EditDefaultNotificationSettingView.kt index 1579af2b03..9eca90fa54 100644 --- a/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/notifications/edit/EditDefaultNotificationSettingView.kt +++ b/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/notifications/edit/EditDefaultNotificationSettingView.kt @@ -84,7 +84,7 @@ fun EditDefaultNotificationSettingView( if (state.roomsWithUserDefinedMode.isNotEmpty()) { PreferenceCategory(title = stringResource(id = R.string.screen_notification_settings_edit_custom_settings_section_title)) { state.roomsWithUserDefinedMode.forEach { summary -> - val subtitle = when (summary.details.notificationMode) { + val subtitle = when (summary.details.userDefinedNotificationMode) { RoomNotificationMode.ALL_MESSAGES -> stringResource(id = R.string.screen_notification_settings_edit_mode_all_messages) RoomNotificationMode.MENTIONS_AND_KEYWORDS_ONLY -> { stringResource(id = R.string.screen_notification_settings_edit_mode_mentions_and_keywords) diff --git a/features/preferences/impl/src/test/kotlin/io/element/android/features/preferences/impl/notifications/EditDefaultNotificationSettingsPresenterTests.kt b/features/preferences/impl/src/test/kotlin/io/element/android/features/preferences/impl/notifications/EditDefaultNotificationSettingsPresenterTests.kt index c4368b3ab2..c8655d6a26 100644 --- a/features/preferences/impl/src/test/kotlin/io/element/android/features/preferences/impl/notifications/EditDefaultNotificationSettingsPresenterTests.kt +++ b/features/preferences/impl/src/test/kotlin/io/element/android/features/preferences/impl/notifications/EditDefaultNotificationSettingsPresenterTests.kt @@ -74,9 +74,9 @@ class EditDefaultNotificationSettingsPresenterTests { }.test { roomListService.postAllRooms(listOf(RoomSummary.Filled(aRoomSummaryDetails(notificationMode = RoomNotificationMode.ALL_MESSAGES)))) val loadedState = consumeItemsUntilPredicate { state -> - state.roomsWithUserDefinedMode.any { it.details.notificationMode == RoomNotificationMode.ALL_MESSAGES } + state.roomsWithUserDefinedMode.any { it.details.userDefinedNotificationMode == RoomNotificationMode.ALL_MESSAGES } }.last() - assertThat(loadedState.roomsWithUserDefinedMode.any { it.details.notificationMode == RoomNotificationMode.ALL_MESSAGES }).isTrue() + assertThat(loadedState.roomsWithUserDefinedMode.any { it.details.userDefinedNotificationMode == RoomNotificationMode.ALL_MESSAGES }).isTrue() } } diff --git a/features/roomlist/impl/src/main/kotlin/io/element/android/features/roomlist/impl/components/RoomSummaryRow.kt b/features/roomlist/impl/src/main/kotlin/io/element/android/features/roomlist/impl/components/RoomSummaryRow.kt index 9f34beb7e5..d8ee21093f 100644 --- a/features/roomlist/impl/src/main/kotlin/io/element/android/features/roomlist/impl/components/RoomSummaryRow.kt +++ b/features/roomlist/impl/src/main/kotlin/io/element/android/features/roomlist/impl/components/RoomSummaryRow.kt @@ -191,7 +191,7 @@ private fun RowScope.LastMessageAndIndicatorRow(room: RoomListRoomSummary) { @Composable private fun NotificationIcon(room: RoomListRoomSummary) { val tint = if (room.hasUnread) ElementTheme.colors.unreadIndicator else ElementTheme.colors.iconQuaternary - when (room.notificationMode) { + when (room.userDefinedNotificationMode) { null, RoomNotificationMode.ALL_MESSAGES -> return RoomNotificationMode.MENTIONS_AND_KEYWORDS_ONLY -> Icon( diff --git a/features/roomlist/impl/src/main/kotlin/io/element/android/features/roomlist/impl/datasource/RoomListDataSource.kt b/features/roomlist/impl/src/main/kotlin/io/element/android/features/roomlist/impl/datasource/RoomListDataSource.kt index 8b6bfba05b..37f26e37ea 100644 --- a/features/roomlist/impl/src/main/kotlin/io/element/android/features/roomlist/impl/datasource/RoomListDataSource.kt +++ b/features/roomlist/impl/src/main/kotlin/io/element/android/features/roomlist/impl/datasource/RoomListDataSource.kt @@ -160,7 +160,7 @@ class RoomListDataSource @Inject constructor( roomLastMessageFormatter.format(message.event, roomSummary.details.isDirect) }.orEmpty(), avatarData = avatarData, - notificationMode = roomSummary.details.notificationMode, + userDefinedNotificationMode = roomSummary.details.userDefinedNotificationMode, hasRoomCall = roomSummary.details.hasRoomCall, isDm = roomSummary.details.isDm, ) diff --git a/features/roomlist/impl/src/main/kotlin/io/element/android/features/roomlist/impl/model/RoomListRoomSummary.kt b/features/roomlist/impl/src/main/kotlin/io/element/android/features/roomlist/impl/model/RoomListRoomSummary.kt index 404488e6c5..629013d26e 100644 --- a/features/roomlist/impl/src/main/kotlin/io/element/android/features/roomlist/impl/model/RoomListRoomSummary.kt +++ b/features/roomlist/impl/src/main/kotlin/io/element/android/features/roomlist/impl/model/RoomListRoomSummary.kt @@ -32,7 +32,7 @@ data class RoomListRoomSummary( val lastMessage: CharSequence? = null, val avatarData: AvatarData = AvatarData(id, name, size = AvatarSize.RoomListItem), val isPlaceholder: Boolean = false, - val notificationMode: RoomNotificationMode? = null, + val userDefinedNotificationMode: RoomNotificationMode? = null, val hasRoomCall: Boolean = false, val isDm: Boolean = false, ) diff --git a/features/roomlist/impl/src/main/kotlin/io/element/android/features/roomlist/impl/model/RoomListRoomSummaryProvider.kt b/features/roomlist/impl/src/main/kotlin/io/element/android/features/roomlist/impl/model/RoomListRoomSummaryProvider.kt index 1bb88699a2..2d2233c2a0 100644 --- a/features/roomlist/impl/src/main/kotlin/io/element/android/features/roomlist/impl/model/RoomListRoomSummaryProvider.kt +++ b/features/roomlist/impl/src/main/kotlin/io/element/android/features/roomlist/impl/model/RoomListRoomSummaryProvider.kt @@ -27,9 +27,9 @@ open class RoomListRoomSummaryProvider : PreviewParameterProvider - state.roomList.any { it.id == A_ROOM_ID.value && it.notificationMode == userDefinedMode } + state.roomList.any { it.id == A_ROOM_ID.value && it.userDefinedNotificationMode == userDefinedMode } }.last() val room = updatedState.roomList.find { it.id == A_ROOM_ID.value } - assertThat(room?.notificationMode).isEqualTo(userDefinedMode) + assertThat(room?.userDefinedNotificationMode).isEqualTo(userDefinedMode) cancelAndIgnoreRemainingEvents() scope.cancel() } diff --git a/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/roomlist/RoomSummary.kt b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/roomlist/RoomSummary.kt index 477ea30427..719452cc16 100644 --- a/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/roomlist/RoomSummary.kt +++ b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/roomlist/RoomSummary.kt @@ -42,7 +42,7 @@ data class RoomSummaryDetails( val lastMessage: RoomMessage?, val unreadNotificationCount: Int, val inviter: RoomMember? = null, - val notificationMode: RoomNotificationMode? = null, + val userDefinedNotificationMode: RoomNotificationMode? = null, val hasRoomCall: Boolean = false, val isDm: Boolean = false, ) { diff --git a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/roomlist/RoomSummaryDetailsFactory.kt b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/roomlist/RoomSummaryDetailsFactory.kt index 767bbe9c89..5dd6f1ff8a 100644 --- a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/roomlist/RoomSummaryDetailsFactory.kt +++ b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/roomlist/RoomSummaryDetailsFactory.kt @@ -38,7 +38,7 @@ class RoomSummaryDetailsFactory(private val roomMessageFactory: RoomMessageFacto unreadNotificationCount = roomInfo.notificationCount.toInt(), lastMessage = latestRoomMessage, inviter = roomInfo.inviter?.let(RoomMemberMapper::map), - notificationMode = roomInfo.userDefinedNotificationMode?.let(RoomNotificationSettingsMapper::mapMode), + userDefinedNotificationMode = roomInfo.userDefinedNotificationMode?.let(RoomNotificationSettingsMapper::mapMode), hasRoomCall = roomInfo.hasRoomCall, isDm = roomInfo.isDirect && roomInfo.activeMembersCount.toLong() == 2L, ) diff --git a/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/room/RoomSummaryFixture.kt b/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/room/RoomSummaryFixture.kt index 11161ff3ae..ae552457e9 100644 --- a/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/room/RoomSummaryFixture.kt +++ b/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/room/RoomSummaryFixture.kt @@ -65,7 +65,7 @@ fun aRoomSummaryDetails( avatarUrl = avatarUrl, lastMessage = lastMessage, unreadNotificationCount = unreadNotificationCount, - notificationMode = notificationMode + userDefinedNotificationMode = notificationMode ) fun aRoomMessage( From b58ac4b02fc2785aea21220f697075380124eef5 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Fri, 19 Jan 2024 16:27:52 +0100 Subject: [PATCH 040/127] Remove dead code. --- .../forward/ForwardMessagesStateProvider.kt | 28 ------------------- 1 file changed, 28 deletions(-) diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/forward/ForwardMessagesStateProvider.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/forward/ForwardMessagesStateProvider.kt index 729714e626..aa33b1cbd9 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/forward/ForwardMessagesStateProvider.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/forward/ForwardMessagesStateProvider.kt @@ -18,9 +18,6 @@ package io.element.android.features.messages.impl.forward import androidx.compose.ui.tooling.preview.PreviewParameterProvider import io.element.android.libraries.matrix.api.core.RoomId -import io.element.android.libraries.matrix.api.room.RoomMember -import io.element.android.libraries.matrix.api.room.message.RoomMessage -import io.element.android.libraries.matrix.api.roomlist.RoomSummaryDetails import kotlinx.collections.immutable.ImmutableList import kotlinx.collections.immutable.persistentListOf @@ -51,28 +48,3 @@ fun aForwardMessagesState( forwardingSucceeded = forwardingSucceeded, eventSink = {} ) - -internal fun aForwardMessagesRoomList() = persistentListOf( - aRoomDetailsState(), - aRoomDetailsState(roomId = RoomId("!room2:domain"), canonicalAlias = "#element-x-room:matrix.org"), -) - -fun aRoomDetailsState( - roomId: RoomId = RoomId("!room:domain"), - name: String = "roomName", - canonicalAlias: String? = null, - isDirect: Boolean = true, - avatarUrl: String? = null, - lastMessage: RoomMessage? = null, - unreadNotificationCount: Int = 0, - inviter: RoomMember? = null, -) = RoomSummaryDetails( - roomId = roomId, - name = name, - canonicalAlias = canonicalAlias, - isDirect = isDirect, - avatarUrl = avatarUrl, - lastMessage = lastMessage, - unreadNotificationCount = unreadNotificationCount, - inviter = inviter, -) From f8f100ccc8e2fc0f5f74afe37e3960114d808827 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Fri, 19 Jan 2024 16:33:40 +0100 Subject: [PATCH 041/127] Remove default value of RoomSummaryDetails constructor, and iterate on fixture functions. --- .../impl/InviteListPresenterTests.kt | 8 ++-- ...DefaultNotificationSettingStateProvider.kt | 6 +-- .../matrix/api/roomlist/RoomSummary.kt | 10 ++--- .../matrix/test/room/RoomSummaryFixture.kt | 11 ++++- .../matrix/ui/components/SelectedRoom.kt | 40 ++++++++++++++----- .../impl/RoomSelectStateProvider.kt | 29 ++------------ 6 files changed, 56 insertions(+), 48 deletions(-) diff --git a/features/invitelist/impl/src/test/kotlin/io/element/android/features/invitelist/impl/InviteListPresenterTests.kt b/features/invitelist/impl/src/test/kotlin/io/element/android/features/invitelist/impl/InviteListPresenterTests.kt index 9ba0181e45..a841b21c56 100644 --- a/features/invitelist/impl/src/test/kotlin/io/element/android/features/invitelist/impl/InviteListPresenterTests.kt +++ b/features/invitelist/impl/src/test/kotlin/io/element/android/features/invitelist/impl/InviteListPresenterTests.kt @@ -30,7 +30,6 @@ import io.element.android.libraries.matrix.api.core.RoomId import io.element.android.libraries.matrix.api.room.RoomMember import io.element.android.libraries.matrix.api.room.RoomMembershipState import io.element.android.libraries.matrix.api.roomlist.RoomSummary -import io.element.android.libraries.matrix.api.roomlist.RoomSummaryDetails import io.element.android.libraries.matrix.test.AN_AVATAR_URL import io.element.android.libraries.matrix.test.A_ROOM_ID import io.element.android.libraries.matrix.test.A_ROOM_ID_2 @@ -39,6 +38,7 @@ import io.element.android.libraries.matrix.test.A_USER_ID import io.element.android.libraries.matrix.test.A_USER_NAME import io.element.android.libraries.matrix.test.FakeMatrixClient import io.element.android.libraries.matrix.test.room.FakeMatrixRoom +import io.element.android.libraries.matrix.test.room.aRoomSummaryDetails import io.element.android.libraries.matrix.test.roomlist.FakeRoomListService import io.element.android.libraries.push.api.notifications.NotificationDrawerManager import io.element.android.libraries.push.test.notifications.FakeNotificationDrawerManager @@ -425,7 +425,7 @@ class InviteListPresenterTests { postInviteRooms( listOf( RoomSummary.Filled( - RoomSummaryDetails( + aRoomSummaryDetails( roomId = A_ROOM_ID, name = A_ROOM_NAME, avatarUrl = null, @@ -453,7 +453,7 @@ class InviteListPresenterTests { postInviteRooms( listOf( RoomSummary.Filled( - RoomSummaryDetails( + aRoomSummaryDetails( roomId = A_ROOM_ID, name = A_ROOM_NAME, avatarUrl = null, @@ -478,7 +478,7 @@ class InviteListPresenterTests { } private fun aRoomSummary(id: RoomId = A_ROOM_ID) = RoomSummary.Filled( - RoomSummaryDetails( + aRoomSummaryDetails( roomId = id, name = A_ROOM_NAME, avatarUrl = null, diff --git a/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/notifications/edit/EditDefaultNotificationSettingStateProvider.kt b/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/notifications/edit/EditDefaultNotificationSettingStateProvider.kt index a2571293e9..3c7df8fc52 100644 --- a/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/notifications/edit/EditDefaultNotificationSettingStateProvider.kt +++ b/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/notifications/edit/EditDefaultNotificationSettingStateProvider.kt @@ -21,7 +21,7 @@ import io.element.android.libraries.architecture.AsyncAction import io.element.android.libraries.matrix.api.core.RoomId import io.element.android.libraries.matrix.api.room.RoomNotificationMode import io.element.android.libraries.matrix.api.roomlist.RoomSummary -import io.element.android.libraries.matrix.api.roomlist.RoomSummaryDetails +import io.element.android.libraries.matrix.ui.components.aRoomSummaryDetails import kotlinx.collections.immutable.persistentListOf open class EditDefaultNotificationSettingStateProvider : PreviewParameterProvider { @@ -49,13 +49,13 @@ private fun anEditDefaultNotificationSettingsState( ) private fun aRoomSummary() = RoomSummary.Filled( - RoomSummaryDetails( + aRoomSummaryDetails( roomId = RoomId("!roomId:domain"), name = "Room", avatarUrl = null, isDirect = false, lastMessage = null, unreadNotificationCount = 0, - userDefinedNotificationMode = RoomNotificationMode.MENTIONS_AND_KEYWORDS_ONLY, + notificationMode = RoomNotificationMode.MENTIONS_AND_KEYWORDS_ONLY, ) ) diff --git a/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/roomlist/RoomSummary.kt b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/roomlist/RoomSummary.kt index 719452cc16..6c43ee1fef 100644 --- a/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/roomlist/RoomSummary.kt +++ b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/roomlist/RoomSummary.kt @@ -36,15 +36,15 @@ sealed interface RoomSummary { data class RoomSummaryDetails( val roomId: RoomId, val name: String, - val canonicalAlias: String? = null, + val canonicalAlias: String?, val isDirect: Boolean, val avatarUrl: String?, val lastMessage: RoomMessage?, val unreadNotificationCount: Int, - val inviter: RoomMember? = null, - val userDefinedNotificationMode: RoomNotificationMode? = null, - val hasRoomCall: Boolean = false, - val isDm: Boolean = false, + val inviter: RoomMember?, + val userDefinedNotificationMode: RoomNotificationMode?, + val hasRoomCall: Boolean, + val isDm: Boolean, ) { val lastMessageTimestamp = lastMessage?.originServerTs } diff --git a/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/room/RoomSummaryFixture.kt b/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/room/RoomSummaryFixture.kt index ae552457e9..a0a69bfe7b 100644 --- a/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/room/RoomSummaryFixture.kt +++ b/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/room/RoomSummaryFixture.kt @@ -19,6 +19,7 @@ package io.element.android.libraries.matrix.test.room import io.element.android.libraries.matrix.api.core.EventId import io.element.android.libraries.matrix.api.core.RoomId import io.element.android.libraries.matrix.api.core.UserId +import io.element.android.libraries.matrix.api.room.RoomMember import io.element.android.libraries.matrix.api.room.RoomNotificationMode import io.element.android.libraries.matrix.api.room.message.RoomMessage import io.element.android.libraries.matrix.api.roomlist.RoomSummary @@ -58,6 +59,10 @@ fun aRoomSummaryDetails( lastMessage: RoomMessage? = aRoomMessage(), unreadNotificationCount: Int = 2, notificationMode: RoomNotificationMode? = null, + inviter: RoomMember? = null, + canonicalAlias: String? = null, + hasRoomCall: Boolean = false, + isDm: Boolean = false, ) = RoomSummaryDetails( roomId = roomId, name = name, @@ -65,7 +70,11 @@ fun aRoomSummaryDetails( avatarUrl = avatarUrl, lastMessage = lastMessage, unreadNotificationCount = unreadNotificationCount, - userDefinedNotificationMode = notificationMode + userDefinedNotificationMode = notificationMode, + inviter = inviter, + canonicalAlias = canonicalAlias, + hasRoomCall = hasRoomCall, + isDm = isDm, ) fun aRoomMessage( diff --git a/libraries/matrixui/src/main/kotlin/io/element/android/libraries/matrix/ui/components/SelectedRoom.kt b/libraries/matrixui/src/main/kotlin/io/element/android/libraries/matrix/ui/components/SelectedRoom.kt index 8d603f54eb..c47fdbdf64 100644 --- a/libraries/matrixui/src/main/kotlin/io/element/android/libraries/matrix/ui/components/SelectedRoom.kt +++ b/libraries/matrixui/src/main/kotlin/io/element/android/libraries/matrix/ui/components/SelectedRoom.kt @@ -44,6 +44,9 @@ import io.element.android.libraries.designsystem.theme.components.Icon import io.element.android.libraries.designsystem.theme.components.Surface import io.element.android.libraries.designsystem.theme.components.Text import io.element.android.libraries.matrix.api.core.RoomId +import io.element.android.libraries.matrix.api.room.RoomMember +import io.element.android.libraries.matrix.api.room.RoomNotificationMode +import io.element.android.libraries.matrix.api.room.message.RoomMessage import io.element.android.libraries.matrix.api.roomlist.RoomSummaryDetails import io.element.android.libraries.ui.strings.CommonStrings @@ -94,16 +97,33 @@ fun SelectedRoom( @Composable internal fun SelectedRoomPreview() = ElementPreview { SelectedRoom( - roomSummary = RoomSummaryDetails( - roomId = RoomId("!room:domain"), - name = "roomName", - canonicalAlias = null, - isDirect = true, - avatarUrl = null, - lastMessage = null, - unreadNotificationCount = 0, - inviter = null, - ), + roomSummary = aRoomSummaryDetails(), onRoomRemoved = {}, ) } + +fun aRoomSummaryDetails( + roomId: RoomId = RoomId("!room:domain"), + name: String = "roomName", + canonicalAlias: String? = null, + isDirect: Boolean = true, + avatarUrl: String? = null, + lastMessage: RoomMessage? = null, + inviter: RoomMember? = null, + notificationMode: RoomNotificationMode? = null, + hasRoomCall: Boolean = false, + isDm: Boolean = false, + unreadNotificationCount: Int = 0 +) = RoomSummaryDetails( + roomId = roomId, + name = name, + canonicalAlias = canonicalAlias, + isDirect = isDirect, + avatarUrl = avatarUrl, + lastMessage = lastMessage, + inviter = inviter, + userDefinedNotificationMode = notificationMode, + hasRoomCall = hasRoomCall, + isDm = isDm, + unreadNotificationCount = unreadNotificationCount, +) diff --git a/libraries/roomselect/impl/src/main/kotlin/io/element/android/libraries/roomselect/impl/RoomSelectStateProvider.kt b/libraries/roomselect/impl/src/main/kotlin/io/element/android/libraries/roomselect/impl/RoomSelectStateProvider.kt index afa056fb21..ecd13338ca 100644 --- a/libraries/roomselect/impl/src/main/kotlin/io/element/android/libraries/roomselect/impl/RoomSelectStateProvider.kt +++ b/libraries/roomselect/impl/src/main/kotlin/io/element/android/libraries/roomselect/impl/RoomSelectStateProvider.kt @@ -19,9 +19,8 @@ package io.element.android.libraries.roomselect.impl import androidx.compose.ui.tooling.preview.PreviewParameterProvider import io.element.android.libraries.designsystem.theme.components.SearchBarResultState import io.element.android.libraries.matrix.api.core.RoomId -import io.element.android.libraries.matrix.api.room.RoomMember -import io.element.android.libraries.matrix.api.room.message.RoomMessage import io.element.android.libraries.matrix.api.roomlist.RoomSummaryDetails +import io.element.android.libraries.matrix.ui.components.aRoomSummaryDetails import io.element.android.libraries.roomselect.api.RoomSelectMode import kotlinx.collections.immutable.ImmutableList import kotlinx.collections.immutable.persistentListOf @@ -41,7 +40,7 @@ open class RoomSelectStateProvider : PreviewParameterProvider { resultState = SearchBarResultState.Results(aForwardMessagesRoomList()), query = "Test", isSearchActive = true, - selectedRooms = persistentListOf(aRoomDetailsState(roomId = RoomId("!room2:domain"))) + selectedRooms = persistentListOf(aRoomSummaryDetails(roomId = RoomId("!room2:domain"))) ), // Add other states here ) @@ -62,30 +61,10 @@ private fun aRoomSelectState( ) private fun aForwardMessagesRoomList() = persistentListOf( - aRoomDetailsState(), - aRoomDetailsState( + aRoomSummaryDetails(), + aRoomSummaryDetails( roomId = RoomId("!room2:domain"), name = "Room with alias", canonicalAlias = "#alias:example.org", ), ) - -private fun aRoomDetailsState( - roomId: RoomId = RoomId("!room:domain"), - name: String = "roomName", - canonicalAlias: String? = null, - isDirect: Boolean = true, - avatarUrl: String? = null, - lastMessage: RoomMessage? = null, - unreadNotificationCount: Int = 0, - inviter: RoomMember? = null, -) = RoomSummaryDetails( - roomId = roomId, - name = name, - canonicalAlias = canonicalAlias, - isDirect = isDirect, - avatarUrl = avatarUrl, - lastMessage = lastMessage, - unreadNotificationCount = unreadNotificationCount, - inviter = inviter, -) From 9d586bf2bb3e76e523035f29ce45635b124419d8 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Fri, 19 Jan 2024 16:51:05 +0100 Subject: [PATCH 042/127] Improve aRoomListRoomSummary method. --- .../impl/model/RoomListRoomSummaryProvider.kt | 38 ++++++++++++------- 1 file changed, 24 insertions(+), 14 deletions(-) diff --git a/features/roomlist/impl/src/main/kotlin/io/element/android/features/roomlist/impl/model/RoomListRoomSummaryProvider.kt b/features/roomlist/impl/src/main/kotlin/io/element/android/features/roomlist/impl/model/RoomListRoomSummaryProvider.kt index 2d2233c2a0..cd7d4ac5f9 100644 --- a/features/roomlist/impl/src/main/kotlin/io/element/android/features/roomlist/impl/model/RoomListRoomSummaryProvider.kt +++ b/features/roomlist/impl/src/main/kotlin/io/element/android/features/roomlist/impl/model/RoomListRoomSummaryProvider.kt @@ -26,13 +26,13 @@ open class RoomListRoomSummaryProvider : PreviewParameterProvider get() = sequenceOf( aRoomListRoomSummary(), - aRoomListRoomSummary().copy(lastMessage = null), - aRoomListRoomSummary().copy(hasUnread = true, userDefinedNotificationMode = RoomNotificationMode.MENTIONS_AND_KEYWORDS_ONLY), - aRoomListRoomSummary().copy(timestamp = "88:88", userDefinedNotificationMode = RoomNotificationMode.MENTIONS_AND_KEYWORDS_ONLY), - aRoomListRoomSummary().copy(timestamp = "88:88", userDefinedNotificationMode = RoomNotificationMode.MUTE), - aRoomListRoomSummary().copy(timestamp = "88:88", hasUnread = true), - aRoomListRoomSummary().copy(isPlaceholder = true, timestamp = "88:88"), - aRoomListRoomSummary().copy( + aRoomListRoomSummary(lastMessage = null), + aRoomListRoomSummary(hasUnread = true, notificationMode = RoomNotificationMode.MENTIONS_AND_KEYWORDS_ONLY), + aRoomListRoomSummary(timestamp = "88:88", notificationMode = RoomNotificationMode.MENTIONS_AND_KEYWORDS_ONLY), + aRoomListRoomSummary(timestamp = "88:88", notificationMode = RoomNotificationMode.MUTE), + aRoomListRoomSummary(timestamp = "88:88", hasUnread = true), + aRoomListRoomSummary(isPlaceholder = true, timestamp = "88:88"), + aRoomListRoomSummary( name = "A very long room name that should be truncated", lastMessage = "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt" + " ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea com" + @@ -40,17 +40,27 @@ open class RoomListRoomSummaryProvider : PreviewParameterProvider Date: Fri, 19 Jan 2024 17:34:06 +0100 Subject: [PATCH 043/127] Make the room settings screen update automatically (#2197) * Make the room settings screen update automatically --- changelog.d/921.bugfix | 1 + .../roomdetails/impl/RoomDetailsPresenter.kt | 14 +++++++--- .../roomdetails/RoomDetailsPresenterTests.kt | 26 +++++++++++++++++-- .../matrix/test/room/FakeMatrixRoom.kt | 2 +- 4 files changed, 36 insertions(+), 7 deletions(-) create mode 100644 changelog.d/921.bugfix diff --git a/changelog.d/921.bugfix b/changelog.d/921.bugfix new file mode 100644 index 0000000000..939455b177 --- /dev/null +++ b/changelog.d/921.bugfix @@ -0,0 +1 @@ +Make the room settings screen update automatically when new room info (name, avatar, topic) is available. diff --git a/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/RoomDetailsPresenter.kt b/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/RoomDetailsPresenter.kt index e9aebe104b..c832cab666 100644 --- a/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/RoomDetailsPresenter.kt +++ b/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/RoomDetailsPresenter.kt @@ -63,6 +63,12 @@ class RoomDetailsPresenter @Inject constructor( val scope = rememberCoroutineScope() val leaveRoomState = leaveRoomPresenter.present() val canShowNotificationSettings = remember { mutableStateOf(false) } + val roomInfo = room.roomInfoFlow.collectAsState(initial = null).value + + val roomAvatar by remember { derivedStateOf { roomInfo?.avatarUrl ?: room.avatarUrl } } + + val roomName by remember { derivedStateOf { (roomInfo?.name ?: room.name ?: room.displayName).trim() } } + val roomTopic by remember { derivedStateOf { roomInfo?.topic ?: room.topic } } LaunchedEffect(Unit) { canShowNotificationSettings.value = featureFlagService.isFeatureEnabled(FeatureFlags.NotificationSettings) @@ -82,8 +88,8 @@ class RoomDetailsPresenter @Inject constructor( val roomMemberDetailsPresenter = roomMemberDetailsPresenter(dmMember) val roomType by getRoomType(dmMember) - val topicState = remember(canEditTopic, room.topic, roomType) { - val topic = room.topic + val topicState = remember(canEditTopic, roomTopic, roomType) { + val topic = roomTopic when { !topic.isNullOrBlank() -> RoomTopicState.ExistingTopic(topic) @@ -115,9 +121,9 @@ class RoomDetailsPresenter @Inject constructor( return RoomDetailsState( roomId = room.roomId.value, - roomName = room.displayName, + roomName = roomName, roomAlias = room.alias, - roomAvatarUrl = room.avatarUrl, + roomAvatarUrl = roomAvatar, roomTopic = topicState, memberCount = room.joinedMemberCount, isEncrypted = room.isEncrypted, diff --git a/features/roomdetails/impl/src/test/kotlin/io/element/android/features/roomdetails/RoomDetailsPresenterTests.kt b/features/roomdetails/impl/src/test/kotlin/io/element/android/features/roomdetails/RoomDetailsPresenterTests.kt index 0a25434339..95deffad31 100644 --- a/features/roomdetails/impl/src/test/kotlin/io/element/android/features/roomdetails/RoomDetailsPresenterTests.kt +++ b/features/roomdetails/impl/src/test/kotlin/io/element/android/features/roomdetails/RoomDetailsPresenterTests.kt @@ -46,6 +46,7 @@ import io.element.android.libraries.matrix.test.A_USER_ID_2 import io.element.android.libraries.matrix.test.FakeMatrixClient import io.element.android.libraries.matrix.test.notificationsettings.FakeNotificationSettingsService import io.element.android.libraries.matrix.test.room.FakeMatrixRoom +import io.element.android.libraries.matrix.test.room.aRoomInfo import io.element.android.tests.testutils.WarmUpRule import io.element.android.tests.testutils.consumeItemsUntilPredicate import io.element.android.tests.testutils.testCoroutineDispatchers @@ -89,7 +90,7 @@ class RoomDetailsPresenterTests { } @Test - fun `present - initial state is created from room info`() = runTest { + fun `present - initial state is created from room if roomInfo is null`() = runTest { val room = aMatrixRoom() val presenter = createRoomDetailsPresenter(room) moleculeFlow(RecompositionMode.Immediate) { @@ -97,7 +98,7 @@ class RoomDetailsPresenterTests { }.test { val initialState = awaitItem() assertThat(initialState.roomId).isEqualTo(room.roomId.value) - assertThat(initialState.roomName).isEqualTo(room.displayName) + assertThat(initialState.roomName).isEqualTo(room.name) assertThat(initialState.roomAvatarUrl).isEqualTo(room.avatarUrl) assertThat(initialState.roomTopic).isEqualTo(RoomTopicState.ExistingTopic(room.topic!!)) assertThat(initialState.memberCount).isEqualTo(room.joinedMemberCount) @@ -107,6 +108,26 @@ class RoomDetailsPresenterTests { } } + @Test + fun `present - initial state is updated with roomInfo if it exists`() = runTest { + val roomInfo = aRoomInfo(name = "A room name", topic = "A topic", avatarUrl = "https://matrix.org/avatar.jpg") + val room = aMatrixRoom().apply { + givenRoomInfo(roomInfo) + } + val presenter = createRoomDetailsPresenter(room) + moleculeFlow(RecompositionMode.Immediate) { + presenter.present() + }.test { + skipItems(1) + val updatedState = awaitItem() + assertThat(updatedState.roomName).isEqualTo(roomInfo.name) + assertThat(updatedState.roomAvatarUrl).isEqualTo(roomInfo.avatarUrl) + assertThat(updatedState.roomTopic).isEqualTo(RoomTopicState.ExistingTopic(roomInfo.topic!!)) + + cancelAndIgnoreRemainingEvents() + } + } + @Test fun `present - initial state with no room name`() = runTest { val room = aMatrixRoom(name = null) @@ -334,6 +355,7 @@ class RoomDetailsPresenterTests { val room = aMatrixRoom(topic = null).apply { givenCanSendStateResult(StateEventType.ROOM_TOPIC, Result.success(true)) givenCanInviteResult(Result.success(false)) + givenRoomInfo(aRoomInfo(topic = null)) } val presenter = createRoomDetailsPresenter(room) diff --git a/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/room/FakeMatrixRoom.kt b/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/room/FakeMatrixRoom.kt index 9c12ba1f4f..b4e0001e84 100644 --- a/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/room/FakeMatrixRoom.kt +++ b/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/room/FakeMatrixRoom.kt @@ -161,7 +161,7 @@ class FakeMatrixRoom( private var leaveRoomError: Throwable? = null - private val _roomInfoFlow: MutableSharedFlow = MutableStateFlow(aRoomInfo()) + private val _roomInfoFlow: MutableSharedFlow = MutableSharedFlow(replay = 1) override val roomInfoFlow: Flow = _roomInfoFlow override val membersStateFlow: MutableStateFlow = MutableStateFlow(MatrixRoomMembersState.Unknown) From 5d462d5ba93071f9bfba7340e0dc0d1791b2a9ff Mon Sep 17 00:00:00 2001 From: Jorge Martin Espinosa Date: Fri, 19 Jan 2024 17:34:27 +0100 Subject: [PATCH 044/127] Remove some state events at the start of DMs (#2252) * Remove some initial events for DMs --- changelog.d/2217.misc | 1 + .../messages/impl/timeline/TimelineView.kt | 2 +- .../impl/timeline/RustMatrixTimeline.kt | 10 ++ .../DmBeginningTimelineProcessor.kt | 61 +++++++++++ .../DmBeginningTimelineProcessorTest.kt | 102 ++++++++++++++++++ 5 files changed, 175 insertions(+), 1 deletion(-) create mode 100644 changelog.d/2217.misc create mode 100644 libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/timeline/postprocessor/DmBeginningTimelineProcessor.kt create mode 100644 libraries/matrix/impl/src/test/kotlin/io/element/android/libraries/matrix/impl/timeline/postprocessor/DmBeginningTimelineProcessorTest.kt diff --git a/changelog.d/2217.misc b/changelog.d/2217.misc new file mode 100644 index 0000000000..40d4bd7fc6 --- /dev/null +++ b/changelog.d/2217.misc @@ -0,0 +1 @@ +Remove room creation, self-join of room creator and 'this is the beginning of X' timeline items for DMs. diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/TimelineView.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/TimelineView.kt index 4f686e594b..d2ab635e6a 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/TimelineView.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/TimelineView.kt @@ -145,7 +145,7 @@ fun TimelineView( } } } - if (state.paginationState.beginningOfRoomReached) { + if (state.paginationState.beginningOfRoomReached && !state.timelineRoomInfo.isDirect) { item(contentType = "BeginningOfRoomReached") { TimelineItemRoomBeginningView(roomName = roomName) } diff --git a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/timeline/RustMatrixTimeline.kt b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/timeline/RustMatrixTimeline.kt index f33e0606e7..7b1e7d0500 100644 --- a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/timeline/RustMatrixTimeline.kt +++ b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/timeline/RustMatrixTimeline.kt @@ -27,6 +27,7 @@ import io.element.android.libraries.matrix.impl.timeline.item.event.EventMessage import io.element.android.libraries.matrix.impl.timeline.item.event.EventTimelineItemMapper import io.element.android.libraries.matrix.impl.timeline.item.event.TimelineEventContentMapper import io.element.android.libraries.matrix.impl.timeline.item.virtual.VirtualTimelineItemMapper +import io.element.android.libraries.matrix.impl.timeline.postprocessor.DmBeginningTimelineProcessor import io.element.android.libraries.matrix.impl.timeline.postprocessor.FilterHiddenStateEventsProcessor import io.element.android.libraries.matrix.impl.timeline.postprocessor.TimelineEncryptedHistoryPostProcessor import kotlinx.coroutines.CompletableDeferred @@ -85,6 +86,8 @@ class RustMatrixTimeline( private val filterHiddenStateEventsProcessor = FilterHiddenStateEventsProcessor() + private val dmBeginningTimelineProcessor = DmBeginningTimelineProcessor() + private val timelineItemFactory = MatrixTimelineItemMapper( fetchDetailsForEvent = this::fetchDetailsForEvent, roomCoroutineScope = roomCoroutineScope, @@ -107,6 +110,13 @@ class RustMatrixTimeline( override val timelineItems: Flow> = _timelineItems .mapLatest { items -> encryptedHistoryPostProcessor.process(items) } .mapLatest { items -> filterHiddenStateEventsProcessor.process(items) } + .mapLatest { items -> + dmBeginningTimelineProcessor.process( + items = items, + isDm = matrixRoom.isDirect && matrixRoom.isOneToOne, + isAtStartOfTimeline = paginationState.value.beginningOfRoomReached + ) + } init { Timber.d("Initialize timeline for room ${matrixRoom.roomId}") diff --git a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/timeline/postprocessor/DmBeginningTimelineProcessor.kt b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/timeline/postprocessor/DmBeginningTimelineProcessor.kt new file mode 100644 index 0000000000..f36b4a78b8 --- /dev/null +++ b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/timeline/postprocessor/DmBeginningTimelineProcessor.kt @@ -0,0 +1,61 @@ +/* + * 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 io.element.android.libraries.matrix.impl.timeline.postprocessor + +import io.element.android.libraries.matrix.api.timeline.MatrixTimelineItem +import io.element.android.libraries.matrix.api.timeline.item.event.MembershipChange +import io.element.android.libraries.matrix.api.timeline.item.event.OtherState +import io.element.android.libraries.matrix.api.timeline.item.event.RoomMembershipContent +import io.element.android.libraries.matrix.api.timeline.item.event.StateContent + +/** + * This timeline post-processor removes the room creation event and the self-join event from the timeline for DMs. + */ +class DmBeginningTimelineProcessor { + fun process( + items: List, + isDm: Boolean, + isAtStartOfTimeline: Boolean + ): List { + if (!isDm || !isAtStartOfTimeline) return items + + // Find room creation event. This is usually index 0 + val roomCreationEventIndex = items.indexOfFirst { + val stateEventContent = (it as? MatrixTimelineItem.Event)?.event?.content as? StateContent + stateEventContent?.content is OtherState.RoomCreate + } + + // Find self-join event for room creator. This is usually index 1 + val roomCreatorUserId = (items.getOrNull(roomCreationEventIndex) as? MatrixTimelineItem.Event)?.event?.sender + val selfUserJoinedEventIndex = roomCreatorUserId?.let { creatorUserId -> + items.indexOfFirst { + val stateEventContent = (it as? MatrixTimelineItem.Event)?.event?.content as? RoomMembershipContent + stateEventContent?.change == MembershipChange.JOINED && stateEventContent.userId == creatorUserId + } + } ?: -1 + + // Remove items at the indices we found + val newItems = items.toMutableList() + if (selfUserJoinedEventIndex in newItems.indices) { + newItems.removeAt(selfUserJoinedEventIndex) + } + if (roomCreationEventIndex in newItems.indices) { + newItems.removeAt(roomCreationEventIndex) + } + return newItems + } +} diff --git a/libraries/matrix/impl/src/test/kotlin/io/element/android/libraries/matrix/impl/timeline/postprocessor/DmBeginningTimelineProcessorTest.kt b/libraries/matrix/impl/src/test/kotlin/io/element/android/libraries/matrix/impl/timeline/postprocessor/DmBeginningTimelineProcessorTest.kt new file mode 100644 index 0000000000..fc24f54c14 --- /dev/null +++ b/libraries/matrix/impl/src/test/kotlin/io/element/android/libraries/matrix/impl/timeline/postprocessor/DmBeginningTimelineProcessorTest.kt @@ -0,0 +1,102 @@ +/* + * 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 io.element.android.libraries.matrix.impl.timeline.postprocessor + +import com.google.common.truth.Truth.assertThat +import io.element.android.libraries.matrix.api.timeline.MatrixTimelineItem +import io.element.android.libraries.matrix.api.timeline.item.event.MembershipChange +import io.element.android.libraries.matrix.api.timeline.item.event.OtherState +import io.element.android.libraries.matrix.api.timeline.item.event.RoomMembershipContent +import io.element.android.libraries.matrix.api.timeline.item.event.StateContent +import io.element.android.libraries.matrix.test.A_USER_ID +import io.element.android.libraries.matrix.test.A_USER_ID_2 +import io.element.android.libraries.matrix.test.timeline.aMessageContent +import io.element.android.libraries.matrix.test.timeline.anEventTimelineItem +import org.junit.Test + +class DmBeginningTimelineProcessorTest { + @Test + fun `processor removes room creation event and self-join event from DM timeline`() { + val timelineItems = listOf( + MatrixTimelineItem.Event("m.room.create", anEventTimelineItem(sender = A_USER_ID, content = StateContent("", OtherState.RoomCreate))), + MatrixTimelineItem.Event("m.room.member", anEventTimelineItem(content = RoomMembershipContent(A_USER_ID, MembershipChange.JOINED))), + ) + val processor = DmBeginningTimelineProcessor() + val processedItems = processor.process(timelineItems, isDm = true, isAtStartOfTimeline = true) + assertThat(processedItems).isEmpty() + } + + @Test + fun `processor removes room creation event and self-join event from DM timeline even if they're not the first items`() { + val timelineItems = listOf( + MatrixTimelineItem.Event("m.room.member_other", anEventTimelineItem(content = RoomMembershipContent(A_USER_ID_2, MembershipChange.JOINED))), + MatrixTimelineItem.Event("m.room.create", anEventTimelineItem(sender = A_USER_ID, content = StateContent("", OtherState.RoomCreate))), + MatrixTimelineItem.Event("m.room.message", anEventTimelineItem(content = aMessageContent("hi"))), + MatrixTimelineItem.Event("m.room.member", anEventTimelineItem(content = RoomMembershipContent(A_USER_ID, MembershipChange.JOINED))), + ) + val expected = listOf( + MatrixTimelineItem.Event("m.room.member_other", anEventTimelineItem(content = RoomMembershipContent(A_USER_ID_2, MembershipChange.JOINED))), + MatrixTimelineItem.Event("m.room.message", anEventTimelineItem(content = aMessageContent("hi"))), + ) + val processor = DmBeginningTimelineProcessor() + val processedItems = processor.process(timelineItems, isDm = true, isAtStartOfTimeline = true) + assertThat(processedItems).isEqualTo(expected) + } + + @Test + fun `processor won't remove items if it's not a DM`() { + val timelineItems = listOf( + MatrixTimelineItem.Event("m.room.create", anEventTimelineItem(sender = A_USER_ID, content = StateContent("", OtherState.RoomCreate))), + MatrixTimelineItem.Event("m.room.member", anEventTimelineItem(content = RoomMembershipContent(A_USER_ID, MembershipChange.JOINED))), + ) + val processor = DmBeginningTimelineProcessor() + val processedItems = processor.process(timelineItems, isDm = false, isAtStartOfTimeline = true) + assertThat(processedItems).isEqualTo(timelineItems) + } + + @Test + fun `processor won't remove items if it's not at the start of the timeline`() { + val timelineItems = listOf( + MatrixTimelineItem.Event("m.room.create", anEventTimelineItem(sender = A_USER_ID, content = StateContent("", OtherState.RoomCreate))), + MatrixTimelineItem.Event("m.room.member", anEventTimelineItem(content = RoomMembershipContent(A_USER_ID, MembershipChange.JOINED))), + ) + val processor = DmBeginningTimelineProcessor() + val processedItems = processor.process(timelineItems, isDm = true, isAtStartOfTimeline = false) + assertThat(processedItems).isEqualTo(timelineItems) + } + + @Test + fun `processor won't remove the first member join event if it can't find the room creation event`() { + val timelineItems = listOf( + MatrixTimelineItem.Event("m.room.member", anEventTimelineItem(content = RoomMembershipContent(A_USER_ID, MembershipChange.JOINED))), + ) + val processor = DmBeginningTimelineProcessor() + val processedItems = processor.process(timelineItems, isDm = true, isAtStartOfTimeline = false) + assertThat(processedItems).isEqualTo(timelineItems) + } + + @Test + fun `processor won't remove the first member join event if it's not from the room creator`() { + val timelineItems = listOf( + MatrixTimelineItem.Event("m.room.create", anEventTimelineItem(sender = A_USER_ID, content = StateContent("", OtherState.RoomCreate))), + MatrixTimelineItem.Event("m.room.member", anEventTimelineItem(content = RoomMembershipContent(A_USER_ID_2, MembershipChange.JOINED))), + ) + val processor = DmBeginningTimelineProcessor() + val processedItems = processor.process(timelineItems, isDm = true, isAtStartOfTimeline = false) + assertThat(processedItems).isEqualTo(timelineItems) + } +} From cf6bcca9cd1a991771124c5d5502c6dd7c78ec66 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Fri, 19 Jan 2024 17:59:18 +0100 Subject: [PATCH 045/127] Preview with a last message by default. --- .../features/roomlist/impl/model/RoomListRoomSummaryProvider.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/features/roomlist/impl/src/main/kotlin/io/element/android/features/roomlist/impl/model/RoomListRoomSummaryProvider.kt b/features/roomlist/impl/src/main/kotlin/io/element/android/features/roomlist/impl/model/RoomListRoomSummaryProvider.kt index cd7d4ac5f9..8390bd03d7 100644 --- a/features/roomlist/impl/src/main/kotlin/io/element/android/features/roomlist/impl/model/RoomListRoomSummaryProvider.kt +++ b/features/roomlist/impl/src/main/kotlin/io/element/android/features/roomlist/impl/model/RoomListRoomSummaryProvider.kt @@ -45,7 +45,7 @@ open class RoomListRoomSummaryProvider : PreviewParameterProvider Date: Fri, 19 Jan 2024 20:13:41 +0000 Subject: [PATCH 046/127] Update screenshots --- ...ow_null_RoomSummaryRow-Day-9_10_null_0,NEXUS_5,1.0,en].png | 4 ++-- ...ow_null_RoomSummaryRow-Day-9_10_null_1,NEXUS_5,1.0,en].png | 4 ++-- ...ow_null_RoomSummaryRow-Day-9_10_null_2,NEXUS_5,1.0,en].png | 4 ++-- ...ow_null_RoomSummaryRow-Day-9_10_null_8,NEXUS_5,1.0,en].png | 4 ++-- ..._null_RoomSummaryRow-Night-9_11_null_0,NEXUS_5,1.0,en].png | 4 ++-- ..._null_RoomSummaryRow-Night-9_11_null_1,NEXUS_5,1.0,en].png | 4 ++-- ..._null_RoomSummaryRow-Night-9_11_null_2,NEXUS_5,1.0,en].png | 4 ++-- ..._null_RoomSummaryRow-Night-9_11_null_8,NEXUS_5,1.0,en].png | 4 ++-- 8 files changed, 16 insertions(+), 16 deletions(-) diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Day-9_10_null_0,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Day-9_10_null_0,NEXUS_5,1.0,en].png index d80e1cc282..040f9a72b8 100644 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Day-9_10_null_0,NEXUS_5,1.0,en].png +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Day-9_10_null_0,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:fde0cc6b7268856b611db66b66b22c51df155f605988fc54f5c7ba18e5f1f713 -size 11456 +oid sha256:cf71e045231208529eb524abce7b246a0ac6283c422f9695d560071fda7085f2 +size 12820 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Day-9_10_null_1,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Day-9_10_null_1,NEXUS_5,1.0,en].png index 73ca4a2eb7..a83f9527ef 100644 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Day-9_10_null_1,NEXUS_5,1.0,en].png +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Day-9_10_null_1,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:ca1cb753204502aa929f52e8b222b86bd845086f841fb9ff2936886e1dcea526 -size 8778 +oid sha256:34972a9257a96b4ac77edf06e5f29ebc2d8e581dcaef131ecba9730cb0f48c1c +size 10176 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Day-9_10_null_2,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Day-9_10_null_2,NEXUS_5,1.0,en].png index 35364ebadc..10d75c6a5b 100644 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Day-9_10_null_2,NEXUS_5,1.0,en].png +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Day-9_10_null_2,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:5315627c3cae4b07d3df50054d9a689148517b8fd0a0e88b160ff3f447513999 -size 12653 +oid sha256:7ef683a74c785d57190508952f18ed5c669ff32a38cbc4f5b66d02330115843b +size 14103 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Day-9_10_null_8,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Day-9_10_null_8,NEXUS_5,1.0,en].png index b1778019d8..7c302dc03f 100644 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Day-9_10_null_8,NEXUS_5,1.0,en].png +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Day-9_10_null_8,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:004de09febcc9962bdc710a258f82083ba4ebca1c2831da48db7a1c9038d2caf -size 12154 +oid sha256:9c90561dc7355b1917ebe96bebc717de14aac5c4897ef3e8dd0b2aca8c51c362 +size 13610 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Night-9_11_null_0,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Night-9_11_null_0,NEXUS_5,1.0,en].png index 774d5ad126..22cb212645 100644 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Night-9_11_null_0,NEXUS_5,1.0,en].png +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Night-9_11_null_0,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:f7d6df9f2573241ad0096a1f93fb682713b8d50ffa4808419e246997027c5d43 -size 11392 +oid sha256:7fcbdfc3e45fa0f111cc384c54c40980913e52ff755e9380fba262a4c659a5c5 +size 12715 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Night-9_11_null_1,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Night-9_11_null_1,NEXUS_5,1.0,en].png index 2920c6453f..3daf9dec9f 100644 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Night-9_11_null_1,NEXUS_5,1.0,en].png +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Night-9_11_null_1,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:5d321e5157196e32961e4915466656145299ea4768e5478151b649740c2f1594 -size 8750 +oid sha256:063d4415a254eef251f4c0f63827062259f76c0d8a1e309e64a4e7376fc04a9b +size 10101 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Night-9_11_null_2,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Night-9_11_null_2,NEXUS_5,1.0,en].png index d5bf02373d..c329163b6f 100644 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Night-9_11_null_2,NEXUS_5,1.0,en].png +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Night-9_11_null_2,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:e86ea02d990c5db670a6aa3d9c17be62dad1192d687c1dc27177758b55cece3c -size 12503 +oid sha256:fd40343c425b1c7499e72d0d4119f36d06200b54e72034f97c172e5c2dad57af +size 13756 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Night-9_11_null_8,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Night-9_11_null_8,NEXUS_5,1.0,en].png index f2441b5999..4e9d41b689 100644 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Night-9_11_null_8,NEXUS_5,1.0,en].png +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Night-9_11_null_8,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:53248c6c1d0a05b8fd08bcd35a43a6463b03b9ad808b24f59d1fa7fe5d444d4f -size 12051 +oid sha256:5efc2679fc43f952d1a41ffff7c5400baeb6f46e7faba0faef6409ea178c08de +size 13319 From 28549068aeb672027b58be255753562213fb5c96 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jorge=20Mart=C3=ADn?= Date: Sat, 20 Jan 2024 16:11:35 +0100 Subject: [PATCH 047/127] Fix nightly build in CI --- .github/workflows/nightly.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/nightly.yml b/.github/workflows/nightly.yml index b1e9dddde9..dc6aaf1249 100644 --- a/.github/workflows/nightly.yml +++ b/.github/workflows/nightly.yml @@ -33,7 +33,7 @@ jobs: yes n | towncrier build --version nightly - name: Build and upload Nightly application run: | - ./gradlew assembleNightly appDistributionUploadNightly $CI_GRADLE_ARG_PROPERTIES + ./gradlew assembleGplayNightly appDistributionUploadGplayNightly $CI_GRADLE_ARG_PROPERTIES env: ELEMENT_ANDROID_MAPTILER_API_KEY: ${{ secrets.MAPTILER_KEY }} ELEMENT_ANDROID_MAPTILER_LIGHT_MAP_ID: ${{ secrets.MAPTILER_LIGHT_MAP_ID }} From 4914c512fea297846e596fa0606cd7275ef2a11c Mon Sep 17 00:00:00 2001 From: bmarty Date: Mon, 22 Jan 2024 00:10:44 +0000 Subject: [PATCH 048/127] Sync Strings from Localazy --- features/leaveroom/api/src/main/res/values-cs/translations.xml | 1 + features/leaveroom/api/src/main/res/values-fr/translations.xml | 1 + features/leaveroom/api/src/main/res/values-ru/translations.xml | 1 + features/leaveroom/api/src/main/res/values-sk/translations.xml | 1 + features/messages/impl/src/main/res/values-fr/translations.xml | 2 +- .../roomdetails/impl/src/main/res/values-cs/translations.xml | 1 + .../roomdetails/impl/src/main/res/values-fr/translations.xml | 1 + .../roomdetails/impl/src/main/res/values-ru/translations.xml | 1 + .../roomdetails/impl/src/main/res/values-sk/translations.xml | 1 + libraries/ui-strings/src/main/res/values-cs/translations.xml | 1 + libraries/ui-strings/src/main/res/values-fr/translations.xml | 1 + libraries/ui-strings/src/main/res/values-ru/translations.xml | 1 + libraries/ui-strings/src/main/res/values-sk/translations.xml | 1 + 13 files changed, 13 insertions(+), 1 deletion(-) diff --git a/features/leaveroom/api/src/main/res/values-cs/translations.xml b/features/leaveroom/api/src/main/res/values-cs/translations.xml index 64195325c4..d3163cfbed 100644 --- a/features/leaveroom/api/src/main/res/values-cs/translations.xml +++ b/features/leaveroom/api/src/main/res/values-cs/translations.xml @@ -1,5 +1,6 @@ + "Opravdu chcete opustit tuto konverzaci? Tato konverzace není veřejná a bez pozvánky se k ní nebudete moci znovu připojit." "Opravdu chcete opustit tuto místnost? Jste tu jediná osoba. Pokud odejdete, nikdo se v budoucnu nebude moci připojit, včetně vás." "Opravdu chcete opustit tuto místnost? Tato místnost není veřejná a bez pozvánky se nebudete moci znovu připojit." "Opravdu chcete opustit místnost?" diff --git a/features/leaveroom/api/src/main/res/values-fr/translations.xml b/features/leaveroom/api/src/main/res/values-fr/translations.xml index 43ca62a678..bed2bdd365 100644 --- a/features/leaveroom/api/src/main/res/values-fr/translations.xml +++ b/features/leaveroom/api/src/main/res/values-fr/translations.xml @@ -1,5 +1,6 @@ + "Êtes-vous sûr de vouloir quitter cette discussion? Vous ne pourrez pas la rejoindre à nouveau sans y être invité." "Êtes-vous sûr de vouloir quitter ce salon ? Vous êtes la seule personne ici. Si vous partez, personne ne pourra rejoindre le salon à l’avenir, y compris vous." "Êtes-vous sûr de vouloir quitter ce salon ? Ce salon n’est pas public et vous ne pourrez pas le rejoindre sans invitation." "Êtes-vous sûr de vouloir quitter le salon ?" diff --git a/features/leaveroom/api/src/main/res/values-ru/translations.xml b/features/leaveroom/api/src/main/res/values-ru/translations.xml index 5915518c80..c6faa299a2 100644 --- a/features/leaveroom/api/src/main/res/values-ru/translations.xml +++ b/features/leaveroom/api/src/main/res/values-ru/translations.xml @@ -1,5 +1,6 @@ + "Вы уверены, что хотите покинуть беседу?" "Вы уверены, что хотите покинуть эту комнату? Вы здесь единственный человек. Если вы уйдете, никто не сможет присоединиться в будущем, включая вас." "Вы уверены, что хотите покинуть эту комнату? Эта комната не является публичной, и Вы не сможете присоединиться к ней без приглашения." "Вы уверены, что хотите покинуть комнату?" diff --git a/features/leaveroom/api/src/main/res/values-sk/translations.xml b/features/leaveroom/api/src/main/res/values-sk/translations.xml index c67cb131e7..74ff01b541 100644 --- a/features/leaveroom/api/src/main/res/values-sk/translations.xml +++ b/features/leaveroom/api/src/main/res/values-sk/translations.xml @@ -1,5 +1,6 @@ + "Ste si istí, že chcete opustiť konverzáciu?" "Ste si istí, že chcete opustiť túto miestnosť? Ste tu jediná osoba. Ak odídete, nikto sa do nej nebude môcť v budúcnosti pripojiť, vrátane vás." "Ste si istí, že chcete opustiť túto miestnosť? Táto miestnosť nie je verejná a bez pozvania sa do nej nebudete môcť vrátiť." "Ste si istí, že chcete opustiť miestnosť?" diff --git a/features/messages/impl/src/main/res/values-fr/translations.xml b/features/messages/impl/src/main/res/values-fr/translations.xml index 061cd73f41..1358ce802b 100644 --- a/features/messages/impl/src/main/res/values-fr/translations.xml +++ b/features/messages/impl/src/main/res/values-fr/translations.xml @@ -23,7 +23,7 @@ "Prendre une photo" "Enregistrer une vidéo" "Pièce jointe" - "Gallerie Photo et Vidéo" + "Galerie Photo et Vidéo" "Position" "Sondage" "Formatage du texte" diff --git a/features/roomdetails/impl/src/main/res/values-cs/translations.xml b/features/roomdetails/impl/src/main/res/values-cs/translations.xml index eddec59585..e6316cfec1 100644 --- a/features/roomdetails/impl/src/main/res/values-cs/translations.xml +++ b/features/roomdetails/impl/src/main/res/values-cs/translations.xml @@ -48,6 +48,7 @@ "Odblokovat" "Znovu uvidíte všechny zprávy od nich." "Odblokovat uživatele" + "Opustit konverzaci" "Opustit místnost" "Zabezpečení" "Téma" diff --git a/features/roomdetails/impl/src/main/res/values-fr/translations.xml b/features/roomdetails/impl/src/main/res/values-fr/translations.xml index 1611f89115..76e3ea81ec 100644 --- a/features/roomdetails/impl/src/main/res/values-fr/translations.xml +++ b/features/roomdetails/impl/src/main/res/values-fr/translations.xml @@ -47,6 +47,7 @@ "Débloquer" "Vous pourrez à nouveau voir tous ses messages." "Débloquer l’utilisateur" + "Quitter la discussion" "Quitter le salon" "Sécurité" "Sujet" diff --git a/features/roomdetails/impl/src/main/res/values-ru/translations.xml b/features/roomdetails/impl/src/main/res/values-ru/translations.xml index 9f586230b2..4412d7be4d 100644 --- a/features/roomdetails/impl/src/main/res/values-ru/translations.xml +++ b/features/roomdetails/impl/src/main/res/values-ru/translations.xml @@ -48,6 +48,7 @@ "Разблокировать" "Вы снова сможете увидеть все сообщения." "Разблокировать пользователя" + "Покинуть беседу" "Покинуть комнату" "Безопасность" "Тема" diff --git a/features/roomdetails/impl/src/main/res/values-sk/translations.xml b/features/roomdetails/impl/src/main/res/values-sk/translations.xml index 74a489c720..c9afe72b80 100644 --- a/features/roomdetails/impl/src/main/res/values-sk/translations.xml +++ b/features/roomdetails/impl/src/main/res/values-sk/translations.xml @@ -48,6 +48,7 @@ "Odblokovať" "Všetky správy od nich budete môcť opäť vidieť." "Odblokovať používateľa" + "Opustiť konverzáciu" "Opustiť miestnosť" "Bezpečnosť" "Téma" diff --git a/libraries/ui-strings/src/main/res/values-cs/translations.xml b/libraries/ui-strings/src/main/res/values-cs/translations.xml index 527ab2b866..3145967bf0 100644 --- a/libraries/ui-strings/src/main/res/values-cs/translations.xml +++ b/libraries/ui-strings/src/main/res/values-cs/translations.xml @@ -57,6 +57,7 @@ "Vstoupit" "Zjistit více" "Odejít" + "Opustit konverzaci" "Opustit místnost" "Spravovat účet" "Spravovat zařízení" diff --git a/libraries/ui-strings/src/main/res/values-fr/translations.xml b/libraries/ui-strings/src/main/res/values-fr/translations.xml index 60e4e78c2e..c56ad20a88 100644 --- a/libraries/ui-strings/src/main/res/values-fr/translations.xml +++ b/libraries/ui-strings/src/main/res/values-fr/translations.xml @@ -57,6 +57,7 @@ "Rejoindre" "En savoir plus" "Quitter" + "Quitter la discussion" "Quitter le salon" "Gérer le compte" "Gérez les sessions" diff --git a/libraries/ui-strings/src/main/res/values-ru/translations.xml b/libraries/ui-strings/src/main/res/values-ru/translations.xml index 4f035ce514..5477f03af9 100644 --- a/libraries/ui-strings/src/main/res/values-ru/translations.xml +++ b/libraries/ui-strings/src/main/res/values-ru/translations.xml @@ -57,6 +57,7 @@ "Присоединиться" "Подробнее" "Выйти" + "Покинуть беседу" "Покинуть комнату" "Настройки аккаунта" "Управление устройствами" diff --git a/libraries/ui-strings/src/main/res/values-sk/translations.xml b/libraries/ui-strings/src/main/res/values-sk/translations.xml index 29ecb56649..343bbbf3ae 100644 --- a/libraries/ui-strings/src/main/res/values-sk/translations.xml +++ b/libraries/ui-strings/src/main/res/values-sk/translations.xml @@ -57,6 +57,7 @@ "Pripojiť sa" "Zistiť viac" "Opustiť" + "Opustiť konverzáciu" "Opustiť miestnosť" "Spravovať účet" "Spravovať zariadenia" From 42c8e11707c9e85f57ae834e08cbc40eae07fb48 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 22 Jan 2024 07:54:18 +0100 Subject: [PATCH 049/127] Update dependency com.google.truth:truth to v1.3.0 (#2266) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 4e2107f302..a5be2c2cba 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -133,7 +133,7 @@ test_junitext = "androidx.test.ext:junit:1.1.5" test_mockk = "io.mockk:mockk:1.13.9" test_konsist = "com.lemonappdev:konsist:0.13.0" test_turbine = "app.cash.turbine:turbine:1.0.0" -test_truth = "com.google.truth:truth:1.2.0" +test_truth = "com.google.truth:truth:1.3.0" test_parameter_injector = "com.google.testparameterinjector:test-parameter-injector:1.15" test_robolectric = "org.robolectric:robolectric:4.11.1" test_appyx_junit = { module = "com.bumble.appyx:testing-junit4", version.ref = "appyx" } From 4924f86d3b8e38cb26ecba3227201f02211dce32 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Mon, 22 Jan 2024 10:49:19 +0100 Subject: [PATCH 050/127] Do not use the function for preview in test. --- .../android/features/roomlist/impl/RoomListPresenterTests.kt | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/features/roomlist/impl/src/test/kotlin/io/element/android/features/roomlist/impl/RoomListPresenterTests.kt b/features/roomlist/impl/src/test/kotlin/io/element/android/features/roomlist/impl/RoomListPresenterTests.kt index e4a8d91583..f4e944e96d 100644 --- a/features/roomlist/impl/src/test/kotlin/io/element/android/features/roomlist/impl/RoomListPresenterTests.kt +++ b/features/roomlist/impl/src/test/kotlin/io/element/android/features/roomlist/impl/RoomListPresenterTests.kt @@ -29,7 +29,6 @@ import io.element.android.features.roomlist.impl.datasource.FakeInviteDataSource import io.element.android.features.roomlist.impl.datasource.InviteStateDataSource import io.element.android.features.roomlist.impl.datasource.RoomListDataSource import io.element.android.features.roomlist.impl.model.RoomListRoomSummary -import io.element.android.features.roomlist.impl.model.aRoomListRoomSummary import io.element.android.libraries.dateformatter.api.LastMessageTimestampFormatter import io.element.android.libraries.dateformatter.test.FakeLastMessageTimestampFormatter import io.element.android.libraries.designsystem.components.avatar.AvatarData @@ -316,7 +315,7 @@ class RoomListPresenterTests { skipItems(1) val initialState = awaitItem() - val summary = aRoomListRoomSummary() + val summary = aRoomListRoomSummary initialState.eventSink(RoomListEvents.ShowContextMenu(summary)) val shownState = awaitItem() @@ -336,7 +335,7 @@ class RoomListPresenterTests { skipItems(1) val initialState = awaitItem() - val summary = aRoomListRoomSummary() + val summary = aRoomListRoomSummary initialState.eventSink(RoomListEvents.ShowContextMenu(summary)) val shownState = awaitItem() From 579f4d6a4e152a9b1a938fbbe02a8760c664eaa6 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Mon, 22 Jan 2024 10:59:42 +0100 Subject: [PATCH 051/127] `fun aRoomListRoomSummary`: make internal, add all fields and reorder to match RoomListRoomSummary constructor order. --- .../impl/model/RoomListRoomSummaryProvider.kt | 20 +++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/features/roomlist/impl/src/main/kotlin/io/element/android/features/roomlist/impl/model/RoomListRoomSummaryProvider.kt b/features/roomlist/impl/src/main/kotlin/io/element/android/features/roomlist/impl/model/RoomListRoomSummaryProvider.kt index 8390bd03d7..89a902f7dc 100644 --- a/features/roomlist/impl/src/main/kotlin/io/element/android/features/roomlist/impl/model/RoomListRoomSummaryProvider.kt +++ b/features/roomlist/impl/src/main/kotlin/io/element/android/features/roomlist/impl/model/RoomListRoomSummaryProvider.kt @@ -44,23 +44,27 @@ open class RoomListRoomSummaryProvider : PreviewParameterProvider Date: Mon, 22 Jan 2024 11:02:13 +0100 Subject: [PATCH 052/127] Use aRoomListRoomSummary function instead of invoking the constructor. --- .../features/roomlist/impl/RoomListStateProvider.kt | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/features/roomlist/impl/src/main/kotlin/io/element/android/features/roomlist/impl/RoomListStateProvider.kt b/features/roomlist/impl/src/main/kotlin/io/element/android/features/roomlist/impl/RoomListStateProvider.kt index bf18bc60cc..b4445dcce0 100644 --- a/features/roomlist/impl/src/main/kotlin/io/element/android/features/roomlist/impl/RoomListStateProvider.kt +++ b/features/roomlist/impl/src/main/kotlin/io/element/android/features/roomlist/impl/RoomListStateProvider.kt @@ -20,6 +20,7 @@ import androidx.compose.ui.tooling.preview.PreviewParameterProvider import io.element.android.features.leaveroom.api.aLeaveRoomState import io.element.android.features.roomlist.impl.model.RoomListRoomSummary import io.element.android.features.roomlist.impl.model.RoomListRoomSummaryPlaceholders +import io.element.android.features.roomlist.impl.model.aRoomListRoomSummary import io.element.android.libraries.designsystem.components.avatar.AvatarData import io.element.android.libraries.designsystem.components.avatar.AvatarSize import io.element.android.libraries.designsystem.utils.snackbar.SnackbarMessage @@ -71,23 +72,21 @@ internal fun aRoomListState() = RoomListState( internal fun aRoomListRoomSummaryList(): ImmutableList { return persistentListOf( - RoomListRoomSummary( + aRoomListRoomSummary( name = "Room", hasUnread = true, timestamp = "14:18", lastMessage = "A very very very very long message which suites on two lines", avatarData = AvatarData("!id", "R", size = AvatarSize.RoomListItem), id = "!roomId:domain", - roomId = RoomId("!roomId:domain") ), - RoomListRoomSummary( + aRoomListRoomSummary( name = "Room#2", hasUnread = false, timestamp = "14:16", lastMessage = "A short message", avatarData = AvatarData("!id", "Z", size = AvatarSize.RoomListItem), id = "!roomId2:domain", - roomId = RoomId("!roomId2:domain") ), RoomListRoomSummaryPlaceholders.create("!roomId2:domain"), RoomListRoomSummaryPlaceholders.create("!roomId3:domain"), From ed1112f09bcdd576252aab16d4d1d5b266f0622c Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Mon, 22 Jan 2024 11:02:45 +0100 Subject: [PATCH 053/127] Ensure roomId are unique in the list. --- .../android/features/roomlist/impl/RoomListStateProvider.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/features/roomlist/impl/src/main/kotlin/io/element/android/features/roomlist/impl/RoomListStateProvider.kt b/features/roomlist/impl/src/main/kotlin/io/element/android/features/roomlist/impl/RoomListStateProvider.kt index b4445dcce0..e1e105afeb 100644 --- a/features/roomlist/impl/src/main/kotlin/io/element/android/features/roomlist/impl/RoomListStateProvider.kt +++ b/features/roomlist/impl/src/main/kotlin/io/element/android/features/roomlist/impl/RoomListStateProvider.kt @@ -88,7 +88,7 @@ internal fun aRoomListRoomSummaryList(): ImmutableList { avatarData = AvatarData("!id", "Z", size = AvatarSize.RoomListItem), id = "!roomId2:domain", ), - RoomListRoomSummaryPlaceholders.create("!roomId2:domain"), RoomListRoomSummaryPlaceholders.create("!roomId3:domain"), + RoomListRoomSummaryPlaceholders.create("!roomId4:domain"), ) } From 8eba12593b82646805573b3a5af8398bd8914c75 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Mon, 22 Jan 2024 11:05:25 +0100 Subject: [PATCH 054/127] Ensure there is no timestamp in RoomListRoomSummary if lastMessage is null. --- .../roomlist/impl/model/RoomListRoomSummaryProvider.kt | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/features/roomlist/impl/src/main/kotlin/io/element/android/features/roomlist/impl/model/RoomListRoomSummaryProvider.kt b/features/roomlist/impl/src/main/kotlin/io/element/android/features/roomlist/impl/model/RoomListRoomSummaryProvider.kt index 89a902f7dc..e312d2bf14 100644 --- a/features/roomlist/impl/src/main/kotlin/io/element/android/features/roomlist/impl/model/RoomListRoomSummaryProvider.kt +++ b/features/roomlist/impl/src/main/kotlin/io/element/android/features/roomlist/impl/model/RoomListRoomSummaryProvider.kt @@ -28,10 +28,10 @@ open class RoomListRoomSummaryProvider : PreviewParameterProvider Date: Mon, 22 Jan 2024 11:11:44 +0100 Subject: [PATCH 055/127] Remove default value for constructor of RoomListRoomSummary. --- .../impl/datasource/RoomListDataSource.kt | 1 + .../impl/model/RoomListRoomSummary.kt | 19 +++++++++---------- .../model/RoomListRoomSummaryPlaceholders.kt | 6 +++++- .../roomlist/impl/RoomListPresenterTests.kt | 3 +++ 4 files changed, 18 insertions(+), 11 deletions(-) diff --git a/features/roomlist/impl/src/main/kotlin/io/element/android/features/roomlist/impl/datasource/RoomListDataSource.kt b/features/roomlist/impl/src/main/kotlin/io/element/android/features/roomlist/impl/datasource/RoomListDataSource.kt index 37f26e37ea..c25759ebd8 100644 --- a/features/roomlist/impl/src/main/kotlin/io/element/android/features/roomlist/impl/datasource/RoomListDataSource.kt +++ b/features/roomlist/impl/src/main/kotlin/io/element/android/features/roomlist/impl/datasource/RoomListDataSource.kt @@ -160,6 +160,7 @@ class RoomListDataSource @Inject constructor( roomLastMessageFormatter.format(message.event, roomSummary.details.isDirect) }.orEmpty(), avatarData = avatarData, + isPlaceholder = false, userDefinedNotificationMode = roomSummary.details.userDefinedNotificationMode, hasRoomCall = roomSummary.details.hasRoomCall, isDm = roomSummary.details.isDm, diff --git a/features/roomlist/impl/src/main/kotlin/io/element/android/features/roomlist/impl/model/RoomListRoomSummary.kt b/features/roomlist/impl/src/main/kotlin/io/element/android/features/roomlist/impl/model/RoomListRoomSummary.kt index 629013d26e..81638ee2e3 100644 --- a/features/roomlist/impl/src/main/kotlin/io/element/android/features/roomlist/impl/model/RoomListRoomSummary.kt +++ b/features/roomlist/impl/src/main/kotlin/io/element/android/features/roomlist/impl/model/RoomListRoomSummary.kt @@ -18,7 +18,6 @@ package io.element.android.features.roomlist.impl.model import androidx.compose.runtime.Immutable import io.element.android.libraries.designsystem.components.avatar.AvatarData -import io.element.android.libraries.designsystem.components.avatar.AvatarSize import io.element.android.libraries.matrix.api.core.RoomId import io.element.android.libraries.matrix.api.room.RoomNotificationMode @@ -26,13 +25,13 @@ import io.element.android.libraries.matrix.api.room.RoomNotificationMode data class RoomListRoomSummary( val id: String, val roomId: RoomId, - val name: String = "", - val hasUnread: Boolean = false, - val timestamp: String? = null, - val lastMessage: CharSequence? = null, - val avatarData: AvatarData = AvatarData(id, name, size = AvatarSize.RoomListItem), - val isPlaceholder: Boolean = false, - val userDefinedNotificationMode: RoomNotificationMode? = null, - val hasRoomCall: Boolean = false, - val isDm: Boolean = false, + val name: String, + val hasUnread: Boolean, + val timestamp: String?, + val lastMessage: CharSequence?, + val avatarData: AvatarData, + val isPlaceholder: Boolean, + val userDefinedNotificationMode: RoomNotificationMode?, + val hasRoomCall: Boolean, + val isDm: Boolean, ) diff --git a/features/roomlist/impl/src/main/kotlin/io/element/android/features/roomlist/impl/model/RoomListRoomSummaryPlaceholders.kt b/features/roomlist/impl/src/main/kotlin/io/element/android/features/roomlist/impl/model/RoomListRoomSummaryPlaceholders.kt index f5976d7d1c..64a91b11e3 100644 --- a/features/roomlist/impl/src/main/kotlin/io/element/android/features/roomlist/impl/model/RoomListRoomSummaryPlaceholders.kt +++ b/features/roomlist/impl/src/main/kotlin/io/element/android/features/roomlist/impl/model/RoomListRoomSummaryPlaceholders.kt @@ -29,7 +29,11 @@ object RoomListRoomSummaryPlaceholders { name = "Short name", timestamp = "hh:mm", lastMessage = "Last message for placeholder", - avatarData = AvatarData(id, "S", size = AvatarSize.RoomListItem) + avatarData = AvatarData(id, "S", size = AvatarSize.RoomListItem), + hasUnread = false, + userDefinedNotificationMode = null, + hasRoomCall = false, + isDm = false, ) } diff --git a/features/roomlist/impl/src/test/kotlin/io/element/android/features/roomlist/impl/RoomListPresenterTests.kt b/features/roomlist/impl/src/test/kotlin/io/element/android/features/roomlist/impl/RoomListPresenterTests.kt index f4e944e96d..2af3b666db 100644 --- a/features/roomlist/impl/src/test/kotlin/io/element/android/features/roomlist/impl/RoomListPresenterTests.kt +++ b/features/roomlist/impl/src/test/kotlin/io/element/android/features/roomlist/impl/RoomListPresenterTests.kt @@ -442,4 +442,7 @@ private val aRoomListRoomSummary = RoomListRoomSummary( lastMessage = "", avatarData = AvatarData(id = A_ROOM_ID.value, name = A_ROOM_NAME, size = AvatarSize.RoomListItem), isPlaceholder = false, + userDefinedNotificationMode = null, + hasRoomCall = false, + isDm = false, ) From 5caebaaa1b3c95df04e409269cf3abe4f97554ed Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Mon, 22 Jan 2024 11:25:05 +0100 Subject: [PATCH 056/127] Introduce RoomListRoomSummaryFactory and remove RoomListRoomSummaryPlaceholders. --- .../roomlist/impl/RoomListStateProvider.kt | 11 ++- .../impl/datasource/RoomListDataSource.kt | 40 +-------- .../datasource/RoomListRoomSummaryFactory.kt | 81 +++++++++++++++++++ .../model/RoomListRoomSummaryPlaceholders.kt | 47 ----------- .../roomlist/impl/RoomListPresenterTests.kt | 9 ++- 5 files changed, 99 insertions(+), 89 deletions(-) create mode 100644 features/roomlist/impl/src/main/kotlin/io/element/android/features/roomlist/impl/datasource/RoomListRoomSummaryFactory.kt delete mode 100644 features/roomlist/impl/src/main/kotlin/io/element/android/features/roomlist/impl/model/RoomListRoomSummaryPlaceholders.kt diff --git a/features/roomlist/impl/src/main/kotlin/io/element/android/features/roomlist/impl/RoomListStateProvider.kt b/features/roomlist/impl/src/main/kotlin/io/element/android/features/roomlist/impl/RoomListStateProvider.kt index e1e105afeb..33736ab592 100644 --- a/features/roomlist/impl/src/main/kotlin/io/element/android/features/roomlist/impl/RoomListStateProvider.kt +++ b/features/roomlist/impl/src/main/kotlin/io/element/android/features/roomlist/impl/RoomListStateProvider.kt @@ -19,7 +19,6 @@ package io.element.android.features.roomlist.impl import androidx.compose.ui.tooling.preview.PreviewParameterProvider import io.element.android.features.leaveroom.api.aLeaveRoomState import io.element.android.features.roomlist.impl.model.RoomListRoomSummary -import io.element.android.features.roomlist.impl.model.RoomListRoomSummaryPlaceholders import io.element.android.features.roomlist.impl.model.aRoomListRoomSummary import io.element.android.libraries.designsystem.components.avatar.AvatarData import io.element.android.libraries.designsystem.components.avatar.AvatarSize @@ -88,7 +87,13 @@ internal fun aRoomListRoomSummaryList(): ImmutableList { avatarData = AvatarData("!id", "Z", size = AvatarSize.RoomListItem), id = "!roomId2:domain", ), - RoomListRoomSummaryPlaceholders.create("!roomId3:domain"), - RoomListRoomSummaryPlaceholders.create("!roomId4:domain"), + aRoomListRoomSummary( + id = "!roomId3:domain", + isPlaceholder = true, + ), + aRoomListRoomSummary( + id = "!roomId4:domain", + isPlaceholder = true, + ), ) } diff --git a/features/roomlist/impl/src/main/kotlin/io/element/android/features/roomlist/impl/datasource/RoomListDataSource.kt b/features/roomlist/impl/src/main/kotlin/io/element/android/features/roomlist/impl/datasource/RoomListDataSource.kt index c25759ebd8..a255767d7e 100644 --- a/features/roomlist/impl/src/main/kotlin/io/element/android/features/roomlist/impl/datasource/RoomListDataSource.kt +++ b/features/roomlist/impl/src/main/kotlin/io/element/android/features/roomlist/impl/datasource/RoomListDataSource.kt @@ -17,16 +17,9 @@ package io.element.android.features.roomlist.impl.datasource import io.element.android.features.roomlist.impl.model.RoomListRoomSummary -import io.element.android.features.roomlist.impl.model.RoomListRoomSummaryPlaceholders import io.element.android.libraries.androidutils.diff.DiffCacheUpdater import io.element.android.libraries.androidutils.diff.MutableListDiffCache import io.element.android.libraries.core.coroutine.CoroutineDispatchers -import io.element.android.libraries.core.extensions.orEmpty -import io.element.android.libraries.dateformatter.api.LastMessageTimestampFormatter -import io.element.android.libraries.designsystem.components.avatar.AvatarData -import io.element.android.libraries.designsystem.components.avatar.AvatarSize -import io.element.android.libraries.eventformatter.api.RoomLastMessageFormatter -import io.element.android.libraries.matrix.api.core.RoomId import io.element.android.libraries.matrix.api.notificationsettings.NotificationSettingsService import io.element.android.libraries.matrix.api.roomlist.RoomListService import io.element.android.libraries.matrix.api.roomlist.RoomSummary @@ -49,8 +42,7 @@ import kotlin.time.Duration.Companion.seconds class RoomListDataSource @Inject constructor( private val roomListService: RoomListService, - private val lastMessageTimestampFormatter: LastMessageTimestampFormatter, - private val roomLastMessageFormatter: RoomLastMessageFormatter, + private val roomListRoomSummaryFactory: RoomListRoomSummaryFactory, private val coroutineDispatchers: CoroutineDispatchers, private val notificationSettingsService: NotificationSettingsService, private val appScope: CoroutineScope, @@ -121,7 +113,7 @@ class RoomListDataSource @Inject constructor( private suspend fun buildAndEmitAllRooms(roomSummaries: List) { if (diffCache.isEmpty()) { _allRooms.emit( - RoomListRoomSummaryPlaceholders.createFakeList(16).toImmutableList() + roomListRoomSummaryFactory.createFakeList() ) } else { val roomListRoomSummaries = ArrayList() @@ -141,34 +133,10 @@ class RoomListDataSource @Inject constructor( private fun buildAndCacheItem(roomSummaries: List, index: Int): RoomListRoomSummary? { val roomListRoomSummary = when (val roomSummary = roomSummaries.getOrNull(index)) { - is RoomSummary.Empty -> RoomListRoomSummaryPlaceholders.create(roomSummary.identifier) - is RoomSummary.Filled -> { - val avatarData = AvatarData( - id = roomSummary.identifier(), - name = roomSummary.details.name, - url = roomSummary.details.avatarUrl, - size = AvatarSize.RoomListItem, - ) - val roomIdentifier = roomSummary.identifier() - RoomListRoomSummary( - id = roomSummary.identifier(), - roomId = RoomId(roomIdentifier), - name = roomSummary.details.name, - hasUnread = roomSummary.details.unreadNotificationCount > 0, - timestamp = lastMessageTimestampFormatter.format(roomSummary.details.lastMessageTimestamp), - lastMessage = roomSummary.details.lastMessage?.let { message -> - roomLastMessageFormatter.format(message.event, roomSummary.details.isDirect) - }.orEmpty(), - avatarData = avatarData, - isPlaceholder = false, - userDefinedNotificationMode = roomSummary.details.userDefinedNotificationMode, - hasRoomCall = roomSummary.details.hasRoomCall, - isDm = roomSummary.details.isDm, - ) - } + is RoomSummary.Empty -> roomListRoomSummaryFactory.createPlaceholder(roomSummary.identifier) + is RoomSummary.Filled -> roomListRoomSummaryFactory.create(roomSummary) null -> null } - diffCache[index] = roomListRoomSummary return roomListRoomSummary } diff --git a/features/roomlist/impl/src/main/kotlin/io/element/android/features/roomlist/impl/datasource/RoomListRoomSummaryFactory.kt b/features/roomlist/impl/src/main/kotlin/io/element/android/features/roomlist/impl/datasource/RoomListRoomSummaryFactory.kt new file mode 100644 index 0000000000..da430d7b73 --- /dev/null +++ b/features/roomlist/impl/src/main/kotlin/io/element/android/features/roomlist/impl/datasource/RoomListRoomSummaryFactory.kt @@ -0,0 +1,81 @@ +/* + * 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 io.element.android.features.roomlist.impl.datasource + +import io.element.android.features.roomlist.impl.model.RoomListRoomSummary +import io.element.android.libraries.core.extensions.orEmpty +import io.element.android.libraries.dateformatter.api.LastMessageTimestampFormatter +import io.element.android.libraries.designsystem.components.avatar.AvatarData +import io.element.android.libraries.designsystem.components.avatar.AvatarSize +import io.element.android.libraries.eventformatter.api.RoomLastMessageFormatter +import io.element.android.libraries.matrix.api.core.RoomId +import io.element.android.libraries.matrix.api.roomlist.RoomSummary +import kotlinx.collections.immutable.ImmutableList +import kotlinx.collections.immutable.toImmutableList +import javax.inject.Inject + +class RoomListRoomSummaryFactory @Inject constructor( + private val lastMessageTimestampFormatter: LastMessageTimestampFormatter, + private val roomLastMessageFormatter: RoomLastMessageFormatter, +) { + fun createPlaceholder(id: String): RoomListRoomSummary { + return RoomListRoomSummary( + id = id, + roomId = RoomId("!aRoom:domain"), + isPlaceholder = true, + name = "Short name", + timestamp = "hh:mm", + lastMessage = "Last message for placeholder", + avatarData = AvatarData(id, "S", size = AvatarSize.RoomListItem), + hasUnread = false, + userDefinedNotificationMode = null, + hasRoomCall = false, + isDm = false, + ) + } + + fun createFakeList(): ImmutableList { + return List(16) { + createPlaceholder("!fakeRoom$it:domain") + }.toImmutableList() + } + + fun create(roomSummary: RoomSummary.Filled): RoomListRoomSummary { + val roomIdentifier = roomSummary.identifier() + val avatarData = AvatarData( + id = roomIdentifier, + name = roomSummary.details.name, + url = roomSummary.details.avatarUrl, + size = AvatarSize.RoomListItem, + ) + return RoomListRoomSummary( + id = roomIdentifier, + roomId = RoomId(roomIdentifier), + name = roomSummary.details.name, + hasUnread = roomSummary.details.unreadNotificationCount > 0, + timestamp = lastMessageTimestampFormatter.format(roomSummary.details.lastMessageTimestamp), + lastMessage = roomSummary.details.lastMessage?.let { message -> + roomLastMessageFormatter.format(message.event, roomSummary.details.isDirect) + }.orEmpty(), + avatarData = avatarData, + isPlaceholder = false, + userDefinedNotificationMode = roomSummary.details.userDefinedNotificationMode, + hasRoomCall = roomSummary.details.hasRoomCall, + isDm = roomSummary.details.isDm, + ) + } +} diff --git a/features/roomlist/impl/src/main/kotlin/io/element/android/features/roomlist/impl/model/RoomListRoomSummaryPlaceholders.kt b/features/roomlist/impl/src/main/kotlin/io/element/android/features/roomlist/impl/model/RoomListRoomSummaryPlaceholders.kt deleted file mode 100644 index 64a91b11e3..0000000000 --- a/features/roomlist/impl/src/main/kotlin/io/element/android/features/roomlist/impl/model/RoomListRoomSummaryPlaceholders.kt +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Copyright (c) 2023 New Vector Ltd - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.element.android.features.roomlist.impl.model - -import io.element.android.libraries.designsystem.components.avatar.AvatarData -import io.element.android.libraries.designsystem.components.avatar.AvatarSize -import io.element.android.libraries.matrix.api.core.RoomId - -object RoomListRoomSummaryPlaceholders { - fun create(id: String): RoomListRoomSummary { - return RoomListRoomSummary( - id = id, - roomId = RoomId("!aRoom:domain"), - isPlaceholder = true, - name = "Short name", - timestamp = "hh:mm", - lastMessage = "Last message for placeholder", - avatarData = AvatarData(id, "S", size = AvatarSize.RoomListItem), - hasUnread = false, - userDefinedNotificationMode = null, - hasRoomCall = false, - isDm = false, - ) - } - - fun createFakeList(size: Int): List { - return mutableListOf().apply { - repeat(size) { - add(create("!fakeRoom$it:domain")) - } - } - } -} diff --git a/features/roomlist/impl/src/test/kotlin/io/element/android/features/roomlist/impl/RoomListPresenterTests.kt b/features/roomlist/impl/src/test/kotlin/io/element/android/features/roomlist/impl/RoomListPresenterTests.kt index 2af3b666db..b868c950e5 100644 --- a/features/roomlist/impl/src/test/kotlin/io/element/android/features/roomlist/impl/RoomListPresenterTests.kt +++ b/features/roomlist/impl/src/test/kotlin/io/element/android/features/roomlist/impl/RoomListPresenterTests.kt @@ -28,6 +28,7 @@ import io.element.android.features.networkmonitor.test.FakeNetworkMonitor import io.element.android.features.roomlist.impl.datasource.FakeInviteDataSource import io.element.android.features.roomlist.impl.datasource.InviteStateDataSource import io.element.android.features.roomlist.impl.datasource.RoomListDataSource +import io.element.android.features.roomlist.impl.datasource.RoomListRoomSummaryFactory import io.element.android.features.roomlist.impl.model.RoomListRoomSummary import io.element.android.libraries.dateformatter.api.LastMessageTimestampFormatter import io.element.android.libraries.dateformatter.test.FakeLastMessageTimestampFormatter @@ -414,9 +415,11 @@ class RoomListPresenterTests { inviteStateDataSource = inviteStateDataSource, leaveRoomPresenter = leaveRoomPresenter, roomListDataSource = RoomListDataSource( - client.roomListService, - lastMessageTimestampFormatter, - roomLastMessageFormatter, + roomListService = client.roomListService, + roomListRoomSummaryFactory = RoomListRoomSummaryFactory( + lastMessageTimestampFormatter = lastMessageTimestampFormatter, + roomLastMessageFormatter = roomLastMessageFormatter, + ), coroutineDispatchers = testCoroutineDispatchers(), notificationSettingsService = client.notificationSettingsService(), appScope = coroutineScope From 9460bcdeb6476c7ad34445c2fa67ec1b0e86588d Mon Sep 17 00:00:00 2001 From: ElementBot Date: Mon, 22 Jan 2024 10:36:08 +0000 Subject: [PATCH 057/127] Update screenshots --- ...ow_null_RoomSummaryRow-Day-9_10_null_0,NEXUS_5,1.0,en].png | 4 ++-- ...ow_null_RoomSummaryRow-Day-9_10_null_1,NEXUS_5,1.0,en].png | 4 ++-- ...ow_null_RoomSummaryRow-Day-9_10_null_2,NEXUS_5,1.0,en].png | 4 ++-- ...ow_null_RoomSummaryRow-Day-9_10_null_3,NEXUS_5,1.0,en].png | 4 ++-- ...ow_null_RoomSummaryRow-Day-9_10_null_4,NEXUS_5,1.0,en].png | 4 ++-- ...ow_null_RoomSummaryRow-Day-9_10_null_5,NEXUS_5,1.0,en].png | 4 ++-- ...ow_null_RoomSummaryRow-Day-9_10_null_7,NEXUS_5,1.0,en].png | 4 ++-- ...ow_null_RoomSummaryRow-Day-9_10_null_8,NEXUS_5,1.0,en].png | 4 ++-- ..._null_RoomSummaryRow-Night-9_11_null_0,NEXUS_5,1.0,en].png | 4 ++-- ..._null_RoomSummaryRow-Night-9_11_null_1,NEXUS_5,1.0,en].png | 4 ++-- ..._null_RoomSummaryRow-Night-9_11_null_2,NEXUS_5,1.0,en].png | 4 ++-- ..._null_RoomSummaryRow-Night-9_11_null_3,NEXUS_5,1.0,en].png | 4 ++-- ..._null_RoomSummaryRow-Night-9_11_null_4,NEXUS_5,1.0,en].png | 4 ++-- ..._null_RoomSummaryRow-Night-9_11_null_5,NEXUS_5,1.0,en].png | 4 ++-- ..._null_RoomSummaryRow-Night-9_11_null_7,NEXUS_5,1.0,en].png | 4 ++-- ..._null_RoomSummaryRow-Night-9_11_null_8,NEXUS_5,1.0,en].png | 4 ++-- 16 files changed, 32 insertions(+), 32 deletions(-) diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Day-9_10_null_0,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Day-9_10_null_0,NEXUS_5,1.0,en].png index 040f9a72b8..ded89c6b2a 100644 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Day-9_10_null_0,NEXUS_5,1.0,en].png +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Day-9_10_null_0,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:cf71e045231208529eb524abce7b246a0ac6283c422f9695d560071fda7085f2 -size 12820 +oid sha256:57e0c90fa627974aba0d62363906bcc7911a6ada7d9d7db00db0df1d51fed54c +size 12911 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Day-9_10_null_1,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Day-9_10_null_1,NEXUS_5,1.0,en].png index a83f9527ef..94306b9d92 100644 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Day-9_10_null_1,NEXUS_5,1.0,en].png +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Day-9_10_null_1,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:34972a9257a96b4ac77edf06e5f29ebc2d8e581dcaef131ecba9730cb0f48c1c -size 10176 +oid sha256:fcf2f25bbcb2f43d70a8a3228ba97426dbb98b533b74dd13ef6459f96a711db5 +size 8877 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Day-9_10_null_2,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Day-9_10_null_2,NEXUS_5,1.0,en].png index 10d75c6a5b..12df0ea671 100644 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Day-9_10_null_2,NEXUS_5,1.0,en].png +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Day-9_10_null_2,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:7ef683a74c785d57190508952f18ed5c669ff32a38cbc4f5b66d02330115843b -size 14103 +oid sha256:d1d8c374c7c3f8ad66b3936e8eda3161a93281aa3107027516ab671958f10980 +size 14187 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Day-9_10_null_3,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Day-9_10_null_3,NEXUS_5,1.0,en].png index ac31b4c341..0af38a4878 100644 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Day-9_10_null_3,NEXUS_5,1.0,en].png +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Day-9_10_null_3,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:28b9ccdc834d9643694f72ce1c01fb988685a7b0300912bada032be1e426b467 -size 13539 +oid sha256:352b75021319958e86affa3d44c38cf72151d32796d70a0920ef63d73984ad72 +size 13627 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Day-9_10_null_4,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Day-9_10_null_4,NEXUS_5,1.0,en].png index 961345501b..ea9b3053bf 100644 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Day-9_10_null_4,NEXUS_5,1.0,en].png +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Day-9_10_null_4,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:3ada109a4f7b3b3bfae402eaddcdc240fd5f08aad41e7f1e70878baa8e257f2b -size 13288 +oid sha256:14e33bc8286952b7608adfa9864a1649c817992d35e9e0de8edc9957b8f4a6c6 +size 13388 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Day-9_10_null_5,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Day-9_10_null_5,NEXUS_5,1.0,en].png index 15fba97e39..356b3a6d1e 100644 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Day-9_10_null_5,NEXUS_5,1.0,en].png +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Day-9_10_null_5,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:0b18e5991be70ab16f983b929d08e566c85483e6d79f4de7a4191a800f4cae35 -size 13305 +oid sha256:d8442308cab3c75f64559bcd67dc39ce6d95a546ae33a7eb885c775349ab36f5 +size 13378 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Day-9_10_null_7,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Day-9_10_null_7,NEXUS_5,1.0,en].png index 547657fe23..ae1e098362 100644 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Day-9_10_null_7,NEXUS_5,1.0,en].png +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Day-9_10_null_7,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:950e80e7e4be904967d35aaffe196548fa4f5ae9afdf2b86e65611ccdb14bf80 -size 22203 +oid sha256:a1dfe518ad4ee77539f017a39c684e0ce7bfb733a33161639fdf606a188b13d0 +size 22406 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Day-9_10_null_8,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Day-9_10_null_8,NEXUS_5,1.0,en].png index 7c302dc03f..fcf6f86a3e 100644 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Day-9_10_null_8,NEXUS_5,1.0,en].png +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Day-9_10_null_8,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:9c90561dc7355b1917ebe96bebc717de14aac5c4897ef3e8dd0b2aca8c51c362 -size 13610 +oid sha256:b044aa278ad070f75ffcf3d0d895c93bd784eb9c3e19e6aa842bbc1170bc92b4 +size 13688 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Night-9_11_null_0,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Night-9_11_null_0,NEXUS_5,1.0,en].png index 22cb212645..d83d063b86 100644 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Night-9_11_null_0,NEXUS_5,1.0,en].png +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Night-9_11_null_0,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:7fcbdfc3e45fa0f111cc384c54c40980913e52ff755e9380fba262a4c659a5c5 -size 12715 +oid sha256:1d914ad609cda9e94ba793027c17f3b7289fec71e65e1880b837615203f7718e +size 12907 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Night-9_11_null_1,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Night-9_11_null_1,NEXUS_5,1.0,en].png index 3daf9dec9f..d93b2c752f 100644 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Night-9_11_null_1,NEXUS_5,1.0,en].png +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Night-9_11_null_1,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:063d4415a254eef251f4c0f63827062259f76c0d8a1e309e64a4e7376fc04a9b -size 10101 +oid sha256:e05f294579b4420e6671f268d10fae8fb49e93e5ae5b0f0d4548f7cdfeb82742 +size 8928 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Night-9_11_null_2,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Night-9_11_null_2,NEXUS_5,1.0,en].png index c329163b6f..904b3a0b95 100644 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Night-9_11_null_2,NEXUS_5,1.0,en].png +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Night-9_11_null_2,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:fd40343c425b1c7499e72d0d4119f36d06200b54e72034f97c172e5c2dad57af -size 13756 +oid sha256:4fcbb393a93d6a04e0415d2bb7bed4c002ec82907fbccf6070a4880a6b208e3c +size 13942 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Night-9_11_null_3,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Night-9_11_null_3,NEXUS_5,1.0,en].png index f8e1416ce2..3b2e01f9b5 100644 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Night-9_11_null_3,NEXUS_5,1.0,en].png +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Night-9_11_null_3,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:584487de266a9b3e9cdefee0378023a946b309e19b09acffc5bf1a08dfc0d390 -size 13335 +oid sha256:811d95287c12d59fa1014b62ac8ae755f6355dbbd0700c2adc331293adfcc7a4 +size 13535 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Night-9_11_null_4,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Night-9_11_null_4,NEXUS_5,1.0,en].png index 11cdbfc582..7c71f03c1b 100644 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Night-9_11_null_4,NEXUS_5,1.0,en].png +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Night-9_11_null_4,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:8bda8b4f6a84b37548e3926f180ddb282d220b8ff581a60e69e0e309ad3ae06a -size 13119 +oid sha256:435737296b59d70210fc93ba70d2fa228ba4bab645fb9a6366609197a97f87c0 +size 13305 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Night-9_11_null_5,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Night-9_11_null_5,NEXUS_5,1.0,en].png index 057f4f914c..4e88d5c639 100644 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Night-9_11_null_5,NEXUS_5,1.0,en].png +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Night-9_11_null_5,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:2c17e87f046bbdd7a0300262737508cd1ffab4b54da9df7e7a7803237e070243 -size 13032 +oid sha256:d5a2d15ec2b36255963bc2514df0ff2dc8588c177d06c5431ca457af4de916e6 +size 13210 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Night-9_11_null_7,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Night-9_11_null_7,NEXUS_5,1.0,en].png index 58ef0ec934..0f0d5353fb 100644 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Night-9_11_null_7,NEXUS_5,1.0,en].png +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Night-9_11_null_7,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:06df893c35c81609b46317f4de733db0bed4f5888eac189d09078ad7bd411cf0 -size 21340 +oid sha256:b5f274b1ad4ca31aaf585d34ce48c2898fbb9ada8294b211fe1440a097da21f6 +size 21626 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Night-9_11_null_8,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Night-9_11_null_8,NEXUS_5,1.0,en].png index 4e9d41b689..2e19344be7 100644 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Night-9_11_null_8,NEXUS_5,1.0,en].png +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Night-9_11_null_8,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:5efc2679fc43f952d1a41ffff7c5400baeb6f46e7faba0faef6409ea178c08de -size 13319 +oid sha256:a13837fffa77d7f95d6f4f163fb2e674070777caf02cce74b6a52e91f3103224 +size 13500 From 473922240ea7dde1b44a60abb0d98537d7e1529b Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Mon, 22 Jan 2024 14:03:40 +0100 Subject: [PATCH 058/127] Fix compilation of sample app. --- .../android/samples/minimal/RoomListScreen.kt | 21 +++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/samples/minimal/src/main/kotlin/io/element/android/samples/minimal/RoomListScreen.kt b/samples/minimal/src/main/kotlin/io/element/android/samples/minimal/RoomListScreen.kt index 7706cdbb5d..286a80d71d 100644 --- a/samples/minimal/src/main/kotlin/io/element/android/samples/minimal/RoomListScreen.kt +++ b/samples/minimal/src/main/kotlin/io/element/android/samples/minimal/RoomListScreen.kt @@ -27,6 +27,7 @@ import io.element.android.features.roomlist.impl.RoomListPresenter import io.element.android.features.roomlist.impl.RoomListView import io.element.android.features.roomlist.impl.datasource.DefaultInviteStateDataSource import io.element.android.features.roomlist.impl.datasource.RoomListDataSource +import io.element.android.features.roomlist.impl.datasource.RoomListRoomSummaryFactory import io.element.android.libraries.core.coroutine.CoroutineDispatchers import io.element.android.libraries.dateformatter.impl.DateFormatters import io.element.android.libraries.dateformatter.impl.DefaultLastMessageTimestampFormatter @@ -76,12 +77,20 @@ class RoomListScreen( leaveRoomPresenter = LeaveRoomPresenterImpl(matrixClient, RoomMembershipObserver(), coroutineDispatchers), roomListDataSource = RoomListDataSource( roomListService = matrixClient.roomListService, - lastMessageTimestampFormatter = DefaultLastMessageTimestampFormatter(dateTimeProvider, dateFormatters), - roomLastMessageFormatter = DefaultRoomLastMessageFormatter( - sp = stringProvider, - roomMembershipContentFormatter = RoomMembershipContentFormatter(matrixClient, stringProvider), - profileChangeContentFormatter = ProfileChangeContentFormatter(stringProvider), - stateContentFormatter = StateContentFormatter(stringProvider), + roomListRoomSummaryFactory = RoomListRoomSummaryFactory( + lastMessageTimestampFormatter = DefaultLastMessageTimestampFormatter( + localDateTimeProvider = dateTimeProvider, + dateFormatters = dateFormatters + ), + roomLastMessageFormatter = DefaultRoomLastMessageFormatter( + sp = stringProvider, + roomMembershipContentFormatter = RoomMembershipContentFormatter( + matrixClient = matrixClient, + sp = stringProvider + ), + profileChangeContentFormatter = ProfileChangeContentFormatter(stringProvider), + stateContentFormatter = StateContentFormatter(stringProvider), + ), ), coroutineDispatchers = coroutineDispatchers, notificationSettingsService = matrixClient.notificationSettingsService(), From bbd871031a03cf06156d10bfb1242b5351e1287a Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Mon, 22 Jan 2024 14:21:49 +0100 Subject: [PATCH 059/127] Fix detekt issue: Use `?.let {}` instead of if/else with a null block when checking for nullable values [UseLet] --- .../features/roomlist/impl/model/RoomListRoomSummaryProvider.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/features/roomlist/impl/src/main/kotlin/io/element/android/features/roomlist/impl/model/RoomListRoomSummaryProvider.kt b/features/roomlist/impl/src/main/kotlin/io/element/android/features/roomlist/impl/model/RoomListRoomSummaryProvider.kt index e312d2bf14..0a45aa10f9 100644 --- a/features/roomlist/impl/src/main/kotlin/io/element/android/features/roomlist/impl/model/RoomListRoomSummaryProvider.kt +++ b/features/roomlist/impl/src/main/kotlin/io/element/android/features/roomlist/impl/model/RoomListRoomSummaryProvider.kt @@ -49,7 +49,7 @@ internal fun aRoomListRoomSummary( name: String = "Room name", hasUnread: Boolean = false, lastMessage: String? = "Last message", - timestamp: String? = if (lastMessage != null) "88:88" else null, + timestamp: String? = lastMessage?.let { "88:88" }, isPlaceholder: Boolean = false, notificationMode: RoomNotificationMode? = null, hasRoomCall: Boolean = false, From dd12071ea2b2c0a4ec85b57d8c6980ad1e5b7b02 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Fri, 19 Jan 2024 17:48:26 +0100 Subject: [PATCH 060/127] Use new Rust fields `numUnreadMessages` and `numUnreadMentions`, and iterate on the room badge rendering. --- .../impl/InviteListPresenterTests.kt | 3 - ...DefaultNotificationSettingStateProvider.kt | 1 - .../roomlist/impl/RoomListStateProvider.kt | 4 +- .../impl/components/RoomSummaryRow.kt | 90 +++++++++++++------ .../datasource/RoomListRoomSummaryFactory.kt | 6 +- .../impl/model/RoomListRoomSummary.kt | 13 ++- .../impl/model/RoomListRoomSummaryProvider.kt | 77 ++++++++++++---- .../roomlist/impl/RoomListPresenterTests.kt | 3 +- .../matrix/api/roomlist/RoomSummary.kt | 3 +- .../roomlist/RoomSummaryDetailsFactory.kt | 3 +- .../matrix/test/room/RoomSummaryFixture.kt | 12 ++- .../matrix/ui/components/SelectedRoom.kt | 6 +- 12 files changed, 159 insertions(+), 62 deletions(-) diff --git a/features/invitelist/impl/src/test/kotlin/io/element/android/features/invitelist/impl/InviteListPresenterTests.kt b/features/invitelist/impl/src/test/kotlin/io/element/android/features/invitelist/impl/InviteListPresenterTests.kt index a841b21c56..0fa899e033 100644 --- a/features/invitelist/impl/src/test/kotlin/io/element/android/features/invitelist/impl/InviteListPresenterTests.kt +++ b/features/invitelist/impl/src/test/kotlin/io/element/android/features/invitelist/impl/InviteListPresenterTests.kt @@ -431,7 +431,6 @@ class InviteListPresenterTests { avatarUrl = null, isDirect = false, lastMessage = null, - unreadNotificationCount = 0, inviter = RoomMember( userId = A_USER_ID, displayName = A_USER_NAME, @@ -459,7 +458,6 @@ class InviteListPresenterTests { avatarUrl = null, isDirect = true, lastMessage = null, - unreadNotificationCount = 0, inviter = RoomMember( userId = A_USER_ID, displayName = A_USER_NAME, @@ -484,7 +482,6 @@ class InviteListPresenterTests { avatarUrl = null, isDirect = false, lastMessage = null, - unreadNotificationCount = 0, ) ) diff --git a/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/notifications/edit/EditDefaultNotificationSettingStateProvider.kt b/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/notifications/edit/EditDefaultNotificationSettingStateProvider.kt index 3c7df8fc52..1eb7c0389e 100644 --- a/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/notifications/edit/EditDefaultNotificationSettingStateProvider.kt +++ b/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/notifications/edit/EditDefaultNotificationSettingStateProvider.kt @@ -55,7 +55,6 @@ private fun aRoomSummary() = RoomSummary.Filled( avatarUrl = null, isDirect = false, lastMessage = null, - unreadNotificationCount = 0, notificationMode = RoomNotificationMode.MENTIONS_AND_KEYWORDS_ONLY, ) ) diff --git a/features/roomlist/impl/src/main/kotlin/io/element/android/features/roomlist/impl/RoomListStateProvider.kt b/features/roomlist/impl/src/main/kotlin/io/element/android/features/roomlist/impl/RoomListStateProvider.kt index 33736ab592..b1e43f147e 100644 --- a/features/roomlist/impl/src/main/kotlin/io/element/android/features/roomlist/impl/RoomListStateProvider.kt +++ b/features/roomlist/impl/src/main/kotlin/io/element/android/features/roomlist/impl/RoomListStateProvider.kt @@ -73,7 +73,7 @@ internal fun aRoomListRoomSummaryList(): ImmutableList { return persistentListOf( aRoomListRoomSummary( name = "Room", - hasUnread = true, + numberOfUnreadMessages = 1, timestamp = "14:18", lastMessage = "A very very very very long message which suites on two lines", avatarData = AvatarData("!id", "R", size = AvatarSize.RoomListItem), @@ -81,7 +81,7 @@ internal fun aRoomListRoomSummaryList(): ImmutableList { ), aRoomListRoomSummary( name = "Room#2", - hasUnread = false, + numberOfUnreadMessages = 0, timestamp = "14:16", lastMessage = "A short message", avatarData = AvatarData("!id", "Z", size = AvatarSize.RoomListItem), diff --git a/features/roomlist/impl/src/main/kotlin/io/element/android/features/roomlist/impl/components/RoomSummaryRow.kt b/features/roomlist/impl/src/main/kotlin/io/element/android/features/roomlist/impl/components/RoomSummaryRow.kt index d8ee21093f..dd16a281c2 100644 --- a/features/roomlist/impl/src/main/kotlin/io/element/android/features/roomlist/impl/components/RoomSummaryRow.kt +++ b/features/roomlist/impl/src/main/kotlin/io/element/android/features/roomlist/impl/components/RoomSummaryRow.kt @@ -43,6 +43,7 @@ import io.element.android.compound.theme.ElementTheme import io.element.android.compound.tokens.generated.CompoundIcons import io.element.android.features.roomlist.impl.model.RoomListRoomSummary import io.element.android.features.roomlist.impl.model.RoomListRoomSummaryProvider +import io.element.android.features.roomlist.impl.model.isTimestampHighlighted import io.element.android.libraries.core.extensions.orEmpty import io.element.android.libraries.designsystem.atomic.atoms.UnreadIndicatorAtom import io.element.android.libraries.designsystem.components.avatar.Avatar @@ -141,7 +142,7 @@ private fun RowScope.NameAndTimestampRow(room: RoomListRoomSummary) { Text( text = room.timestamp ?: "", style = ElementTheme.typography.fontBodySmMedium, - color = if (room.hasUnread) { + color = if (room.isTimestampHighlighted()) { ElementTheme.colors.unreadIndicator } else { MaterialTheme.roomListRoomMessageDate() @@ -173,40 +174,77 @@ private fun RowScope.LastMessageAndIndicatorRow(room: RoomListRoomSummary) { verticalAlignment = Alignment.CenterVertically, ) { // Video call - if (room.hasRoomCall) { - Icon( - modifier = Modifier.size(16.dp), - imageVector = CompoundIcons.VideoCallSolid, - contentDescription = null, - tint = ElementTheme.colors.unreadIndicator, - ) - } - NotificationIcon(room) - if (room.hasUnread) { - UnreadIndicatorAtom() - } + OnGoingCallIcon( + room.hasRoomCall, + ) + // Other indicators + NotificationIcons( + room.userDefinedNotificationMode, + room.numberOfUnreadMessages, + room.numberOfUnreadMentions, + ) } } @Composable -private fun NotificationIcon(room: RoomListRoomSummary) { - val tint = if (room.hasUnread) ElementTheme.colors.unreadIndicator else ElementTheme.colors.iconQuaternary - when (room.userDefinedNotificationMode) { - null, RoomNotificationMode.ALL_MESSAGES -> return - RoomNotificationMode.MENTIONS_AND_KEYWORDS_ONLY -> - Icon( - modifier = Modifier.size(16.dp), - contentDescription = null, - imageVector = CompoundIcons.Mention, - tint = tint, - ) - RoomNotificationMode.MUTE -> +private fun OnGoingCallIcon( + hasRoomCall: Boolean, +) { + if (hasRoomCall) { + Icon( + modifier = Modifier.size(16.dp), + imageVector = CompoundIcons.VideoCallSolid, + contentDescription = null, + tint = ElementTheme.colors.unreadIndicator, + ) + } +} + +@Composable +private fun RowScope.NotificationIcons( + userDefinedNotificationMode: RoomNotificationMode?, + numberOfUnreadMessages: Int, + numberOfUnreadMentions: Int, +) { + when (userDefinedNotificationMode) { + null, + RoomNotificationMode.ALL_MESSAGES -> { + if (numberOfUnreadMentions > 0) { + Icon( + modifier = Modifier.size(16.dp), + contentDescription = null, + imageVector = CompoundIcons.Mention, + tint = ElementTheme.colors.unreadIndicator, + ) + UnreadIndicatorAtom() + } else if (numberOfUnreadMessages > 0) { + UnreadIndicatorAtom() + } + } + RoomNotificationMode.MENTIONS_AND_KEYWORDS_ONLY -> { + if (numberOfUnreadMentions > 0) { + Icon( + modifier = Modifier.size(16.dp), + contentDescription = null, + imageVector = CompoundIcons.Mention, + tint = ElementTheme.colors.unreadIndicator, + ) + UnreadIndicatorAtom() + } else if (numberOfUnreadMessages > 0) { + UnreadIndicatorAtom(color = ElementTheme.colors.iconQuaternary) + } + } + RoomNotificationMode.MUTE -> { Icon( modifier = Modifier.size(16.dp), contentDescription = null, imageVector = CompoundIcons.NotificationsSolidOff, - tint = tint, + tint = ElementTheme.colors.iconQuaternary, ) + if (numberOfUnreadMessages > 0 || numberOfUnreadMentions > 0) { + UnreadIndicatorAtom(color = ElementTheme.colors.iconQuaternary) + } + } } } diff --git a/features/roomlist/impl/src/main/kotlin/io/element/android/features/roomlist/impl/datasource/RoomListRoomSummaryFactory.kt b/features/roomlist/impl/src/main/kotlin/io/element/android/features/roomlist/impl/datasource/RoomListRoomSummaryFactory.kt index da430d7b73..e12674658a 100644 --- a/features/roomlist/impl/src/main/kotlin/io/element/android/features/roomlist/impl/datasource/RoomListRoomSummaryFactory.kt +++ b/features/roomlist/impl/src/main/kotlin/io/element/android/features/roomlist/impl/datasource/RoomListRoomSummaryFactory.kt @@ -41,7 +41,8 @@ class RoomListRoomSummaryFactory @Inject constructor( timestamp = "hh:mm", lastMessage = "Last message for placeholder", avatarData = AvatarData(id, "S", size = AvatarSize.RoomListItem), - hasUnread = false, + numberOfUnreadMessages = 0, + numberOfUnreadMentions = 0, userDefinedNotificationMode = null, hasRoomCall = false, isDm = false, @@ -66,7 +67,8 @@ class RoomListRoomSummaryFactory @Inject constructor( id = roomIdentifier, roomId = RoomId(roomIdentifier), name = roomSummary.details.name, - hasUnread = roomSummary.details.unreadNotificationCount > 0, + numberOfUnreadMessages = roomSummary.details.numUnreadMessages, + numberOfUnreadMentions = roomSummary.details.numUnreadMentions, timestamp = lastMessageTimestampFormatter.format(roomSummary.details.lastMessageTimestamp), lastMessage = roomSummary.details.lastMessage?.let { message -> roomLastMessageFormatter.format(message.event, roomSummary.details.isDirect) diff --git a/features/roomlist/impl/src/main/kotlin/io/element/android/features/roomlist/impl/model/RoomListRoomSummary.kt b/features/roomlist/impl/src/main/kotlin/io/element/android/features/roomlist/impl/model/RoomListRoomSummary.kt index 81638ee2e3..0669be0031 100644 --- a/features/roomlist/impl/src/main/kotlin/io/element/android/features/roomlist/impl/model/RoomListRoomSummary.kt +++ b/features/roomlist/impl/src/main/kotlin/io/element/android/features/roomlist/impl/model/RoomListRoomSummary.kt @@ -26,7 +26,8 @@ data class RoomListRoomSummary( val id: String, val roomId: RoomId, val name: String, - val hasUnread: Boolean, + val numberOfUnreadMessages: Int, + val numberOfUnreadMentions: Int, val timestamp: String?, val lastMessage: CharSequence?, val avatarData: AvatarData, @@ -35,3 +36,13 @@ data class RoomListRoomSummary( val hasRoomCall: Boolean, val isDm: Boolean, ) + +fun RoomListRoomSummary.isTimestampHighlighted(): Boolean { + return hasRoomCall || + when (userDefinedNotificationMode) { + null, + RoomNotificationMode.ALL_MESSAGES -> numberOfUnreadMessages > 0 || numberOfUnreadMentions > 0 + RoomNotificationMode.MENTIONS_AND_KEYWORDS_ONLY -> numberOfUnreadMentions > 0 + RoomNotificationMode.MUTE -> false + } +} diff --git a/features/roomlist/impl/src/main/kotlin/io/element/android/features/roomlist/impl/model/RoomListRoomSummaryProvider.kt b/features/roomlist/impl/src/main/kotlin/io/element/android/features/roomlist/impl/model/RoomListRoomSummaryProvider.kt index 0a45aa10f9..f1b0403f5b 100644 --- a/features/roomlist/impl/src/main/kotlin/io/element/android/features/roomlist/impl/model/RoomListRoomSummaryProvider.kt +++ b/features/roomlist/impl/src/main/kotlin/io/element/android/features/roomlist/impl/model/RoomListRoomSummaryProvider.kt @@ -25,29 +25,69 @@ import io.element.android.libraries.matrix.api.room.RoomNotificationMode open class RoomListRoomSummaryProvider : PreviewParameterProvider { override val values: Sequence get() = sequenceOf( - aRoomListRoomSummary(), - aRoomListRoomSummary(lastMessage = null), - aRoomListRoomSummary(hasUnread = true, notificationMode = RoomNotificationMode.MENTIONS_AND_KEYWORDS_ONLY), - aRoomListRoomSummary(notificationMode = RoomNotificationMode.MENTIONS_AND_KEYWORDS_ONLY), - aRoomListRoomSummary(notificationMode = RoomNotificationMode.MUTE), - aRoomListRoomSummary(hasUnread = true), - aRoomListRoomSummary(isPlaceholder = true), - aRoomListRoomSummary( - name = "A very long room name that should be truncated", - lastMessage = "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt" + - " ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea com" + - "modo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur.", - timestamp = "yesterday", - hasUnread = true, + listOf( + aRoomListRoomSummary(isPlaceholder = true), + aRoomListRoomSummary(), + aRoomListRoomSummary(lastMessage = null), + aRoomListRoomSummary( + name = "A very long room name that should be truncated", + lastMessage = "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt" + + " ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea com" + + "modo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur.", + timestamp = "yesterday", + numberOfUnreadMessages = 1, + ), ), - aRoomListRoomSummary(hasUnread = true, hasRoomCall = true), - ) + listOf(false, true).map { hasCall -> + listOf( + RoomNotificationMode.ALL_MESSAGES, + RoomNotificationMode.MENTIONS_AND_KEYWORDS_ONLY, + RoomNotificationMode.MUTE, + ).map { roomNotificationMode -> + listOf( + aRoomListRoomSummary( + name = roomNotificationMode.name, + lastMessage = "No activity" + if (hasCall) ", call" else "", + notificationMode = roomNotificationMode, + numberOfUnreadMessages = 0, + numberOfUnreadMentions = 0, + hasRoomCall = hasCall, + ), + aRoomListRoomSummary( + name = roomNotificationMode.name, + lastMessage = "New messages" + if (hasCall) ", call" else "", + notificationMode = roomNotificationMode, + numberOfUnreadMessages = 1, + numberOfUnreadMentions = 0, + hasRoomCall = hasCall, + ), + aRoomListRoomSummary( + name = roomNotificationMode.name, + lastMessage = "New messages, mentions" + if (hasCall) ", call" else "", + notificationMode = roomNotificationMode, + numberOfUnreadMessages = 1, + numberOfUnreadMentions = 1, + hasRoomCall = hasCall, + ), + aRoomListRoomSummary( + name = roomNotificationMode.name, + lastMessage = "New mentions" + if (hasCall) ", call" else "", + notificationMode = roomNotificationMode, + numberOfUnreadMessages = 0, + numberOfUnreadMentions = 1, + hasRoomCall = hasCall, + ), + ) + }.flatten() + }.flatten(), + ).flatten() } internal fun aRoomListRoomSummary( id: String = "!roomId:domain", name: String = "Room name", - hasUnread: Boolean = false, + numberOfUnreadMessages: Int = 0, + numberOfUnreadMentions: Int = 0, lastMessage: String? = "Last message", timestamp: String? = lastMessage?.let { "88:88" }, isPlaceholder: Boolean = false, @@ -59,7 +99,8 @@ internal fun aRoomListRoomSummary( id = id, roomId = RoomId(id), name = name, - hasUnread = hasUnread, + numberOfUnreadMessages = numberOfUnreadMessages, + numberOfUnreadMentions = numberOfUnreadMentions, timestamp = timestamp, lastMessage = lastMessage, avatarData = avatarData, diff --git a/features/roomlist/impl/src/test/kotlin/io/element/android/features/roomlist/impl/RoomListPresenterTests.kt b/features/roomlist/impl/src/test/kotlin/io/element/android/features/roomlist/impl/RoomListPresenterTests.kt index b868c950e5..27d8fca783 100644 --- a/features/roomlist/impl/src/test/kotlin/io/element/android/features/roomlist/impl/RoomListPresenterTests.kt +++ b/features/roomlist/impl/src/test/kotlin/io/element/android/features/roomlist/impl/RoomListPresenterTests.kt @@ -440,7 +440,8 @@ private val aRoomListRoomSummary = RoomListRoomSummary( id = A_ROOM_ID.value, roomId = A_ROOM_ID, name = A_ROOM_NAME, - hasUnread = true, + numberOfUnreadMentions = 1, + numberOfUnreadMessages = 2, timestamp = A_FORMATTED_DATE, lastMessage = "", avatarData = AvatarData(id = A_ROOM_ID.value, name = A_ROOM_NAME, size = AvatarSize.RoomListItem), diff --git a/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/roomlist/RoomSummary.kt b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/roomlist/RoomSummary.kt index 6c43ee1fef..09862c7879 100644 --- a/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/roomlist/RoomSummary.kt +++ b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/roomlist/RoomSummary.kt @@ -40,7 +40,8 @@ data class RoomSummaryDetails( val isDirect: Boolean, val avatarUrl: String?, val lastMessage: RoomMessage?, - val unreadNotificationCount: Int, + val numUnreadMessages: Int, + val numUnreadMentions: Int, val inviter: RoomMember?, val userDefinedNotificationMode: RoomNotificationMode?, val hasRoomCall: Boolean, diff --git a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/roomlist/RoomSummaryDetailsFactory.kt b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/roomlist/RoomSummaryDetailsFactory.kt index 5dd6f1ff8a..d308f2b1d3 100644 --- a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/roomlist/RoomSummaryDetailsFactory.kt +++ b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/roomlist/RoomSummaryDetailsFactory.kt @@ -35,7 +35,8 @@ class RoomSummaryDetailsFactory(private val roomMessageFactory: RoomMessageFacto canonicalAlias = roomInfo.canonicalAlias, isDirect = roomInfo.isDirect, avatarUrl = roomInfo.avatarUrl, - unreadNotificationCount = roomInfo.notificationCount.toInt(), + numUnreadMentions = roomInfo.numUnreadMentions.toInt(), + numUnreadMessages = roomInfo.numUnreadMessages.toInt(), lastMessage = latestRoomMessage, inviter = roomInfo.inviter?.let(RoomMemberMapper::map), userDefinedNotificationMode = roomInfo.userDefinedNotificationMode?.let(RoomNotificationSettingsMapper::mapMode), diff --git a/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/room/RoomSummaryFixture.kt b/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/room/RoomSummaryFixture.kt index a0a69bfe7b..9e8c438ee3 100644 --- a/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/room/RoomSummaryFixture.kt +++ b/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/room/RoomSummaryFixture.kt @@ -37,7 +37,8 @@ fun aRoomSummaryFilled( isDirect: Boolean = false, avatarUrl: String? = null, lastMessage: RoomMessage? = aRoomMessage(), - unreadNotificationCount: Int = 2, + numUnreadMentions: Int = 1, + numUnreadMessages: Int = 2, notificationMode: RoomNotificationMode? = null, ) = RoomSummary.Filled( aRoomSummaryDetails( @@ -46,7 +47,8 @@ fun aRoomSummaryFilled( isDirect = isDirect, avatarUrl = avatarUrl, lastMessage = lastMessage, - unreadNotificationCount = unreadNotificationCount, + numUnreadMentions = numUnreadMentions, + numUnreadMessages = numUnreadMessages, notificationMode = notificationMode, ) ) @@ -57,7 +59,8 @@ fun aRoomSummaryDetails( isDirect: Boolean = false, avatarUrl: String? = null, lastMessage: RoomMessage? = aRoomMessage(), - unreadNotificationCount: Int = 2, + numUnreadMentions: Int = 0, + numUnreadMessages: Int = 0, notificationMode: RoomNotificationMode? = null, inviter: RoomMember? = null, canonicalAlias: String? = null, @@ -69,7 +72,8 @@ fun aRoomSummaryDetails( isDirect = isDirect, avatarUrl = avatarUrl, lastMessage = lastMessage, - unreadNotificationCount = unreadNotificationCount, + numUnreadMentions = numUnreadMentions, + numUnreadMessages = numUnreadMessages, userDefinedNotificationMode = notificationMode, inviter = inviter, canonicalAlias = canonicalAlias, diff --git a/libraries/matrixui/src/main/kotlin/io/element/android/libraries/matrix/ui/components/SelectedRoom.kt b/libraries/matrixui/src/main/kotlin/io/element/android/libraries/matrix/ui/components/SelectedRoom.kt index c47fdbdf64..734f7eef1f 100644 --- a/libraries/matrixui/src/main/kotlin/io/element/android/libraries/matrix/ui/components/SelectedRoom.kt +++ b/libraries/matrixui/src/main/kotlin/io/element/android/libraries/matrix/ui/components/SelectedRoom.kt @@ -113,7 +113,8 @@ fun aRoomSummaryDetails( notificationMode: RoomNotificationMode? = null, hasRoomCall: Boolean = false, isDm: Boolean = false, - unreadNotificationCount: Int = 0 + numUnreadMentions: Int = 0, + numUnreadMessages: Int = 0, ) = RoomSummaryDetails( roomId = roomId, name = name, @@ -125,5 +126,6 @@ fun aRoomSummaryDetails( userDefinedNotificationMode = notificationMode, hasRoomCall = hasRoomCall, isDm = isDm, - unreadNotificationCount = unreadNotificationCount, + numUnreadMentions = numUnreadMentions, + numUnreadMessages = numUnreadMessages, ) From 7a201e310cf7f382c023c94f1e6e180a120f5ba5 Mon Sep 17 00:00:00 2001 From: ElementBot Date: Mon, 22 Jan 2024 14:56:56 +0000 Subject: [PATCH 061/127] Update screenshots --- ...ow_null_RoomSummaryRow-Day-9_10_null_0,NEXUS_5,1.0,en].png | 4 ++-- ...ow_null_RoomSummaryRow-Day-9_10_null_1,NEXUS_5,1.0,en].png | 4 ++-- ...w_null_RoomSummaryRow-Day-9_10_null_10,NEXUS_5,1.0,en].png | 3 +++ ...w_null_RoomSummaryRow-Day-9_10_null_11,NEXUS_5,1.0,en].png | 3 +++ ...w_null_RoomSummaryRow-Day-9_10_null_12,NEXUS_5,1.0,en].png | 3 +++ ...w_null_RoomSummaryRow-Day-9_10_null_13,NEXUS_5,1.0,en].png | 3 +++ ...w_null_RoomSummaryRow-Day-9_10_null_14,NEXUS_5,1.0,en].png | 3 +++ ...w_null_RoomSummaryRow-Day-9_10_null_15,NEXUS_5,1.0,en].png | 3 +++ ...w_null_RoomSummaryRow-Day-9_10_null_16,NEXUS_5,1.0,en].png | 3 +++ ...w_null_RoomSummaryRow-Day-9_10_null_17,NEXUS_5,1.0,en].png | 3 +++ ...w_null_RoomSummaryRow-Day-9_10_null_18,NEXUS_5,1.0,en].png | 3 +++ ...w_null_RoomSummaryRow-Day-9_10_null_19,NEXUS_5,1.0,en].png | 3 +++ ...ow_null_RoomSummaryRow-Day-9_10_null_2,NEXUS_5,1.0,en].png | 4 ++-- ...w_null_RoomSummaryRow-Day-9_10_null_20,NEXUS_5,1.0,en].png | 3 +++ ...w_null_RoomSummaryRow-Day-9_10_null_21,NEXUS_5,1.0,en].png | 3 +++ ...w_null_RoomSummaryRow-Day-9_10_null_22,NEXUS_5,1.0,en].png | 3 +++ ...w_null_RoomSummaryRow-Day-9_10_null_23,NEXUS_5,1.0,en].png | 3 +++ ...w_null_RoomSummaryRow-Day-9_10_null_24,NEXUS_5,1.0,en].png | 3 +++ ...w_null_RoomSummaryRow-Day-9_10_null_25,NEXUS_5,1.0,en].png | 3 +++ ...w_null_RoomSummaryRow-Day-9_10_null_26,NEXUS_5,1.0,en].png | 3 +++ ...w_null_RoomSummaryRow-Day-9_10_null_27,NEXUS_5,1.0,en].png | 3 +++ ...ow_null_RoomSummaryRow-Day-9_10_null_3,NEXUS_5,1.0,en].png | 4 ++-- ...ow_null_RoomSummaryRow-Day-9_10_null_4,NEXUS_5,1.0,en].png | 4 ++-- ...ow_null_RoomSummaryRow-Day-9_10_null_5,NEXUS_5,1.0,en].png | 4 ++-- ...ow_null_RoomSummaryRow-Day-9_10_null_6,NEXUS_5,1.0,en].png | 4 ++-- ...ow_null_RoomSummaryRow-Day-9_10_null_7,NEXUS_5,1.0,en].png | 4 ++-- ...ow_null_RoomSummaryRow-Day-9_10_null_8,NEXUS_5,1.0,en].png | 4 ++-- ...ow_null_RoomSummaryRow-Day-9_10_null_9,NEXUS_5,1.0,en].png | 3 +++ ..._null_RoomSummaryRow-Night-9_11_null_0,NEXUS_5,1.0,en].png | 4 ++-- ..._null_RoomSummaryRow-Night-9_11_null_1,NEXUS_5,1.0,en].png | 4 ++-- ...null_RoomSummaryRow-Night-9_11_null_10,NEXUS_5,1.0,en].png | 3 +++ ...null_RoomSummaryRow-Night-9_11_null_11,NEXUS_5,1.0,en].png | 3 +++ ...null_RoomSummaryRow-Night-9_11_null_12,NEXUS_5,1.0,en].png | 3 +++ ...null_RoomSummaryRow-Night-9_11_null_13,NEXUS_5,1.0,en].png | 3 +++ ...null_RoomSummaryRow-Night-9_11_null_14,NEXUS_5,1.0,en].png | 3 +++ ...null_RoomSummaryRow-Night-9_11_null_15,NEXUS_5,1.0,en].png | 3 +++ ...null_RoomSummaryRow-Night-9_11_null_16,NEXUS_5,1.0,en].png | 3 +++ ...null_RoomSummaryRow-Night-9_11_null_17,NEXUS_5,1.0,en].png | 3 +++ ...null_RoomSummaryRow-Night-9_11_null_18,NEXUS_5,1.0,en].png | 3 +++ ...null_RoomSummaryRow-Night-9_11_null_19,NEXUS_5,1.0,en].png | 3 +++ ..._null_RoomSummaryRow-Night-9_11_null_2,NEXUS_5,1.0,en].png | 4 ++-- ...null_RoomSummaryRow-Night-9_11_null_20,NEXUS_5,1.0,en].png | 3 +++ ...null_RoomSummaryRow-Night-9_11_null_21,NEXUS_5,1.0,en].png | 3 +++ ...null_RoomSummaryRow-Night-9_11_null_22,NEXUS_5,1.0,en].png | 3 +++ ...null_RoomSummaryRow-Night-9_11_null_23,NEXUS_5,1.0,en].png | 3 +++ ...null_RoomSummaryRow-Night-9_11_null_24,NEXUS_5,1.0,en].png | 3 +++ ...null_RoomSummaryRow-Night-9_11_null_25,NEXUS_5,1.0,en].png | 3 +++ ...null_RoomSummaryRow-Night-9_11_null_26,NEXUS_5,1.0,en].png | 3 +++ ...null_RoomSummaryRow-Night-9_11_null_27,NEXUS_5,1.0,en].png | 3 +++ ..._null_RoomSummaryRow-Night-9_11_null_3,NEXUS_5,1.0,en].png | 4 ++-- ..._null_RoomSummaryRow-Night-9_11_null_4,NEXUS_5,1.0,en].png | 4 ++-- ..._null_RoomSummaryRow-Night-9_11_null_5,NEXUS_5,1.0,en].png | 4 ++-- ..._null_RoomSummaryRow-Night-9_11_null_6,NEXUS_5,1.0,en].png | 4 ++-- ..._null_RoomSummaryRow-Night-9_11_null_7,NEXUS_5,1.0,en].png | 4 ++-- ..._null_RoomSummaryRow-Night-9_11_null_8,NEXUS_5,1.0,en].png | 4 ++-- ..._null_RoomSummaryRow-Night-9_11_null_9,NEXUS_5,1.0,en].png | 3 +++ 56 files changed, 150 insertions(+), 36 deletions(-) create mode 100644 tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Day-9_10_null_10,NEXUS_5,1.0,en].png create mode 100644 tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Day-9_10_null_11,NEXUS_5,1.0,en].png create mode 100644 tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Day-9_10_null_12,NEXUS_5,1.0,en].png create mode 100644 tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Day-9_10_null_13,NEXUS_5,1.0,en].png create mode 100644 tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Day-9_10_null_14,NEXUS_5,1.0,en].png create mode 100644 tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Day-9_10_null_15,NEXUS_5,1.0,en].png create mode 100644 tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Day-9_10_null_16,NEXUS_5,1.0,en].png create mode 100644 tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Day-9_10_null_17,NEXUS_5,1.0,en].png create mode 100644 tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Day-9_10_null_18,NEXUS_5,1.0,en].png create mode 100644 tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Day-9_10_null_19,NEXUS_5,1.0,en].png create mode 100644 tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Day-9_10_null_20,NEXUS_5,1.0,en].png create mode 100644 tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Day-9_10_null_21,NEXUS_5,1.0,en].png create mode 100644 tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Day-9_10_null_22,NEXUS_5,1.0,en].png create mode 100644 tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Day-9_10_null_23,NEXUS_5,1.0,en].png create mode 100644 tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Day-9_10_null_24,NEXUS_5,1.0,en].png create mode 100644 tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Day-9_10_null_25,NEXUS_5,1.0,en].png create mode 100644 tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Day-9_10_null_26,NEXUS_5,1.0,en].png create mode 100644 tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Day-9_10_null_27,NEXUS_5,1.0,en].png create mode 100644 tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Day-9_10_null_9,NEXUS_5,1.0,en].png create mode 100644 tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Night-9_11_null_10,NEXUS_5,1.0,en].png create mode 100644 tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Night-9_11_null_11,NEXUS_5,1.0,en].png create mode 100644 tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Night-9_11_null_12,NEXUS_5,1.0,en].png create mode 100644 tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Night-9_11_null_13,NEXUS_5,1.0,en].png create mode 100644 tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Night-9_11_null_14,NEXUS_5,1.0,en].png create mode 100644 tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Night-9_11_null_15,NEXUS_5,1.0,en].png create mode 100644 tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Night-9_11_null_16,NEXUS_5,1.0,en].png create mode 100644 tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Night-9_11_null_17,NEXUS_5,1.0,en].png create mode 100644 tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Night-9_11_null_18,NEXUS_5,1.0,en].png create mode 100644 tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Night-9_11_null_19,NEXUS_5,1.0,en].png create mode 100644 tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Night-9_11_null_20,NEXUS_5,1.0,en].png create mode 100644 tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Night-9_11_null_21,NEXUS_5,1.0,en].png create mode 100644 tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Night-9_11_null_22,NEXUS_5,1.0,en].png create mode 100644 tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Night-9_11_null_23,NEXUS_5,1.0,en].png create mode 100644 tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Night-9_11_null_24,NEXUS_5,1.0,en].png create mode 100644 tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Night-9_11_null_25,NEXUS_5,1.0,en].png create mode 100644 tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Night-9_11_null_26,NEXUS_5,1.0,en].png create mode 100644 tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Night-9_11_null_27,NEXUS_5,1.0,en].png create mode 100644 tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Night-9_11_null_9,NEXUS_5,1.0,en].png diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Day-9_10_null_0,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Day-9_10_null_0,NEXUS_5,1.0,en].png index ded89c6b2a..6bfb7eeabe 100644 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Day-9_10_null_0,NEXUS_5,1.0,en].png +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Day-9_10_null_0,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:57e0c90fa627974aba0d62363906bcc7911a6ada7d9d7db00db0df1d51fed54c -size 12911 +oid sha256:c978bc799ab79290f89568de692d3ace219a4192ec9706fef63fe977a853f74d +size 6046 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Day-9_10_null_1,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Day-9_10_null_1,NEXUS_5,1.0,en].png index 94306b9d92..ded89c6b2a 100644 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Day-9_10_null_1,NEXUS_5,1.0,en].png +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Day-9_10_null_1,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:fcf2f25bbcb2f43d70a8a3228ba97426dbb98b533b74dd13ef6459f96a711db5 -size 8877 +oid sha256:57e0c90fa627974aba0d62363906bcc7911a6ada7d9d7db00db0df1d51fed54c +size 12911 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Day-9_10_null_10,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Day-9_10_null_10,NEXUS_5,1.0,en].png new file mode 100644 index 0000000000..f0c758b53a --- /dev/null +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Day-9_10_null_10,NEXUS_5,1.0,en].png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:a3596d2a24536c5b0614e80f2f69024edacff71c654e50b59b68948d4413a17d +size 19155 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Day-9_10_null_11,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Day-9_10_null_11,NEXUS_5,1.0,en].png new file mode 100644 index 0000000000..bc3ac24996 --- /dev/null +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Day-9_10_null_11,NEXUS_5,1.0,en].png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:ce723333b1cac9ea41ef93b92a6bcc0d2fa5eec1344308da18f5103b00216c1b +size 17412 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Day-9_10_null_12,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Day-9_10_null_12,NEXUS_5,1.0,en].png new file mode 100644 index 0000000000..7b2586a782 --- /dev/null +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Day-9_10_null_12,NEXUS_5,1.0,en].png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:5abb560a12f1641ae93423fe88c9b1c9f68414c67b529c72d44f260817f00eb2 +size 11888 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Day-9_10_null_13,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Day-9_10_null_13,NEXUS_5,1.0,en].png new file mode 100644 index 0000000000..d616106e20 --- /dev/null +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Day-9_10_null_13,NEXUS_5,1.0,en].png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:12456705abcc0f7efb351a97880d9b0f1cbba9723b74723ff264925004621efd +size 12986 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Day-9_10_null_14,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Day-9_10_null_14,NEXUS_5,1.0,en].png new file mode 100644 index 0000000000..2bcb59f874 --- /dev/null +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Day-9_10_null_14,NEXUS_5,1.0,en].png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:d1cdaa0f4b68c50902eb631789aec93d7f0a5c2570a2230827a55a03f1eb52f3 +size 14345 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Day-9_10_null_15,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Day-9_10_null_15,NEXUS_5,1.0,en].png new file mode 100644 index 0000000000..8402f2f222 --- /dev/null +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Day-9_10_null_15,NEXUS_5,1.0,en].png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:f58bf26b7f82401f557b4948abda9202be478058280d7af8fdf0cc917dbe123f +size 12585 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Day-9_10_null_16,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Day-9_10_null_16,NEXUS_5,1.0,en].png new file mode 100644 index 0000000000..ac8f73cb15 --- /dev/null +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Day-9_10_null_16,NEXUS_5,1.0,en].png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:aed38a22a1d3a481d07c6955cc14f2a81ed27d754fb0701113d5ec5b6bb85015 +size 14461 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Day-9_10_null_17,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Day-9_10_null_17,NEXUS_5,1.0,en].png new file mode 100644 index 0000000000..cc9c93bf90 --- /dev/null +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Day-9_10_null_17,NEXUS_5,1.0,en].png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:b8194ccafe6f78cb90bbe1d1291a8b04463e57e9fe0a891adb3d1a95cb7b91a9 +size 15652 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Day-9_10_null_18,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Day-9_10_null_18,NEXUS_5,1.0,en].png new file mode 100644 index 0000000000..7ffb8bec52 --- /dev/null +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Day-9_10_null_18,NEXUS_5,1.0,en].png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:ae38bd0b9effd780670034bd0f0d18d686b566be684fbe1a19d5641d9ecbc5e4 +size 17931 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Day-9_10_null_19,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Day-9_10_null_19,NEXUS_5,1.0,en].png new file mode 100644 index 0000000000..87025e3b6e --- /dev/null +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Day-9_10_null_19,NEXUS_5,1.0,en].png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:91a5a604bf078e6dc1a4161ed00c779ecec5cd0ac01283d38ea201a9bce9207b +size 15999 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Day-9_10_null_2,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Day-9_10_null_2,NEXUS_5,1.0,en].png index 12df0ea671..94306b9d92 100644 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Day-9_10_null_2,NEXUS_5,1.0,en].png +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Day-9_10_null_2,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:d1d8c374c7c3f8ad66b3936e8eda3161a93281aa3107027516ab671958f10980 -size 14187 +oid sha256:fcf2f25bbcb2f43d70a8a3228ba97426dbb98b533b74dd13ef6459f96a711db5 +size 8877 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Day-9_10_null_20,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Day-9_10_null_20,NEXUS_5,1.0,en].png new file mode 100644 index 0000000000..585b47b72a --- /dev/null +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Day-9_10_null_20,NEXUS_5,1.0,en].png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:f9b6e33a825b4fb6379827a9ec28f586e64d05aaf013d8120eccdafa178f6816 +size 16714 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Day-9_10_null_21,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Day-9_10_null_21,NEXUS_5,1.0,en].png new file mode 100644 index 0000000000..62735b485b --- /dev/null +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Day-9_10_null_21,NEXUS_5,1.0,en].png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:229fbadc49f0ef62434e9f26e7f31f1f94037a358dfc218b552046978ca3a182 +size 17874 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Day-9_10_null_22,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Day-9_10_null_22,NEXUS_5,1.0,en].png new file mode 100644 index 0000000000..ada41882c5 --- /dev/null +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Day-9_10_null_22,NEXUS_5,1.0,en].png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:9541c448d629db2715864652c16f6de0dd8537ab5be95df3410f139615156efe +size 20117 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Day-9_10_null_23,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Day-9_10_null_23,NEXUS_5,1.0,en].png new file mode 100644 index 0000000000..43b49ae924 --- /dev/null +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Day-9_10_null_23,NEXUS_5,1.0,en].png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:df7e4e982ca275e9318673bb05d5eff0f0c3f4c696cb951faa78ef68fabf0f6e +size 18233 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Day-9_10_null_24,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Day-9_10_null_24,NEXUS_5,1.0,en].png new file mode 100644 index 0000000000..e6bb8b58c1 --- /dev/null +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Day-9_10_null_24,NEXUS_5,1.0,en].png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:3951f02f9f2cc0ba1907363ba7fdf1150260b5add22be95d7bea94ec0c52f31e +size 12841 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Day-9_10_null_25,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Day-9_10_null_25,NEXUS_5,1.0,en].png new file mode 100644 index 0000000000..89f803773a --- /dev/null +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Day-9_10_null_25,NEXUS_5,1.0,en].png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:324024fbe1bf52291a0352859742d630f688becaed00c3c1eeab4ef96f436d63 +size 13943 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Day-9_10_null_26,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Day-9_10_null_26,NEXUS_5,1.0,en].png new file mode 100644 index 0000000000..a6e71a4e57 --- /dev/null +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Day-9_10_null_26,NEXUS_5,1.0,en].png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:1b6cc4f49d6440ea9ae146ff816ea7ac649a6880924a7be82b2823b1064ce285 +size 15454 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Day-9_10_null_27,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Day-9_10_null_27,NEXUS_5,1.0,en].png new file mode 100644 index 0000000000..2253b1ae8a --- /dev/null +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Day-9_10_null_27,NEXUS_5,1.0,en].png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:2b3e39f3c7e6606d340bf4462d18f9b4e5329b1e845beb6a4a3d0c1a1dabe5b2 +size 13521 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Day-9_10_null_3,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Day-9_10_null_3,NEXUS_5,1.0,en].png index 0af38a4878..ae1e098362 100644 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Day-9_10_null_3,NEXUS_5,1.0,en].png +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Day-9_10_null_3,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:352b75021319958e86affa3d44c38cf72151d32796d70a0920ef63d73984ad72 -size 13627 +oid sha256:a1dfe518ad4ee77539f017a39c684e0ce7bfb733a33161639fdf606a188b13d0 +size 22406 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Day-9_10_null_4,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Day-9_10_null_4,NEXUS_5,1.0,en].png index ea9b3053bf..1dd2438d7f 100644 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Day-9_10_null_4,NEXUS_5,1.0,en].png +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Day-9_10_null_4,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:14e33bc8286952b7608adfa9864a1649c817992d35e9e0de8edc9957b8f4a6c6 -size 13388 +oid sha256:d5e32fab6c9f6500bf523a18d10464a7b703649c80e6f1c56bc124cadbd2d248 +size 13512 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Day-9_10_null_5,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Day-9_10_null_5,NEXUS_5,1.0,en].png index 356b3a6d1e..004868ed67 100644 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Day-9_10_null_5,NEXUS_5,1.0,en].png +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Day-9_10_null_5,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:d8442308cab3c75f64559bcd67dc39ce6d95a546ae33a7eb885c775349ab36f5 -size 13378 +oid sha256:176f15fb96c05d5932708c9eb26a98261540f07fa4204a416b67baa2388993e5 +size 14775 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Day-9_10_null_6,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Day-9_10_null_6,NEXUS_5,1.0,en].png index 6bfb7eeabe..2cf2e92f08 100644 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Day-9_10_null_6,NEXUS_5,1.0,en].png +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Day-9_10_null_6,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:c978bc799ab79290f89568de692d3ace219a4192ec9706fef63fe977a853f74d -size 6046 +oid sha256:275649c8aceae86b0ab6ef633dc3bb9533d443a1ab3125fc16d8a288cdd8e8dc +size 16937 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Day-9_10_null_7,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Day-9_10_null_7,NEXUS_5,1.0,en].png index ae1e098362..14f9e6a3dd 100644 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Day-9_10_null_7,NEXUS_5,1.0,en].png +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Day-9_10_null_7,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:a1dfe518ad4ee77539f017a39c684e0ce7bfb733a33161639fdf606a188b13d0 -size 22406 +oid sha256:72aa257540b31b448e5eb57610c0d62422bc1d40c2abbdb41da99d6244a316c3 +size 15172 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Day-9_10_null_8,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Day-9_10_null_8,NEXUS_5,1.0,en].png index fcf6f86a3e..c680a1430a 100644 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Day-9_10_null_8,NEXUS_5,1.0,en].png +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Day-9_10_null_8,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:b044aa278ad070f75ffcf3d0d895c93bd784eb9c3e19e6aa842bbc1170bc92b4 -size 13688 +oid sha256:eaa409bac7f41b101207542e7be42b3caacd3039f6918dd1bb1df3105dffa1e0 +size 15747 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Day-9_10_null_9,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Day-9_10_null_9,NEXUS_5,1.0,en].png new file mode 100644 index 0000000000..ce0baeb017 --- /dev/null +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Day-9_10_null_9,NEXUS_5,1.0,en].png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:efa3edb3d8f7f071e4b622c4d5dda9ec86741b468c734caffd1b6463294038bb +size 16882 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Night-9_11_null_0,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Night-9_11_null_0,NEXUS_5,1.0,en].png index d83d063b86..6ab88c6759 100644 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Night-9_11_null_0,NEXUS_5,1.0,en].png +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Night-9_11_null_0,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:1d914ad609cda9e94ba793027c17f3b7289fec71e65e1880b837615203f7718e -size 12907 +oid sha256:144decfd898287f548035c89c264eb5f380084bfe69328a115b8c42cda5282f7 +size 5963 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Night-9_11_null_1,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Night-9_11_null_1,NEXUS_5,1.0,en].png index d93b2c752f..d83d063b86 100644 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Night-9_11_null_1,NEXUS_5,1.0,en].png +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Night-9_11_null_1,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:e05f294579b4420e6671f268d10fae8fb49e93e5ae5b0f0d4548f7cdfeb82742 -size 8928 +oid sha256:1d914ad609cda9e94ba793027c17f3b7289fec71e65e1880b837615203f7718e +size 12907 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Night-9_11_null_10,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Night-9_11_null_10,NEXUS_5,1.0,en].png new file mode 100644 index 0000000000..cea81a1d64 --- /dev/null +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Night-9_11_null_10,NEXUS_5,1.0,en].png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:33eb8815da0c19c454c8af842ff28cf244d2d09bf32af3789f0e9b52a01cc826 +size 18407 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Night-9_11_null_11,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Night-9_11_null_11,NEXUS_5,1.0,en].png new file mode 100644 index 0000000000..be0b0c5319 --- /dev/null +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Night-9_11_null_11,NEXUS_5,1.0,en].png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:313d37ec6776cbde514c152a3192e001a72f0174eddd728fef5e24b26c0a040e +size 16713 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Night-9_11_null_12,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Night-9_11_null_12,NEXUS_5,1.0,en].png new file mode 100644 index 0000000000..fae7083462 --- /dev/null +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Night-9_11_null_12,NEXUS_5,1.0,en].png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:ab320b11e312301da35a906ff9e8591adbd2dde19364fbecc6b16200e43a5a58 +size 11891 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Night-9_11_null_13,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Night-9_11_null_13,NEXUS_5,1.0,en].png new file mode 100644 index 0000000000..39e135705f --- /dev/null +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Night-9_11_null_13,NEXUS_5,1.0,en].png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:4c169aba4adcfd8a6e4680f9ccfc463ce80f6f3e6380e09a66eb0effb5a93a8d +size 12982 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Night-9_11_null_14,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Night-9_11_null_14,NEXUS_5,1.0,en].png new file mode 100644 index 0000000000..ae6ef1502a --- /dev/null +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Night-9_11_null_14,NEXUS_5,1.0,en].png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:c11af6c23854ce64d42a922979ea3d19edcd6051601a130aa2d7924dbe45506f +size 14280 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Night-9_11_null_15,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Night-9_11_null_15,NEXUS_5,1.0,en].png new file mode 100644 index 0000000000..5c79bad901 --- /dev/null +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Night-9_11_null_15,NEXUS_5,1.0,en].png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:4332d3590b7961cb28a7e6b586aed182babf31f585e129f0b7a7c901bf321a61 +size 12557 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Night-9_11_null_16,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Night-9_11_null_16,NEXUS_5,1.0,en].png new file mode 100644 index 0000000000..df70b73967 --- /dev/null +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Night-9_11_null_16,NEXUS_5,1.0,en].png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:0f59a1489dc39a6b9fdb3c90a17eb2d604d3f9a422827fe30b6e3251a6a5e54f +size 14131 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Night-9_11_null_17,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Night-9_11_null_17,NEXUS_5,1.0,en].png new file mode 100644 index 0000000000..695a5a0908 --- /dev/null +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Night-9_11_null_17,NEXUS_5,1.0,en].png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:f5d8aa34aaebac1defbc0a78aef1f45635e68b58390639d9e8ddaff1e8c95647 +size 15261 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Night-9_11_null_18,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Night-9_11_null_18,NEXUS_5,1.0,en].png new file mode 100644 index 0000000000..3c38a5e87a --- /dev/null +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Night-9_11_null_18,NEXUS_5,1.0,en].png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:40157d0455ad2e5124bb074106dcaacaa374a4275dd905d6a4c3def3c296a83f +size 17364 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Night-9_11_null_19,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Night-9_11_null_19,NEXUS_5,1.0,en].png new file mode 100644 index 0000000000..de444fa94a --- /dev/null +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Night-9_11_null_19,NEXUS_5,1.0,en].png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:3be9552a7539343fdefc0e5d090cbd1e6438b4821ca0949d542b94a7e2ab7165 +size 15509 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Night-9_11_null_2,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Night-9_11_null_2,NEXUS_5,1.0,en].png index 904b3a0b95..d93b2c752f 100644 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Night-9_11_null_2,NEXUS_5,1.0,en].png +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Night-9_11_null_2,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:4fcbb393a93d6a04e0415d2bb7bed4c002ec82907fbccf6070a4880a6b208e3c -size 13942 +oid sha256:e05f294579b4420e6671f268d10fae8fb49e93e5ae5b0f0d4548f7cdfeb82742 +size 8928 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Night-9_11_null_20,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Night-9_11_null_20,NEXUS_5,1.0,en].png new file mode 100644 index 0000000000..d34599fe58 --- /dev/null +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Night-9_11_null_20,NEXUS_5,1.0,en].png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:4aae70caf5fda4fce4f014d1526456e33da65b8221fa81998d69ba675f1a478d +size 16163 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Night-9_11_null_21,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Night-9_11_null_21,NEXUS_5,1.0,en].png new file mode 100644 index 0000000000..bec68b016d --- /dev/null +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Night-9_11_null_21,NEXUS_5,1.0,en].png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:17419657995b619a72322d54fb148f9ddf689016f2fb0fc385aeaa9d6114d81c +size 17233 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Night-9_11_null_22,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Night-9_11_null_22,NEXUS_5,1.0,en].png new file mode 100644 index 0000000000..1ccdd46786 --- /dev/null +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Night-9_11_null_22,NEXUS_5,1.0,en].png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:8c44cdfed89219f67b44b33466c06299c1974c3fce567d9e0ae74cfdb0e4fbeb +size 19365 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Night-9_11_null_23,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Night-9_11_null_23,NEXUS_5,1.0,en].png new file mode 100644 index 0000000000..ae73549b4a --- /dev/null +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Night-9_11_null_23,NEXUS_5,1.0,en].png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:5e8d9ad1a2a4c9f6ce4a9c57e9628e2759e00cf7ae51a8266e769254a5bdb1b5 +size 17511 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Night-9_11_null_24,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Night-9_11_null_24,NEXUS_5,1.0,en].png new file mode 100644 index 0000000000..5389529e8a --- /dev/null +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Night-9_11_null_24,NEXUS_5,1.0,en].png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:288c85268c3383d5daaa6d45ee8060ca74330e284b5ef807a1cca7706284daf9 +size 12686 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Night-9_11_null_25,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Night-9_11_null_25,NEXUS_5,1.0,en].png new file mode 100644 index 0000000000..7562af3e65 --- /dev/null +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Night-9_11_null_25,NEXUS_5,1.0,en].png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:63d8fe9ff875a9e7223af0c0acfbdc025600580c5a43144bcc650bfc6bc0b696 +size 13797 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Night-9_11_null_26,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Night-9_11_null_26,NEXUS_5,1.0,en].png new file mode 100644 index 0000000000..d9eb1328ad --- /dev/null +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Night-9_11_null_26,NEXUS_5,1.0,en].png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:5dda78f4088b9201f0600a06a35d44ca6d407551aeea538392c8a38e9e6fb16e +size 15234 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Night-9_11_null_27,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Night-9_11_null_27,NEXUS_5,1.0,en].png new file mode 100644 index 0000000000..57931f091f --- /dev/null +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Night-9_11_null_27,NEXUS_5,1.0,en].png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:b6414b6557672508d6bdabe2b40d547b25ef9a73566241e98bc12500b4cf7234 +size 13370 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Night-9_11_null_3,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Night-9_11_null_3,NEXUS_5,1.0,en].png index 3b2e01f9b5..0f0d5353fb 100644 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Night-9_11_null_3,NEXUS_5,1.0,en].png +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Night-9_11_null_3,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:811d95287c12d59fa1014b62ac8ae755f6355dbbd0700c2adc331293adfcc7a4 -size 13535 +oid sha256:b5f274b1ad4ca31aaf585d34ce48c2898fbb9ada8294b211fe1440a097da21f6 +size 21626 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Night-9_11_null_4,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Night-9_11_null_4,NEXUS_5,1.0,en].png index 7c71f03c1b..1288669d86 100644 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Night-9_11_null_4,NEXUS_5,1.0,en].png +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Night-9_11_null_4,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:435737296b59d70210fc93ba70d2fa228ba4bab645fb9a6366609197a97f87c0 -size 13305 +oid sha256:ca84726aa42db2d961b328d3ba34523f783f215fed36d049da1cf8a503d0dca7 +size 13304 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Night-9_11_null_5,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Night-9_11_null_5,NEXUS_5,1.0,en].png index 4e88d5c639..3af269b8f6 100644 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Night-9_11_null_5,NEXUS_5,1.0,en].png +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Night-9_11_null_5,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:d5a2d15ec2b36255963bc2514df0ff2dc8588c177d06c5431ca457af4de916e6 -size 13210 +oid sha256:9e13796d33e2ae08bdf7e1b9cc3ae4216e4a4d86054b8172d7054f8758232f03 +size 14406 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Night-9_11_null_6,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Night-9_11_null_6,NEXUS_5,1.0,en].png index 6ab88c6759..ec77c36679 100644 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Night-9_11_null_6,NEXUS_5,1.0,en].png +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Night-9_11_null_6,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:144decfd898287f548035c89c264eb5f380084bfe69328a115b8c42cda5282f7 -size 5963 +oid sha256:f5b24a09682a6e23f9fb5ae95bf61a76b2ac711dcb6e61485a3a0de0766062f9 +size 16423 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Night-9_11_null_7,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Night-9_11_null_7,NEXUS_5,1.0,en].png index 0f0d5353fb..d134f4b746 100644 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Night-9_11_null_7,NEXUS_5,1.0,en].png +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Night-9_11_null_7,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:b5f274b1ad4ca31aaf585d34ce48c2898fbb9ada8294b211fe1440a097da21f6 -size 21626 +oid sha256:a839e11d5f481cdc3973ee1a863badf44df39cd3c20571e9e475800bff726913 +size 14714 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Night-9_11_null_8,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Night-9_11_null_8,NEXUS_5,1.0,en].png index 2e19344be7..a25e42f8de 100644 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Night-9_11_null_8,NEXUS_5,1.0,en].png +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Night-9_11_null_8,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:a13837fffa77d7f95d6f4f163fb2e674070777caf02cce74b6a52e91f3103224 -size 13500 +oid sha256:0ff91c8812358efc55693fb855aa1c7bb5f617ebbf6fad7f57ab5cbe3b8a6123 +size 15323 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Night-9_11_null_9,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Night-9_11_null_9,NEXUS_5,1.0,en].png new file mode 100644 index 0000000000..84e9bf7098 --- /dev/null +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Night-9_11_null_9,NEXUS_5,1.0,en].png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:6e7dd7bdb6bf394ae39f75cafc9d9424becb483d61140bbc11eb374eb0173bd5 +size 16402 From 18fba261e099073d9514845d7f0e2a451718ce65 Mon Sep 17 00:00:00 2001 From: Jorge Martin Espinosa Date: Mon, 22 Jan 2024 17:53:10 +0100 Subject: [PATCH 062/127] Edited text message bubbles should resize when edited (#2272) * Make `ContentAvoidingLayoutScopeInstance` scope aware so message bubbles are resized when edited. * Move back to using `Layout` instead of `SubcomposeLayout` --- changelog.d/2260.bugfix | 1 + .../layout/ContentAvoidingLayout.kt | 24 ++++++++++--------- 2 files changed, 14 insertions(+), 11 deletions(-) create mode 100644 changelog.d/2260.bugfix diff --git a/changelog.d/2260.bugfix b/changelog.d/2260.bugfix new file mode 100644 index 0000000000..23501e3264 --- /dev/null +++ b/changelog.d/2260.bugfix @@ -0,0 +1 @@ +Edited text message bubbles should resize when edited diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/layout/ContentAvoidingLayout.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/layout/ContentAvoidingLayout.kt index 5df38c1845..334899288d 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/layout/ContentAvoidingLayout.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/layout/ContentAvoidingLayout.kt @@ -18,10 +18,11 @@ package io.element.android.features.messages.impl.timeline.components.layout import android.text.Layout import androidx.compose.runtime.Composable +import androidx.compose.runtime.MutableState +import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.ui.Modifier import androidx.compose.ui.layout.Layout -import androidx.compose.ui.layout.SubcomposeLayout import androidx.compose.ui.platform.LocalLayoutDirection import androidx.compose.ui.text.TextLayoutResult import androidx.compose.ui.unit.Constraints @@ -59,23 +60,27 @@ fun ContentAvoidingLayout( ) { val scope = remember { ContentAvoidingLayoutScopeInstance() } - SubcomposeLayout( + Layout( modifier = modifier, - ) { constraints -> + content = { + scope.content() + overlay() + } + ) { measurables, constraints -> // Measure the `overlay` view first, in case we need to shrink the `content` - val overlayPlaceable = subcompose(0, overlay).first().measure(Constraints(minWidth = 0, maxWidth = constraints.maxWidth)) + val overlayPlaceable = measurables.last().measure(Constraints(minWidth = 0, maxWidth = constraints.maxWidth)) val contentConstraints = if (shrinkContent) { Constraints(minWidth = 0, maxWidth = constraints.maxWidth - overlayPlaceable.width) } else { Constraints(minWidth = 0, maxWidth = constraints.maxWidth) } - val contentPlaceable = subcompose(1) { scope.content() }.first().measure(contentConstraints) + val contentPlaceable = measurables.first().measure(contentConstraints) var layoutWidth = contentPlaceable.width var layoutHeight = contentPlaceable.height - val data = scope.data + val data = scope.data.value // Free space = width of the whole component - width of its non overlapping contents val freeSpace = max(contentPlaceable.width - data.nonOverlappingContentWidth, 0) @@ -135,13 +140,10 @@ interface ContentAvoidingLayoutScope { } private class ContentAvoidingLayoutScopeInstance( - val data: ContentAvoidingLayoutData = ContentAvoidingLayoutData(), + val data: MutableState = mutableStateOf(ContentAvoidingLayoutData()), ) : ContentAvoidingLayoutScope { override fun onContentLayoutChanged(data: ContentAvoidingLayoutData) { - this.data.contentWidth = data.contentWidth - this.data.contentHeight = data.contentHeight - this.data.nonOverlappingContentWidth = data.nonOverlappingContentWidth - this.data.nonOverlappingContentHeight = data.nonOverlappingContentHeight + this.data.value = data } } From 958e97f89c58a251954429e776c48ad0c649809e Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Tue, 23 Jan 2024 11:18:39 +0100 Subject: [PATCH 063/127] Make `isTimestampHighlighted` a computed val. --- .../features/roomlist/impl/components/RoomSummaryRow.kt | 3 +-- .../features/roomlist/impl/model/RoomListRoomSummary.kt | 6 ++---- 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/features/roomlist/impl/src/main/kotlin/io/element/android/features/roomlist/impl/components/RoomSummaryRow.kt b/features/roomlist/impl/src/main/kotlin/io/element/android/features/roomlist/impl/components/RoomSummaryRow.kt index dd16a281c2..65e5490aa6 100644 --- a/features/roomlist/impl/src/main/kotlin/io/element/android/features/roomlist/impl/components/RoomSummaryRow.kt +++ b/features/roomlist/impl/src/main/kotlin/io/element/android/features/roomlist/impl/components/RoomSummaryRow.kt @@ -43,7 +43,6 @@ import io.element.android.compound.theme.ElementTheme import io.element.android.compound.tokens.generated.CompoundIcons import io.element.android.features.roomlist.impl.model.RoomListRoomSummary import io.element.android.features.roomlist.impl.model.RoomListRoomSummaryProvider -import io.element.android.features.roomlist.impl.model.isTimestampHighlighted import io.element.android.libraries.core.extensions.orEmpty import io.element.android.libraries.designsystem.atomic.atoms.UnreadIndicatorAtom import io.element.android.libraries.designsystem.components.avatar.Avatar @@ -142,7 +141,7 @@ private fun RowScope.NameAndTimestampRow(room: RoomListRoomSummary) { Text( text = room.timestamp ?: "", style = ElementTheme.typography.fontBodySmMedium, - color = if (room.isTimestampHighlighted()) { + color = if (room.isTimestampHighlighted) { ElementTheme.colors.unreadIndicator } else { MaterialTheme.roomListRoomMessageDate() diff --git a/features/roomlist/impl/src/main/kotlin/io/element/android/features/roomlist/impl/model/RoomListRoomSummary.kt b/features/roomlist/impl/src/main/kotlin/io/element/android/features/roomlist/impl/model/RoomListRoomSummary.kt index 0669be0031..e35680abc9 100644 --- a/features/roomlist/impl/src/main/kotlin/io/element/android/features/roomlist/impl/model/RoomListRoomSummary.kt +++ b/features/roomlist/impl/src/main/kotlin/io/element/android/features/roomlist/impl/model/RoomListRoomSummary.kt @@ -35,10 +35,8 @@ data class RoomListRoomSummary( val userDefinedNotificationMode: RoomNotificationMode?, val hasRoomCall: Boolean, val isDm: Boolean, -) - -fun RoomListRoomSummary.isTimestampHighlighted(): Boolean { - return hasRoomCall || +) { + val isTimestampHighlighted = hasRoomCall || when (userDefinedNotificationMode) { null, RoomNotificationMode.ALL_MESSAGES -> numberOfUnreadMessages > 0 || numberOfUnreadMentions > 0 From 71c29b6381ba01e61abea34b30c6998e7e8182b6 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 23 Jan 2024 11:14:03 +0000 Subject: [PATCH 064/127] Update dependency org.matrix.rustcomponents:sdk-android to v0.1.92 --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index eaa3da11b2..71d8e10d0b 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -153,7 +153,7 @@ jsoup = "org.jsoup:jsoup:1.17.2" appyx_core = { module = "com.bumble.appyx:core", version.ref = "appyx" } molecule-runtime = "app.cash.molecule:molecule-runtime:1.3.2" timber = "com.jakewharton.timber:timber:5.0.1" -matrix_sdk = "org.matrix.rustcomponents:sdk-android:0.1.84" +matrix_sdk = "org.matrix.rustcomponents:sdk-android:0.1.92" matrix_richtexteditor = { module = "io.element.android:wysiwyg", version.ref = "wysiwyg" } matrix_richtexteditor_compose = { module = "io.element.android:wysiwyg-compose", version.ref = "wysiwyg" } sqldelight-driver-android = { module = "app.cash.sqldelight:android-driver", version.ref = "sqldelight" } From ce7d77059c022f1b9eabd7eef29579af04fe1216 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Tue, 23 Jan 2024 12:28:23 +0100 Subject: [PATCH 065/127] Kotlin 1.9.22 --- .idea/kotlinc.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.idea/kotlinc.xml b/.idea/kotlinc.xml index ae3f30ae18..8d81632f83 100644 --- a/.idea/kotlinc.xml +++ b/.idea/kotlinc.xml @@ -1,6 +1,6 @@ - \ No newline at end of file From f8443990256345e87f91e7f4af5ef0783da235c1 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Tue, 23 Jan 2024 12:20:07 +0100 Subject: [PATCH 066/127] Fix API break: use new methods `canUserRedactOwn` and `canUserRedactOther`. --- .../messages/impl/MessagesPresenter.kt | 9 +- .../features/messages/impl/MessagesState.kt | 3 +- .../messages/impl/MessagesStateProvider.kt | 3 +- .../features/messages/impl/MessagesView.kt | 3 +- .../impl/actionlist/ActionListEvents.kt | 3 +- .../impl/actionlist/ActionListPresenter.kt | 17 +- .../messages/impl/MessagesPresenterTest.kt | 25 +- .../actionlist/ActionListPresenterTest.kt | 221 ++++++++++++++++-- .../libraries/matrix/api/room/MatrixRoom.kt | 4 +- .../room/powerlevels/MatrixRoomPowerLevels.kt | 9 +- .../matrix/impl/room/RustMatrixRoom.kt | 10 +- .../matrix/test/room/FakeMatrixRoom.kt | 14 +- .../matrix/ui/room/MatrixRoomState.kt | 14 +- 13 files changed, 286 insertions(+), 49 deletions(-) diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/MessagesPresenter.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/MessagesPresenter.kt index e40d0bbb9b..07eeda2efa 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/MessagesPresenter.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/MessagesPresenter.kt @@ -84,7 +84,8 @@ import io.element.android.libraries.matrix.api.room.MessageEventType import io.element.android.libraries.matrix.api.user.CurrentSessionIdHolder import io.element.android.libraries.matrix.ui.components.AttachmentThumbnailInfo import io.element.android.libraries.matrix.ui.components.AttachmentThumbnailType -import io.element.android.libraries.matrix.ui.room.canRedactAsState +import io.element.android.libraries.matrix.ui.room.canRedactOtherAsState +import io.element.android.libraries.matrix.ui.room.canRedactOwnAsState import io.element.android.libraries.matrix.ui.room.canSendMessageAsState import io.element.android.libraries.textcomposer.model.MessageComposerMode import kotlinx.coroutines.CoroutineScope @@ -138,7 +139,8 @@ class MessagesPresenter @AssistedInject constructor( val syncUpdateFlow = room.syncUpdateFlow.collectAsState() val userHasPermissionToSendMessage by room.canSendMessageAsState(type = MessageEventType.ROOM_MESSAGE, updateKey = syncUpdateFlow.value) - val userHasPermissionToRedact by room.canRedactAsState(updateKey = syncUpdateFlow.value) + val userHasPermissionToRedactOwn by room.canRedactOwnAsState(updateKey = syncUpdateFlow.value) + val userHasPermissionToRedactOther by room.canRedactOtherAsState(updateKey = syncUpdateFlow.value) val userHasPermissionToSendReaction by room.canSendMessageAsState(type = MessageEventType.REACTION_SENT, updateKey = syncUpdateFlow.value) val roomName: AsyncData by remember { derivedStateOf { roomInfo?.name?.let { AsyncData.Success(it) } ?: AsyncData.Uninitialized } @@ -219,7 +221,8 @@ class MessagesPresenter @AssistedInject constructor( roomName = roomName, roomAvatar = roomAvatar, userHasPermissionToSendMessage = userHasPermissionToSendMessage, - userHasPermissionToRedact = userHasPermissionToRedact, + userHasPermissionToRedactOwn = userHasPermissionToRedactOwn, + userHasPermissionToRedactOther = userHasPermissionToRedactOther, userHasPermissionToSendReaction = userHasPermissionToSendReaction, composerState = composerState, voiceMessageComposerState = voiceMessageComposerState, diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/MessagesState.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/MessagesState.kt index c196535607..8e4d1c484b 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/MessagesState.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/MessagesState.kt @@ -36,7 +36,8 @@ data class MessagesState( val roomName: AsyncData, val roomAvatar: AsyncData, val userHasPermissionToSendMessage: Boolean, - val userHasPermissionToRedact: Boolean, + val userHasPermissionToRedactOwn: Boolean, + val userHasPermissionToRedactOther: Boolean, val userHasPermissionToSendReaction: Boolean, val composerState: MessageComposerState, val voiceMessageComposerState: VoiceMessageComposerState, diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/MessagesStateProvider.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/MessagesStateProvider.kt index 8fc7466f95..1bb500e08f 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/MessagesStateProvider.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/MessagesStateProvider.kt @@ -86,7 +86,8 @@ fun aMessagesState() = MessagesState( roomName = AsyncData.Success("Room name"), roomAvatar = AsyncData.Success(AvatarData("!id:domain", "Room name", size = AvatarSize.TimelineRoom)), userHasPermissionToSendMessage = true, - userHasPermissionToRedact = false, + userHasPermissionToRedactOwn = false, + userHasPermissionToRedactOther = false, userHasPermissionToSendReaction = true, composerState = aMessageComposerState().copy( richTextEditorState = RichTextEditorState("Hello", initialFocus = true), diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/MessagesView.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/MessagesView.kt index 96af343a5a..394f1f3556 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/MessagesView.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/MessagesView.kt @@ -160,7 +160,8 @@ fun MessagesView( state.actionListState.eventSink( ActionListEvents.ComputeForMessage( event = event, - canRedact = state.userHasPermissionToRedact, + canRedactOwn = state.userHasPermissionToRedactOwn, + canRedactOther = state.userHasPermissionToRedactOther, canSendMessage = state.userHasPermissionToSendMessage, canSendReaction = state.userHasPermissionToSendReaction, ) diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/actionlist/ActionListEvents.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/actionlist/ActionListEvents.kt index 6339716ccf..e486c1ae2b 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/actionlist/ActionListEvents.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/actionlist/ActionListEvents.kt @@ -22,7 +22,8 @@ sealed interface ActionListEvents { data object Clear : ActionListEvents data class ComputeForMessage( val event: TimelineItem.Event, - val canRedact: Boolean, + val canRedactOwn: Boolean, + val canRedactOther: Boolean, val canSendMessage: Boolean, val canSendReaction: Boolean, ) : ActionListEvents diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/actionlist/ActionListPresenter.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/actionlist/ActionListPresenter.kt index 474a0cf022..bede5669fd 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/actionlist/ActionListPresenter.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/actionlist/ActionListPresenter.kt @@ -56,7 +56,8 @@ class ActionListPresenter @Inject constructor( ActionListEvents.Clear -> target.value = ActionListState.Target.None is ActionListEvents.ComputeForMessage -> localCoroutineScope.computeForMessage( timelineItem = event.event, - userCanRedact = event.canRedact, + userCanRedactOwn = event.canRedactOwn, + userCanRedactOther = event.canRedactOther, userCanSendMessage = event.canSendMessage, userCanSendReaction = event.canSendReaction, isDeveloperModeEnabled = isDeveloperModeEnabled, @@ -73,13 +74,16 @@ class ActionListPresenter @Inject constructor( private fun CoroutineScope.computeForMessage( timelineItem: TimelineItem.Event, - userCanRedact: Boolean, + userCanRedactOwn: Boolean, + userCanRedactOther: Boolean, userCanSendMessage: Boolean, userCanSendReaction: Boolean, isDeveloperModeEnabled: Boolean, target: MutableState ) = launch { target.value = ActionListState.Target.Loading(timelineItem) + val canRedact = (timelineItem.isMine && userCanRedactOwn) || + (!timelineItem.isMine && userCanRedactOther) val actions = when (timelineItem.content) { is TimelineItemRedactedContent -> { @@ -99,7 +103,6 @@ class ActionListPresenter @Inject constructor( } is TimelineItemPollContent -> { buildList { - val isMineOrCanRedact = timelineItem.isMine || userCanRedact if (timelineItem.isRemote) { // Can only reply or forward messages already uploaded to the server add(TimelineItemAction.Reply) @@ -107,7 +110,7 @@ class ActionListPresenter @Inject constructor( if (timelineItem.isRemote && timelineItem.isEditable) { add(TimelineItemAction.Edit) } - if (timelineItem.isRemote && !timelineItem.content.isEnded && isMineOrCanRedact) { + if (timelineItem.isRemote && !timelineItem.content.isEnded && (timelineItem.isMine || canRedact)) { add(TimelineItemAction.EndPoll) } if (timelineItem.content.canBeCopied()) { @@ -119,7 +122,7 @@ class ActionListPresenter @Inject constructor( if (!timelineItem.isMine) { add(TimelineItemAction.ReportContent) } - if (isMineOrCanRedact) { + if (canRedact) { add(TimelineItemAction.Redact) } } @@ -136,7 +139,7 @@ class ActionListPresenter @Inject constructor( if (!timelineItem.isMine) { add(TimelineItemAction.ReportContent) } - if (timelineItem.isMine || userCanRedact) { + if (canRedact) { add(TimelineItemAction.Redact) } } @@ -169,7 +172,7 @@ class ActionListPresenter @Inject constructor( if (!timelineItem.isMine) { add(TimelineItemAction.ReportContent) } - if (timelineItem.isMine || userCanRedact) { + if (canRedact) { add(TimelineItemAction.Redact) } } diff --git a/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/MessagesPresenterTest.kt b/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/MessagesPresenterTest.kt index 1ad6a693ab..67bbb98e73 100644 --- a/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/MessagesPresenterTest.kt +++ b/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/MessagesPresenterTest.kt @@ -120,7 +120,7 @@ class MessagesPresenterTest { assertThat(initialState.roomAvatar) .isEqualTo(AsyncData.Success(AvatarData(id = A_ROOM_ID.value, name = "", url = AN_AVATAR_URL, size = AvatarSize.TimelineRoom))) assertThat(initialState.userHasPermissionToSendMessage).isTrue() - assertThat(initialState.userHasPermissionToRedact).isFalse() + assertThat(initialState.userHasPermissionToRedactOwn).isFalse() assertThat(initialState.hasNetworkConnection).isTrue() assertThat(initialState.snackbarMessage).isNull() assertThat(initialState.inviteProgress).isEqualTo(AsyncData.Uninitialized) @@ -601,14 +601,29 @@ class MessagesPresenterTest { } @Test - fun `present - permission to redact`() = runTest { - val matrixRoom = FakeMatrixRoom(canRedact = true) + fun `present - permission to redact own`() = runTest { + val matrixRoom = FakeMatrixRoom(canRedactOwn = true) val presenter = createMessagesPresenter(matrixRoom = matrixRoom) moleculeFlow(RecompositionMode.Immediate) { presenter.present() }.test { - val initialState = consumeItemsUntilPredicate { it.userHasPermissionToRedact }.last() - assertThat(initialState.userHasPermissionToRedact).isTrue() + val initialState = consumeItemsUntilPredicate { it.userHasPermissionToRedactOwn }.last() + assertThat(initialState.userHasPermissionToRedactOwn).isTrue() + assertThat(initialState.userHasPermissionToRedactOther).isFalse() + cancelAndIgnoreRemainingEvents() + } + } + + @Test + fun `present - permission to redact other`() = runTest { + val matrixRoom = FakeMatrixRoom(canRedactOther = true) + val presenter = createMessagesPresenter(matrixRoom = matrixRoom) + moleculeFlow(RecompositionMode.Immediate) { + presenter.present() + }.test { + val initialState = consumeItemsUntilPredicate { it.userHasPermissionToRedactOther }.last() + assertThat(initialState.userHasPermissionToRedactOwn).isFalse() + assertThat(initialState.userHasPermissionToRedactOther).isTrue() cancelAndIgnoreRemainingEvents() } } diff --git a/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/actionlist/ActionListPresenterTest.kt b/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/actionlist/ActionListPresenterTest.kt index 0dbdc7194b..1fefc09544 100644 --- a/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/actionlist/ActionListPresenterTest.kt +++ b/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/actionlist/ActionListPresenterTest.kt @@ -61,7 +61,15 @@ class ActionListPresenterTest { }.test { val initialState = awaitItem() val messageEvent = aMessageEvent(isMine = true, content = TimelineItemRedactedContent) - initialState.eventSink.invoke(ActionListEvents.ComputeForMessage(messageEvent, canRedact = false, canSendMessage = true, canSendReaction = true)) + initialState.eventSink.invoke( + ActionListEvents.ComputeForMessage( + event = messageEvent, + canRedactOwn = false, + canRedactOther = false, + canSendMessage = true, + canSendReaction = true, + ) + ) // val loadingState = awaitItem() // assertThat(loadingState.target).isEqualTo(ActionListState.Target.Loading(messageEvent)) val successState = awaitItem() @@ -87,7 +95,15 @@ class ActionListPresenterTest { }.test { val initialState = awaitItem() val messageEvent = aMessageEvent(isMine = false, content = TimelineItemRedactedContent) - initialState.eventSink.invoke(ActionListEvents.ComputeForMessage(messageEvent, canRedact = false, canSendMessage = true, canSendReaction = true)) + initialState.eventSink.invoke( + ActionListEvents.ComputeForMessage( + event = messageEvent, + canRedactOwn = false, + canRedactOther = false, + canSendMessage = true, + canSendReaction = true, + ) + ) // val loadingState = awaitItem() // assertThat(loadingState.target).isEqualTo(ActionListState.Target.Loading(messageEvent)) val successState = awaitItem() @@ -116,7 +132,15 @@ class ActionListPresenterTest { isMine = false, content = TimelineItemTextContent(body = A_MESSAGE, htmlDocument = null, isEdited = false, formattedBody = null) ) - initialState.eventSink.invoke(ActionListEvents.ComputeForMessage(messageEvent, canRedact = false, canSendMessage = true, canSendReaction = true)) + initialState.eventSink.invoke( + ActionListEvents.ComputeForMessage( + event = messageEvent, + canRedactOwn = false, + canRedactOther = false, + canSendMessage = true, + canSendReaction = true, + ) + ) // val loadingState = awaitItem() // assertThat(loadingState.target).isEqualTo(ActionListState.Target.Loading(messageEvent)) val successState = awaitItem() @@ -149,7 +173,15 @@ class ActionListPresenterTest { isMine = false, content = TimelineItemTextContent(body = A_MESSAGE, htmlDocument = null, isEdited = false, formattedBody = null) ) - initialState.eventSink.invoke(ActionListEvents.ComputeForMessage(messageEvent, canRedact = false, canSendMessage = false, canSendReaction = true)) + initialState.eventSink.invoke( + ActionListEvents.ComputeForMessage( + event = messageEvent, + canRedactOwn = true, + canRedactOther = false, + canSendMessage = false, + canSendReaction = true + ) + ) // val loadingState = awaitItem() // assertThat(loadingState.target).isEqualTo(ActionListState.Target.Loading(messageEvent)) val successState = awaitItem() @@ -181,7 +213,15 @@ class ActionListPresenterTest { isMine = false, content = TimelineItemTextContent(body = A_MESSAGE, htmlDocument = null, isEdited = false, formattedBody = null) ) - initialState.eventSink.invoke(ActionListEvents.ComputeForMessage(messageEvent, canRedact = true, canSendMessage = true, canSendReaction = true)) + initialState.eventSink.invoke( + ActionListEvents.ComputeForMessage( + event = messageEvent, + canRedactOwn = false, + canRedactOther = true, + canSendMessage = true, + canSendReaction = true, + ) + ) val successState = awaitItem() assertThat(successState.target).isEqualTo( ActionListState.Target.Success( @@ -213,7 +253,15 @@ class ActionListPresenterTest { isMine = false, content = TimelineItemTextContent(body = A_MESSAGE, htmlDocument = null, isEdited = false, formattedBody = null) ) - initialState.eventSink.invoke(ActionListEvents.ComputeForMessage(messageEvent, canRedact = true, canSendMessage = true, canSendReaction = false)) + initialState.eventSink.invoke( + ActionListEvents.ComputeForMessage( + event = messageEvent, + canRedactOwn = false, + canRedactOther = true, + canSendMessage = true, + canSendReaction = false + ) + ) val successState = awaitItem() assertThat(successState.target).isEqualTo( ActionListState.Target.Success( @@ -245,7 +293,15 @@ class ActionListPresenterTest { isMine = true, content = TimelineItemTextContent(body = A_MESSAGE, htmlDocument = null, isEdited = false, formattedBody = null) ) - initialState.eventSink.invoke(ActionListEvents.ComputeForMessage(messageEvent, canRedact = false, canSendMessage = true, canSendReaction = true)) + initialState.eventSink.invoke( + ActionListEvents.ComputeForMessage( + event = messageEvent, + canRedactOwn = true, + canRedactOther = false, + canSendMessage = true, + canSendReaction = true, + ) + ) // val loadingState = awaitItem() // assertThat(loadingState.target).isEqualTo(ActionListState.Target.Loading(messageEvent)) val successState = awaitItem() @@ -268,6 +324,47 @@ class ActionListPresenterTest { } } + @Test + fun `present - compute for my message cannot redact`() = runTest { + val presenter = createActionListPresenter(isDeveloperModeEnabled = true) + moleculeFlow(RecompositionMode.Immediate) { + presenter.present() + }.test { + val initialState = awaitItem() + val messageEvent = aMessageEvent( + isMine = true, + content = TimelineItemTextContent(body = A_MESSAGE, htmlDocument = null, isEdited = false, formattedBody = null) + ) + initialState.eventSink.invoke( + ActionListEvents.ComputeForMessage( + event = messageEvent, + canRedactOwn = false, + canRedactOther = false, + canSendMessage = true, + canSendReaction = true, + ) + ) + // val loadingState = awaitItem() + // assertThat(loadingState.target).isEqualTo(ActionListState.Target.Loading(messageEvent)) + val successState = awaitItem() + assertThat(successState.target).isEqualTo( + ActionListState.Target.Success( + event = messageEvent, + displayEmojiReactions = true, + actions = persistentListOf( + TimelineItemAction.Reply, + TimelineItemAction.Forward, + TimelineItemAction.Edit, + TimelineItemAction.Copy, + TimelineItemAction.ViewSource, + ) + ) + ) + initialState.eventSink.invoke(ActionListEvents.Clear) + assertThat(awaitItem().target).isEqualTo(ActionListState.Target.None) + } + } + @Test fun `present - compute for a media item`() = runTest { val presenter = createActionListPresenter(isDeveloperModeEnabled = true) @@ -279,7 +376,15 @@ class ActionListPresenterTest { isMine = true, content = aTimelineItemImageContent(), ) - initialState.eventSink.invoke(ActionListEvents.ComputeForMessage(messageEvent, canRedact = false, canSendMessage = true, canSendReaction = true)) + initialState.eventSink.invoke( + ActionListEvents.ComputeForMessage( + event = messageEvent, + canRedactOwn = true, + canRedactOther = false, + canSendMessage = true, + canSendReaction = true, + ) + ) // val loadingState = awaitItem() // assertThat(loadingState.target).isEqualTo(ActionListState.Target.Loading(messageEvent)) val successState = awaitItem() @@ -311,7 +416,15 @@ class ActionListPresenterTest { isMine = true, content = aTimelineItemStateEventContent(), ) - initialState.eventSink.invoke(ActionListEvents.ComputeForMessage(stateEvent, canRedact = false, canSendMessage = true, canSendReaction = true)) + initialState.eventSink.invoke( + ActionListEvents.ComputeForMessage( + event = stateEvent, + canRedactOwn = false, + canRedactOther = false, + canSendMessage = true, + canSendReaction = true, + ) + ) // val loadingState = awaitItem() // assertThat(loadingState.target).isEqualTo(ActionListState.Target.Loading(messageEvent)) val successState = awaitItem() @@ -341,7 +454,15 @@ class ActionListPresenterTest { isMine = true, content = aTimelineItemStateEventContent(), ) - initialState.eventSink.invoke(ActionListEvents.ComputeForMessage(stateEvent, canRedact = false, canSendMessage = true, canSendReaction = true)) + initialState.eventSink.invoke( + ActionListEvents.ComputeForMessage( + event = stateEvent, + canRedactOwn = false, + canRedactOther = false, + canSendMessage = true, + canSendReaction = true, + ) + ) // val loadingState = awaitItem() // assertThat(loadingState.target).isEqualTo(ActionListState.Target.Loading(messageEvent)) val successState = awaitItem() @@ -370,7 +491,15 @@ class ActionListPresenterTest { isMine = true, content = TimelineItemTextContent(body = A_MESSAGE, htmlDocument = null, isEdited = false, formattedBody = null) ) - initialState.eventSink.invoke(ActionListEvents.ComputeForMessage(messageEvent, canRedact = false, canSendMessage = true, canSendReaction = true)) + initialState.eventSink.invoke( + ActionListEvents.ComputeForMessage( + event = messageEvent, + canRedactOwn = true, + canRedactOther = false, + canSendMessage = true, + canSendReaction = true, + ) + ) // val loadingState = awaitItem() // assertThat(loadingState.target).isEqualTo(ActionListState.Target.Loading(messageEvent)) val successState = awaitItem() @@ -408,10 +537,26 @@ class ActionListPresenterTest { content = TimelineItemRedactedContent, ) - initialState.eventSink.invoke(ActionListEvents.ComputeForMessage(messageEvent, canRedact = false, canSendMessage = true, canSendReaction = true)) + initialState.eventSink.invoke( + ActionListEvents.ComputeForMessage( + event = messageEvent, + canRedactOwn = false, + canRedactOther = false, + canSendMessage = true, + canSendReaction = true, + ) + ) assertThat(awaitItem().target).isInstanceOf(ActionListState.Target.Success::class.java) - initialState.eventSink.invoke(ActionListEvents.ComputeForMessage(redactedEvent, canRedact = false, canSendMessage = true, canSendReaction = true)) + initialState.eventSink.invoke( + ActionListEvents.ComputeForMessage( + event = redactedEvent, + canRedactOwn = false, + canRedactOther = false, + canSendMessage = true, + canSendReaction = true, + ) + ) awaitItem().run { assertThat(target).isEqualTo(ActionListState.Target.None) } @@ -432,7 +577,15 @@ class ActionListPresenterTest { content = TimelineItemTextContent(body = A_MESSAGE, htmlDocument = null, isEdited = false, formattedBody = null), ) - initialState.eventSink.invoke(ActionListEvents.ComputeForMessage(messageEvent, canRedact = false, canSendMessage = true, canSendReaction = true)) + initialState.eventSink.invoke( + ActionListEvents.ComputeForMessage( + event = messageEvent, + canRedactOwn = true, + canRedactOther = false, + canSendMessage = true, + canSendReaction = true, + ) + ) val successState = awaitItem() assertThat(successState.target).isEqualTo( ActionListState.Target.Success( @@ -460,7 +613,15 @@ class ActionListPresenterTest { isEditable = true, content = aTimelineItemPollContent(answerItems = aPollAnswerItemList(hasVotes = false)), ) - initialState.eventSink.invoke(ActionListEvents.ComputeForMessage(messageEvent, canRedact = false, canSendMessage = true, canSendReaction = true)) + initialState.eventSink.invoke( + ActionListEvents.ComputeForMessage( + event = messageEvent, + canRedactOwn = true, + canRedactOther = false, + canSendMessage = true, + canSendReaction = true, + ) + ) val successState = awaitItem() assertThat(successState.target).isEqualTo( ActionListState.Target.Success( @@ -489,7 +650,15 @@ class ActionListPresenterTest { isEditable = false, content = aTimelineItemPollContent(answerItems = aPollAnswerItemList(hasVotes = true)), ) - initialState.eventSink.invoke(ActionListEvents.ComputeForMessage(messageEvent, canRedact = false, canSendMessage = true, canSendReaction = true)) + initialState.eventSink.invoke( + ActionListEvents.ComputeForMessage( + event = messageEvent, + canRedactOwn = true, + canRedactOther = false, + canSendMessage = true, + canSendReaction = true, + ) + ) val successState = awaitItem() assertThat(successState.target).isEqualTo( ActionListState.Target.Success( @@ -517,7 +686,15 @@ class ActionListPresenterTest { isEditable = false, content = aTimelineItemPollContent(isEnded = true), ) - initialState.eventSink.invoke(ActionListEvents.ComputeForMessage(messageEvent, canRedact = false, canSendMessage = true, canSendReaction = true)) + initialState.eventSink.invoke( + ActionListEvents.ComputeForMessage( + event = messageEvent, + canRedactOwn = true, + canRedactOther = false, + canSendMessage = true, + canSendReaction = true, + ) + ) val successState = awaitItem() assertThat(successState.target).isEqualTo( ActionListState.Target.Success( @@ -543,7 +720,15 @@ class ActionListPresenterTest { isMine = true, content = aTimelineItemVoiceContent(), ) - initialState.eventSink.invoke(ActionListEvents.ComputeForMessage(messageEvent, canRedact = false, canSendMessage = true, canSendReaction = true)) + initialState.eventSink.invoke( + ActionListEvents.ComputeForMessage( + event = messageEvent, + canRedactOwn = true, + canRedactOther = false, + canSendMessage = true, + canSendReaction = true, + ) + ) val successState = awaitItem() assertThat(successState.target).isEqualTo( ActionListState.Target.Success( diff --git a/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/room/MatrixRoom.kt b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/room/MatrixRoom.kt index 03c143f078..af6cd81fb2 100644 --- a/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/room/MatrixRoom.kt +++ b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/room/MatrixRoom.kt @@ -127,7 +127,9 @@ interface MatrixRoom : Closeable { suspend fun canUserInvite(userId: UserId): Result - suspend fun canUserRedact(userId: UserId): Result + suspend fun canUserRedactOwn(userId: UserId): Result + + suspend fun canUserRedactOther(userId: UserId): Result suspend fun canUserSendState(userId: UserId, type: StateEventType): Result diff --git a/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/room/powerlevels/MatrixRoomPowerLevels.kt b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/room/powerlevels/MatrixRoomPowerLevels.kt index 3a89f61d9d..c228a9cb2f 100644 --- a/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/room/powerlevels/MatrixRoomPowerLevels.kt +++ b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/room/powerlevels/MatrixRoomPowerLevels.kt @@ -36,6 +36,11 @@ suspend fun MatrixRoom.canSendState(type: StateEventType): Result = can suspend fun MatrixRoom.canSendMessage(type: MessageEventType): Result = canUserSendMessage(sessionId, type) /** - * Shortcut for calling [MatrixRoom.canUserRedact] with our own user. + * Shortcut for calling [MatrixRoom.canUserRedactOwn] with our own user. */ -suspend fun MatrixRoom.canRedact(): Result = canUserRedact(sessionId) +suspend fun MatrixRoom.canRedactOwn(): Result = canUserRedactOwn(sessionId) + +/** + * Shortcut for calling [MatrixRoom.canRedactOther] with our own user. + */ +suspend fun MatrixRoom.canRedactOther(): Result = canUserRedactOther(sessionId) diff --git a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/room/RustMatrixRoom.kt b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/room/RustMatrixRoom.kt index 84ccacb75f..c9a89e558e 100644 --- a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/room/RustMatrixRoom.kt +++ b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/room/RustMatrixRoom.kt @@ -335,9 +335,15 @@ class RustMatrixRoom( } } - override suspend fun canUserRedact(userId: UserId): Result { + override suspend fun canUserRedactOwn(userId: UserId): Result { return runCatching { - innerRoom.canUserRedact(userId.value) + innerRoom.canUserRedactOwn(userId.value) + } + } + + override suspend fun canUserRedactOther(userId: UserId): Result { + return runCatching { + innerRoom.canUserRedactOther(userId.value) } } diff --git a/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/room/FakeMatrixRoom.kt b/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/room/FakeMatrixRoom.kt index b4e0001e84..fbddf28bbe 100644 --- a/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/room/FakeMatrixRoom.kt +++ b/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/room/FakeMatrixRoom.kt @@ -78,7 +78,8 @@ class FakeMatrixRoom( override val activeMemberCount: Long = 234L, val notificationSettingsService: NotificationSettingsService = FakeNotificationSettingsService(), private val matrixTimeline: MatrixTimeline = FakeMatrixTimeline(), - canRedact: Boolean = false, + canRedactOwn: Boolean = false, + canRedactOther: Boolean = false, ) : MatrixRoom { private var ignoreResult: Result = Result.success(Unit) private var unignoreResult: Result = Result.success(Unit) @@ -88,7 +89,8 @@ class FakeMatrixRoom( private var joinRoomResult = Result.success(Unit) private var inviteUserResult = Result.success(Unit) private var canInviteResult = Result.success(true) - private var canRedactResult = Result.success(canRedact) + private var canRedactOwnResult = Result.success(canRedactOwn) + private var canRedactOtherResult = Result.success(canRedactOther) private val canSendStateResults = mutableMapOf>() private val canSendEventResults = mutableMapOf>() private var sendMediaResult = Result.success(FakeMediaUploadHandler()) @@ -276,8 +278,12 @@ class FakeMatrixRoom( return canInviteResult } - override suspend fun canUserRedact(userId: UserId): Result { - return canRedactResult + override suspend fun canUserRedactOwn(userId: UserId): Result { + return canRedactOwnResult + } + + override suspend fun canUserRedactOther(userId: UserId): Result { + return canRedactOtherResult } override suspend fun canUserSendState(userId: UserId, type: StateEventType): Result { diff --git a/libraries/matrixui/src/main/kotlin/io/element/android/libraries/matrix/ui/room/MatrixRoomState.kt b/libraries/matrixui/src/main/kotlin/io/element/android/libraries/matrix/ui/room/MatrixRoomState.kt index dea6195ba8..fbe35742e5 100644 --- a/libraries/matrixui/src/main/kotlin/io/element/android/libraries/matrix/ui/room/MatrixRoomState.kt +++ b/libraries/matrixui/src/main/kotlin/io/element/android/libraries/matrix/ui/room/MatrixRoomState.kt @@ -21,7 +21,8 @@ import androidx.compose.runtime.State import androidx.compose.runtime.produceState import io.element.android.libraries.matrix.api.room.MatrixRoom import io.element.android.libraries.matrix.api.room.MessageEventType -import io.element.android.libraries.matrix.api.room.powerlevels.canRedact +import io.element.android.libraries.matrix.api.room.powerlevels.canRedactOther +import io.element.android.libraries.matrix.api.room.powerlevels.canRedactOwn import io.element.android.libraries.matrix.api.room.powerlevels.canSendMessage @Composable @@ -32,8 +33,15 @@ fun MatrixRoom.canSendMessageAsState(type: MessageEventType, updateKey: Long): S } @Composable -fun MatrixRoom.canRedactAsState(updateKey: Long): State { +fun MatrixRoom.canRedactOwnAsState(updateKey: Long): State { return produceState(initialValue = false, key1 = updateKey) { - value = canRedact().getOrElse { false } + value = canRedactOwn().getOrElse { false } + } +} + +@Composable +fun MatrixRoom.canRedactOtherAsState(updateKey: Long): State { + return produceState(initialValue = false, key1 = updateKey) { + value = canRedactOther().getOrElse { false } } } From dac5a5ae30afaf2f11e75b5dcbec46720d8ef1c9 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Tue, 23 Jan 2024 14:24:40 +0100 Subject: [PATCH 067/127] Fix complexity error by extracting condition to a val. --- .../features/messages/impl/actionlist/ActionListPresenter.kt | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/actionlist/ActionListPresenter.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/actionlist/ActionListPresenter.kt index bede5669fd..3ba333a850 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/actionlist/ActionListPresenter.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/actionlist/ActionListPresenter.kt @@ -102,6 +102,9 @@ class ActionListPresenter @Inject constructor( } } is TimelineItemPollContent -> { + val canEndPoll = timelineItem.isRemote && + !timelineItem.content.isEnded && + (timelineItem.isMine || canRedact) buildList { if (timelineItem.isRemote) { // Can only reply or forward messages already uploaded to the server @@ -110,7 +113,7 @@ class ActionListPresenter @Inject constructor( if (timelineItem.isRemote && timelineItem.isEditable) { add(TimelineItemAction.Edit) } - if (timelineItem.isRemote && !timelineItem.content.isEnded && (timelineItem.isMine || canRedact)) { + if (canEndPoll) { add(TimelineItemAction.EndPoll) } if (timelineItem.content.canBeCopied()) { From addc8e3161fb75f7ddaec2e5eaa3e94b7f1305e8 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Tue, 23 Jan 2024 14:25:16 +0100 Subject: [PATCH 068/127] @Suppress("LargeClass") for test. --- .../features/messages/impl/actionlist/ActionListPresenterTest.kt | 1 + 1 file changed, 1 insertion(+) diff --git a/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/actionlist/ActionListPresenterTest.kt b/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/actionlist/ActionListPresenterTest.kt index 1fefc09544..0132b449df 100644 --- a/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/actionlist/ActionListPresenterTest.kt +++ b/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/actionlist/ActionListPresenterTest.kt @@ -38,6 +38,7 @@ import kotlinx.coroutines.test.runTest import org.junit.Rule import org.junit.Test +@Suppress("LargeClass") class ActionListPresenterTest { @get:Rule val warmUpRule = WarmUpRule() From b3accdaa786d4c8c272ee8a3589f54abbbbf8b32 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Tue, 23 Jan 2024 14:27:06 +0100 Subject: [PATCH 069/127] Remove unnecessary parenthesis. --- .../features/messages/impl/actionlist/ActionListPresenter.kt | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/actionlist/ActionListPresenter.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/actionlist/ActionListPresenter.kt index 3ba333a850..f753266062 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/actionlist/ActionListPresenter.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/actionlist/ActionListPresenter.kt @@ -82,8 +82,7 @@ class ActionListPresenter @Inject constructor( target: MutableState ) = launch { target.value = ActionListState.Target.Loading(timelineItem) - val canRedact = (timelineItem.isMine && userCanRedactOwn) || - (!timelineItem.isMine && userCanRedactOther) + val canRedact = timelineItem.isMine && userCanRedactOwn || !timelineItem.isMine && userCanRedactOther val actions = when (timelineItem.content) { is TimelineItemRedactedContent -> { From ce20b5f518608cf1c62091cbbfaf668f0951d9c6 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Tue, 23 Jan 2024 15:53:58 +0100 Subject: [PATCH 070/127] Add a report problem text button to the OnBoarding screen #2275. --- .../android/appnav/NotLoggedInFlowNode.kt | 9 +++++++++ .../io/element/android/appnav/RootFlowNode.kt | 9 ++++++++- changelog.d/2275.misc | 1 + .../onboarding/api/OnBoardingEntryPoint.kt | 1 + .../features/onboarding/impl/OnBoardingNode.kt | 5 +++++ .../features/onboarding/impl/OnBoardingView.kt | 16 +++++++++++++++- 6 files changed, 39 insertions(+), 2 deletions(-) create mode 100644 changelog.d/2275.misc diff --git a/appnav/src/main/kotlin/io/element/android/appnav/NotLoggedInFlowNode.kt b/appnav/src/main/kotlin/io/element/android/appnav/NotLoggedInFlowNode.kt index 9401cdeac1..fae6d586aa 100644 --- a/appnav/src/main/kotlin/io/element/android/appnav/NotLoggedInFlowNode.kt +++ b/appnav/src/main/kotlin/io/element/android/appnav/NotLoggedInFlowNode.kt @@ -24,6 +24,7 @@ import com.bumble.appyx.core.lifecycle.subscribe import com.bumble.appyx.core.modality.BuildContext import com.bumble.appyx.core.node.Node import com.bumble.appyx.core.plugin.Plugin +import com.bumble.appyx.core.plugin.plugins import com.bumble.appyx.navmodel.backstack.BackStack import com.bumble.appyx.navmodel.backstack.operation.push import dagger.assisted.Assisted @@ -54,6 +55,10 @@ class NotLoggedInFlowNode @AssistedInject constructor( buildContext = buildContext, plugins = plugins, ) { + interface Callback : Plugin { + fun onOpenBugReport() + } + override fun onBuilt() { super.onBuilt() lifecycle.subscribe( @@ -91,6 +96,10 @@ class NotLoggedInFlowNode @AssistedInject constructor( override fun onOpenDeveloperSettings() { backstack.push(NavTarget.ConfigureTracing) } + + override fun onReportProblem() { + plugins().forEach { it.onOpenBugReport() } + } } onBoardingEntryPoint .nodeBuilder(this, buildContext) diff --git a/appnav/src/main/kotlin/io/element/android/appnav/RootFlowNode.kt b/appnav/src/main/kotlin/io/element/android/appnav/RootFlowNode.kt index 8a9ea22926..fa7820b5d5 100644 --- a/appnav/src/main/kotlin/io/element/android/appnav/RootFlowNode.kt +++ b/appnav/src/main/kotlin/io/element/android/appnav/RootFlowNode.kt @@ -210,7 +210,14 @@ class RootFlowNode @AssistedInject constructor( } createNode(buildContext, plugins = listOf(inputs, callback)) } - NavTarget.NotLoggedInFlow -> createNode(buildContext) + NavTarget.NotLoggedInFlow -> { + val callback = object : NotLoggedInFlowNode.Callback { + override fun onOpenBugReport() { + backstack.push(NavTarget.BugReport) + } + } + createNode(buildContext, plugins = listOf(callback)) + } is NavTarget.SignedOutFlow -> { signedOutEntryPoint.nodeBuilder(this, buildContext) .params( diff --git a/changelog.d/2275.misc b/changelog.d/2275.misc new file mode 100644 index 0000000000..ba8eabfebd --- /dev/null +++ b/changelog.d/2275.misc @@ -0,0 +1 @@ +Add "Report a problem" button to the onboarding screen diff --git a/features/onboarding/api/src/main/kotlin/io/element/android/features/onboarding/api/OnBoardingEntryPoint.kt b/features/onboarding/api/src/main/kotlin/io/element/android/features/onboarding/api/OnBoardingEntryPoint.kt index 77898ca91f..a70f14dc43 100644 --- a/features/onboarding/api/src/main/kotlin/io/element/android/features/onboarding/api/OnBoardingEntryPoint.kt +++ b/features/onboarding/api/src/main/kotlin/io/element/android/features/onboarding/api/OnBoardingEntryPoint.kt @@ -33,5 +33,6 @@ interface OnBoardingEntryPoint : FeatureEntryPoint { fun onSignUp() fun onSignIn() fun onOpenDeveloperSettings() + fun onReportProblem() } } diff --git a/features/onboarding/impl/src/main/kotlin/io/element/android/features/onboarding/impl/OnBoardingNode.kt b/features/onboarding/impl/src/main/kotlin/io/element/android/features/onboarding/impl/OnBoardingNode.kt index f8653cc921..f7d829d5fe 100644 --- a/features/onboarding/impl/src/main/kotlin/io/element/android/features/onboarding/impl/OnBoardingNode.kt +++ b/features/onboarding/impl/src/main/kotlin/io/element/android/features/onboarding/impl/OnBoardingNode.kt @@ -49,6 +49,10 @@ class OnBoardingNode @AssistedInject constructor( plugins().forEach { it.onOpenDeveloperSettings() } } + private fun onReportProblem() { + plugins().forEach { it.onReportProblem() } + } + @Composable override fun View(modifier: Modifier) { val state = presenter.present() @@ -59,6 +63,7 @@ class OnBoardingNode @AssistedInject constructor( onCreateAccount = ::onSignUp, onSignInWithQrCode = { /* Not supported yet */ }, onOpenDeveloperSettings = ::onOpenDeveloperSettings, + onReportProblem = ::onReportProblem, ) } } diff --git a/features/onboarding/impl/src/main/kotlin/io/element/android/features/onboarding/impl/OnBoardingView.kt b/features/onboarding/impl/src/main/kotlin/io/element/android/features/onboarding/impl/OnBoardingView.kt index a0d2e2ce7f..c4b4e2d6b4 100644 --- a/features/onboarding/impl/src/main/kotlin/io/element/android/features/onboarding/impl/OnBoardingView.kt +++ b/features/onboarding/impl/src/main/kotlin/io/element/android/features/onboarding/impl/OnBoardingView.kt @@ -16,6 +16,7 @@ package io.element.android.features.onboarding.impl +import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Spacer @@ -65,6 +66,7 @@ fun OnBoardingView( onSignIn: () -> Unit, onCreateAccount: () -> Unit, onOpenDeveloperSettings: () -> Unit, + onReportProblem: () -> Unit, modifier: Modifier = Modifier, ) { OnBoardingPage( @@ -81,6 +83,7 @@ fun OnBoardingView( onSignInWithQrCode = onSignInWithQrCode, onSignIn = onSignIn, onCreateAccount = onCreateAccount, + onReportProblem = onReportProblem, ) } ) @@ -154,6 +157,7 @@ private fun OnBoardingButtons( onSignInWithQrCode: () -> Unit, onSignIn: () -> Unit, onCreateAccount: () -> Unit, + onReportProblem: () -> Unit, modifier: Modifier = Modifier, ) { ButtonColumnMolecule(modifier = modifier) { @@ -187,6 +191,15 @@ private fun OnBoardingButtons( ) } Spacer(modifier = Modifier.height(16.dp)) + // Add a report problem text button. Use a Text since we need a special theme here. + Text( + modifier = Modifier + .padding(8.dp) + .clickable(onClick = onReportProblem), + text = stringResource(id = CommonStrings.common_report_a_problem), + style = ElementTheme.typography.fontBodySmRegular, + color = ElementTheme.colors.textSecondary, + ) } } @@ -200,6 +213,7 @@ internal fun OnBoardingScreenPreview( onSignInWithQrCode = {}, onSignIn = {}, onCreateAccount = {}, - onOpenDeveloperSettings = {} + onOpenDeveloperSettings = {}, + onReportProblem = {}, ) } From 46770075d9753cf4f6ec1cf142d90f3d3fc90f5d Mon Sep 17 00:00:00 2001 From: ElementBot Date: Tue, 23 Jan 2024 15:04:39 +0000 Subject: [PATCH 071/127] Update screenshots --- ...n_null_OnBoardingScreen-Day-0_1_null_0,NEXUS_5,1.0,en].png | 4 ++-- ...n_null_OnBoardingScreen-Day-0_1_null_1,NEXUS_5,1.0,en].png | 4 ++-- ...n_null_OnBoardingScreen-Day-0_1_null_2,NEXUS_5,1.0,en].png | 4 ++-- ...n_null_OnBoardingScreen-Day-0_1_null_3,NEXUS_5,1.0,en].png | 4 ++-- ...n_null_OnBoardingScreen-Day-0_1_null_4,NEXUS_5,1.0,en].png | 4 ++-- ...null_OnBoardingScreen-Night-0_2_null_0,NEXUS_5,1.0,en].png | 4 ++-- ...null_OnBoardingScreen-Night-0_2_null_1,NEXUS_5,1.0,en].png | 4 ++-- ...null_OnBoardingScreen-Night-0_2_null_2,NEXUS_5,1.0,en].png | 4 ++-- ...null_OnBoardingScreen-Night-0_2_null_3,NEXUS_5,1.0,en].png | 4 ++-- ...null_OnBoardingScreen-Night-0_2_null_4,NEXUS_5,1.0,en].png | 4 ++-- 10 files changed, 20 insertions(+), 20 deletions(-) diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.onboarding.impl_OnBoardingScreen_null_OnBoardingScreen-Day-0_1_null_0,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.onboarding.impl_OnBoardingScreen_null_OnBoardingScreen-Day-0_1_null_0,NEXUS_5,1.0,en].png index 6e9b5a2034..1618c3e638 100644 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.onboarding.impl_OnBoardingScreen_null_OnBoardingScreen-Day-0_1_null_0,NEXUS_5,1.0,en].png +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.onboarding.impl_OnBoardingScreen_null_OnBoardingScreen-Day-0_1_null_0,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:067d37cbe20e27b8e852f3eedaa3bcc64d94d062cb825df5b826a1b584e2aa1b -size 316186 +oid sha256:4595089f2c885b73cdbd79d626c3eab79da657fef1a2ce2390e761e2469a4e0b +size 313738 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.onboarding.impl_OnBoardingScreen_null_OnBoardingScreen-Day-0_1_null_1,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.onboarding.impl_OnBoardingScreen_null_OnBoardingScreen-Day-0_1_null_1,NEXUS_5,1.0,en].png index 708b07d88d..df970a3ce3 100644 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.onboarding.impl_OnBoardingScreen_null_OnBoardingScreen-Day-0_1_null_1,NEXUS_5,1.0,en].png +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.onboarding.impl_OnBoardingScreen_null_OnBoardingScreen-Day-0_1_null_1,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:08aedb3ff38729714de367a1b51b92f14907d1cd6f71a02a3b73ada46c2b86a6 -size 311794 +oid sha256:452876b1189da12691bca146c63202324593c791e854a1f8918a71c556a2c454 +size 305809 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.onboarding.impl_OnBoardingScreen_null_OnBoardingScreen-Day-0_1_null_2,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.onboarding.impl_OnBoardingScreen_null_OnBoardingScreen-Day-0_1_null_2,NEXUS_5,1.0,en].png index 54aa98cef9..ac4bd00348 100644 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.onboarding.impl_OnBoardingScreen_null_OnBoardingScreen-Day-0_1_null_2,NEXUS_5,1.0,en].png +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.onboarding.impl_OnBoardingScreen_null_OnBoardingScreen-Day-0_1_null_2,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:94383700dd12a703f9e3773d231a18520b74037d7823d307c15c2c44ef9c4fd3 -size 315047 +oid sha256:f496246dd0186280943dbf3057956eef19fdfd64ccd8458c49edb32cb97f24d3 +size 315968 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.onboarding.impl_OnBoardingScreen_null_OnBoardingScreen-Day-0_1_null_3,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.onboarding.impl_OnBoardingScreen_null_OnBoardingScreen-Day-0_1_null_3,NEXUS_5,1.0,en].png index 92da16468b..254fa69e4f 100644 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.onboarding.impl_OnBoardingScreen_null_OnBoardingScreen-Day-0_1_null_3,NEXUS_5,1.0,en].png +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.onboarding.impl_OnBoardingScreen_null_OnBoardingScreen-Day-0_1_null_3,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:672c71bf95e048043af54904e3e14909a7af37efc8dbfa0c29ba3b027db2b70a -size 305960 +oid sha256:a127838495bdd790e1eeb6632d9fcfb256edd8ebe5d83f222434458b9687679c +size 307141 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.onboarding.impl_OnBoardingScreen_null_OnBoardingScreen-Day-0_1_null_4,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.onboarding.impl_OnBoardingScreen_null_OnBoardingScreen-Day-0_1_null_4,NEXUS_5,1.0,en].png index 5d7e8bf7d7..148df5143d 100644 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.onboarding.impl_OnBoardingScreen_null_OnBoardingScreen-Day-0_1_null_4,NEXUS_5,1.0,en].png +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.onboarding.impl_OnBoardingScreen_null_OnBoardingScreen-Day-0_1_null_4,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:aaf9e59966650af342740484f37b7e5da334a72a96faa318db0dc9ea012d891c -size 316954 +oid sha256:c5c86f4f08460382392eb9404fecdc93b6ff056e0d4116f39fc6308d1061c163 +size 314537 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.onboarding.impl_OnBoardingScreen_null_OnBoardingScreen-Night-0_2_null_0,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.onboarding.impl_OnBoardingScreen_null_OnBoardingScreen-Night-0_2_null_0,NEXUS_5,1.0,en].png index d8891a6a48..7cd11d4937 100644 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.onboarding.impl_OnBoardingScreen_null_OnBoardingScreen-Night-0_2_null_0,NEXUS_5,1.0,en].png +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.onboarding.impl_OnBoardingScreen_null_OnBoardingScreen-Night-0_2_null_0,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:6334be27e7a3c3fd2b000ffb8d912b84fdf3867211c261fcd6451f8321d91f9e -size 412644 +oid sha256:9df131c8d7482b7b00df587cca8b385d0cd57954240368f349a24e8e6ae36322 +size 405021 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.onboarding.impl_OnBoardingScreen_null_OnBoardingScreen-Night-0_2_null_1,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.onboarding.impl_OnBoardingScreen_null_OnBoardingScreen-Night-0_2_null_1,NEXUS_5,1.0,en].png index 0e7087356f..b5ca95ff71 100644 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.onboarding.impl_OnBoardingScreen_null_OnBoardingScreen-Night-0_2_null_1,NEXUS_5,1.0,en].png +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.onboarding.impl_OnBoardingScreen_null_OnBoardingScreen-Night-0_2_null_1,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:8d84c6f511b9533118bf603d37e99f9a8670f8dc120c0b6ef85f0e488ffea43a -size 401150 +oid sha256:d5070637e034d7ecc1db4944cb05ec056e0cbea342769a32ee030b47110f8e4b +size 386301 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.onboarding.impl_OnBoardingScreen_null_OnBoardingScreen-Night-0_2_null_2,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.onboarding.impl_OnBoardingScreen_null_OnBoardingScreen-Night-0_2_null_2,NEXUS_5,1.0,en].png index 8c96d798de..a6d71eb418 100644 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.onboarding.impl_OnBoardingScreen_null_OnBoardingScreen-Night-0_2_null_2,NEXUS_5,1.0,en].png +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.onboarding.impl_OnBoardingScreen_null_OnBoardingScreen-Night-0_2_null_2,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:162389f0543bec631064fa9da20bf4e76150cedacc594a3299b4da231fe62502 -size 404119 +oid sha256:662e5beadd1baea7825ce047df87c4429f720ea7b4dd53f8ea576ada91814568 +size 399093 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.onboarding.impl_OnBoardingScreen_null_OnBoardingScreen-Night-0_2_null_3,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.onboarding.impl_OnBoardingScreen_null_OnBoardingScreen-Night-0_2_null_3,NEXUS_5,1.0,en].png index eb250c9c5e..8791e1399c 100644 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.onboarding.impl_OnBoardingScreen_null_OnBoardingScreen-Night-0_2_null_3,NEXUS_5,1.0,en].png +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.onboarding.impl_OnBoardingScreen_null_OnBoardingScreen-Night-0_2_null_3,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:0f980d1c2a27b18237e04679bc8a507854ebb518eab7506d1210e34bd38087a4 -size 383009 +oid sha256:3a76b73d9e5e94b8dd8b27addd07593bae43423b92048110b213413e1185100e +size 373027 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.onboarding.impl_OnBoardingScreen_null_OnBoardingScreen-Night-0_2_null_4,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.onboarding.impl_OnBoardingScreen_null_OnBoardingScreen-Night-0_2_null_4,NEXUS_5,1.0,en].png index d40e2236b4..36442edf97 100644 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.onboarding.impl_OnBoardingScreen_null_OnBoardingScreen-Night-0_2_null_4,NEXUS_5,1.0,en].png +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.onboarding.impl_OnBoardingScreen_null_OnBoardingScreen-Night-0_2_null_4,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:b19d128ca665799591b6a570be4643e482821bf9d632dc7704aacd13111d458a -size 413352 +oid sha256:d1a672fea8d9f8b6a1c9646982438bf3dc66874a472c0c2269d74fccffed3a98 +size 405810 From e9be294ff9c676c809afafefa739127d7360ac9e Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 19 Jan 2024 16:34:40 +0000 Subject: [PATCH 072/127] Update dependency io.nlopez.compose.rules:detekt to v0.3.10 --- build.gradle.kts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle.kts b/build.gradle.kts index 051a7a4112..26b7a4efe5 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -60,7 +60,7 @@ allprojects { config.from(files("$rootDir/tools/detekt/detekt.yml")) } dependencies { - detektPlugins("io.nlopez.compose.rules:detekt:0.3.9") + detektPlugins("io.nlopez.compose.rules:detekt:0.3.10") } // KtLint From 1c1cf60ba0a771737fd30a1f3bbb6d7e3fd9de37 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Fri, 19 Jan 2024 20:25:40 +0100 Subject: [PATCH 073/127] Change type of `SecureBackupEnableState.enableAction` from `AsyncData` to `AsyncAction` --- .../enable/SecureBackupEnablePresenter.kt | 8 +++---- .../impl/enable/SecureBackupEnableState.kt | 4 ++-- .../enable/SecureBackupEnableStateProvider.kt | 8 +++---- .../impl/enable/SecureBackupEnableView.kt | 21 +++++++------------ .../enable/SecureBackupEnablePresenterTest.kt | 14 ++++++------- 5 files changed, 24 insertions(+), 31 deletions(-) diff --git a/features/securebackup/impl/src/main/kotlin/io/element/android/features/securebackup/impl/enable/SecureBackupEnablePresenter.kt b/features/securebackup/impl/src/main/kotlin/io/element/android/features/securebackup/impl/enable/SecureBackupEnablePresenter.kt index c12ea2d24e..73d8058036 100644 --- a/features/securebackup/impl/src/main/kotlin/io/element/android/features/securebackup/impl/enable/SecureBackupEnablePresenter.kt +++ b/features/securebackup/impl/src/main/kotlin/io/element/android/features/securebackup/impl/enable/SecureBackupEnablePresenter.kt @@ -22,7 +22,7 @@ import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.runtime.rememberCoroutineScope import io.element.android.features.securebackup.impl.loggerTagDisable -import io.element.android.libraries.architecture.AsyncData +import io.element.android.libraries.architecture.AsyncAction import io.element.android.libraries.architecture.Presenter import io.element.android.libraries.architecture.runCatchingUpdatingState import io.element.android.libraries.matrix.api.encryption.EncryptionService @@ -36,14 +36,14 @@ class SecureBackupEnablePresenter @Inject constructor( ) : Presenter { @Composable override fun present(): SecureBackupEnableState { - val enableAction = remember { mutableStateOf>(AsyncData.Uninitialized) } + val enableAction = remember { mutableStateOf>(AsyncAction.Uninitialized) } val coroutineScope = rememberCoroutineScope() fun handleEvents(event: SecureBackupEnableEvents) { when (event) { is SecureBackupEnableEvents.EnableBackup -> coroutineScope.enableBackup(enableAction) SecureBackupEnableEvents.DismissDialog -> { - enableAction.value = AsyncData.Uninitialized + enableAction.value = AsyncAction.Uninitialized } } } @@ -54,7 +54,7 @@ class SecureBackupEnablePresenter @Inject constructor( ) } - private fun CoroutineScope.enableBackup(action: MutableState>) = launch { + private fun CoroutineScope.enableBackup(action: MutableState>) = launch { suspend { Timber.tag(loggerTagDisable.value).d("Calling encryptionService.enableBackups()") encryptionService.enableBackups().getOrThrow() diff --git a/features/securebackup/impl/src/main/kotlin/io/element/android/features/securebackup/impl/enable/SecureBackupEnableState.kt b/features/securebackup/impl/src/main/kotlin/io/element/android/features/securebackup/impl/enable/SecureBackupEnableState.kt index bd81004f9c..7c38501bf0 100644 --- a/features/securebackup/impl/src/main/kotlin/io/element/android/features/securebackup/impl/enable/SecureBackupEnableState.kt +++ b/features/securebackup/impl/src/main/kotlin/io/element/android/features/securebackup/impl/enable/SecureBackupEnableState.kt @@ -16,9 +16,9 @@ package io.element.android.features.securebackup.impl.enable -import io.element.android.libraries.architecture.AsyncData +import io.element.android.libraries.architecture.AsyncAction data class SecureBackupEnableState( - val enableAction: AsyncData, + val enableAction: AsyncAction, val eventSink: (SecureBackupEnableEvents) -> Unit ) diff --git a/features/securebackup/impl/src/main/kotlin/io/element/android/features/securebackup/impl/enable/SecureBackupEnableStateProvider.kt b/features/securebackup/impl/src/main/kotlin/io/element/android/features/securebackup/impl/enable/SecureBackupEnableStateProvider.kt index 1029278c05..fc48036626 100644 --- a/features/securebackup/impl/src/main/kotlin/io/element/android/features/securebackup/impl/enable/SecureBackupEnableStateProvider.kt +++ b/features/securebackup/impl/src/main/kotlin/io/element/android/features/securebackup/impl/enable/SecureBackupEnableStateProvider.kt @@ -17,20 +17,20 @@ package io.element.android.features.securebackup.impl.enable import androidx.compose.ui.tooling.preview.PreviewParameterProvider -import io.element.android.libraries.architecture.AsyncData +import io.element.android.libraries.architecture.AsyncAction open class SecureBackupEnableStateProvider : PreviewParameterProvider { override val values: Sequence get() = sequenceOf( aSecureBackupEnableState(), - aSecureBackupEnableState(enableAction = AsyncData.Loading()), - aSecureBackupEnableState(enableAction = AsyncData.Failure(Exception("Failed to enable"))), + aSecureBackupEnableState(enableAction = AsyncAction.Loading), + aSecureBackupEnableState(enableAction = AsyncAction.Failure(Exception("Failed to enable"))), // Add other states here ) } fun aSecureBackupEnableState( - enableAction: AsyncData = AsyncData.Uninitialized, + enableAction: AsyncAction = AsyncAction.Uninitialized, ) = SecureBackupEnableState( enableAction = enableAction, eventSink = {} diff --git a/features/securebackup/impl/src/main/kotlin/io/element/android/features/securebackup/impl/enable/SecureBackupEnableView.kt b/features/securebackup/impl/src/main/kotlin/io/element/android/features/securebackup/impl/enable/SecureBackupEnableView.kt index 37a46a1408..db41289ecc 100644 --- a/features/securebackup/impl/src/main/kotlin/io/element/android/features/securebackup/impl/enable/SecureBackupEnableView.kt +++ b/features/securebackup/impl/src/main/kotlin/io/element/android/features/securebackup/impl/enable/SecureBackupEnableView.kt @@ -19,16 +19,14 @@ package io.element.android.features.securebackup.impl.enable import androidx.compose.foundation.layout.ColumnScope import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.runtime.Composable -import androidx.compose.runtime.LaunchedEffect import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.vector.ImageVector import androidx.compose.ui.res.stringResource import androidx.compose.ui.res.vectorResource import androidx.compose.ui.tooling.preview.PreviewParameter import io.element.android.features.securebackup.impl.R -import io.element.android.libraries.architecture.AsyncData import io.element.android.libraries.designsystem.atomic.pages.FlowStepPage -import io.element.android.libraries.designsystem.components.dialogs.ErrorDialog +import io.element.android.libraries.designsystem.components.async.AsyncActionView import io.element.android.libraries.designsystem.preview.ElementPreview import io.element.android.libraries.designsystem.preview.PreviewsDayNight import io.element.android.libraries.designsystem.theme.components.Button @@ -41,11 +39,6 @@ fun SecureBackupEnableView( onBackClicked: () -> Unit, modifier: Modifier = Modifier, ) { - LaunchedEffect(state.enableAction) { - if (state.enableAction is AsyncData.Success) { - onDone() - } - } FlowStepPage( modifier = modifier, onBackClicked = onBackClicked, @@ -53,12 +46,12 @@ fun SecureBackupEnableView( iconVector = ImageVector.vectorResource(CommonDrawables.ic_key), buttons = { Buttons(state = state) } ) - if (state.enableAction is AsyncData.Failure) { - ErrorDialog( - content = state.enableAction.error.let { it.message ?: it.toString() }, - onDismiss = { state.eventSink.invoke(SecureBackupEnableEvents.DismissDialog) }, - ) - } + AsyncActionView( + async = state.enableAction, + progressDialog = { }, + onSuccess = { onDone() }, + onErrorDismiss = { state.eventSink.invoke(SecureBackupEnableEvents.DismissDialog) } + ) } @Composable diff --git a/features/securebackup/impl/src/test/kotlin/io/element/android/features/securebackup/impl/enable/SecureBackupEnablePresenterTest.kt b/features/securebackup/impl/src/test/kotlin/io/element/android/features/securebackup/impl/enable/SecureBackupEnablePresenterTest.kt index 39d8ebf81f..4ee16285cd 100644 --- a/features/securebackup/impl/src/test/kotlin/io/element/android/features/securebackup/impl/enable/SecureBackupEnablePresenterTest.kt +++ b/features/securebackup/impl/src/test/kotlin/io/element/android/features/securebackup/impl/enable/SecureBackupEnablePresenterTest.kt @@ -20,7 +20,7 @@ import app.cash.molecule.RecompositionMode import app.cash.molecule.moleculeFlow import app.cash.turbine.test import com.google.common.truth.Truth.assertThat -import io.element.android.libraries.architecture.AsyncData +import io.element.android.libraries.architecture.AsyncAction import io.element.android.libraries.matrix.api.encryption.EncryptionService import io.element.android.libraries.matrix.test.AN_EXCEPTION import io.element.android.libraries.matrix.test.encryption.FakeEncryptionService @@ -40,7 +40,7 @@ class SecureBackupEnablePresenterTest { presenter.present() }.test { val initialState = awaitItem() - assertThat(initialState.enableAction).isEqualTo(AsyncData.Uninitialized) + assertThat(initialState.enableAction).isEqualTo(AsyncAction.Uninitialized) } } @@ -53,9 +53,9 @@ class SecureBackupEnablePresenterTest { val initialState = awaitItem() initialState.eventSink(SecureBackupEnableEvents.EnableBackup) val loadingState = awaitItem() - assertThat(loadingState.enableAction).isInstanceOf(AsyncData.Loading::class.java) + assertThat(loadingState.enableAction).isInstanceOf(AsyncAction.Loading::class.java) val finalState = awaitItem() - assertThat(finalState.enableAction).isEqualTo(AsyncData.Success(Unit)) + assertThat(finalState.enableAction).isEqualTo(AsyncAction.Success(Unit)) } } @@ -70,12 +70,12 @@ class SecureBackupEnablePresenterTest { val initialState = awaitItem() initialState.eventSink(SecureBackupEnableEvents.EnableBackup) val loadingState = awaitItem() - assertThat(loadingState.enableAction).isInstanceOf(AsyncData.Loading::class.java) + assertThat(loadingState.enableAction).isInstanceOf(AsyncAction.Loading::class.java) val errorState = awaitItem() - assertThat(errorState.enableAction).isEqualTo(AsyncData.Failure(AN_EXCEPTION)) + assertThat(errorState.enableAction).isEqualTo(AsyncAction.Failure(AN_EXCEPTION)) errorState.eventSink(SecureBackupEnableEvents.DismissDialog) val finalState = awaitItem() - assertThat(finalState.enableAction).isEqualTo(AsyncData.Uninitialized) + assertThat(finalState.enableAction).isEqualTo(AsyncAction.Uninitialized) } } From 3ced570b3c742e0f255d91748dde574bee5bb729 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Fri, 19 Jan 2024 20:44:43 +0100 Subject: [PATCH 074/127] Fix detekt issue: Lambda parameters in a @Composable that are referenced directly inside of restarting effects can cause issues or unpredictable behavior. If restarting the effect is ok, you can add the reference to this parameter as a key in that effect, so when the parameter changes, a new effect is created. However, if the effect is not to be restarted, you will need to use `rememberUpdatedState` on the parameter and use its result in the effect. See https://mrmans0n.github.io/compose-rules/rules/#be-mindful-of-the-arguments-you-use-inside-of-a-restarting-effect for more information. [LambdaParameterInRestartableEffect] --- .../features/ftue/impl/migration/MigrationScreenView.kt | 2 +- .../android/features/invitelist/impl/InviteListView.kt | 2 +- .../features/lockscreen/impl/unlock/PinUnlockHelper.kt | 7 +++++-- .../features/login/impl/changeserver/ChangeServerView.kt | 2 +- .../android/features/logout/impl/ui/LogoutActionDialog.kt | 2 +- .../element/android/features/messages/impl/MessagesView.kt | 2 +- .../impl/attachments/preview/AttachmentsPreviewView.kt | 2 +- .../features/messages/impl/timeline/TimelineView.kt | 4 +++- .../rageshake/api/detection/RageshakeDetectionView.kt | 2 +- .../designsystem/components/async/AsyncActionView.kt | 2 +- .../android/libraries/textcomposer/SoftKeyboardEffect.kt | 7 +++++-- .../element/android/libraries/textcomposer/TextComposer.kt | 6 ++++-- 12 files changed, 25 insertions(+), 15 deletions(-) diff --git a/features/ftue/impl/src/main/kotlin/io/element/android/features/ftue/impl/migration/MigrationScreenView.kt b/features/ftue/impl/src/main/kotlin/io/element/android/features/ftue/impl/migration/MigrationScreenView.kt index d2674e3f98..a365b1e4dc 100644 --- a/features/ftue/impl/src/main/kotlin/io/element/android/features/ftue/impl/migration/MigrationScreenView.kt +++ b/features/ftue/impl/src/main/kotlin/io/element/android/features/ftue/impl/migration/MigrationScreenView.kt @@ -32,7 +32,7 @@ fun MigrationScreenView( modifier: Modifier = Modifier, ) { if (migrationState.isMigrating.not()) { - LaunchedEffect(Unit) { + LaunchedEffect(onMigrationFinished) { onMigrationFinished() } } diff --git a/features/invitelist/impl/src/main/kotlin/io/element/android/features/invitelist/impl/InviteListView.kt b/features/invitelist/impl/src/main/kotlin/io/element/android/features/invitelist/impl/InviteListView.kt index 28ecf4938d..93d552237f 100644 --- a/features/invitelist/impl/src/main/kotlin/io/element/android/features/invitelist/impl/InviteListView.kt +++ b/features/invitelist/impl/src/main/kotlin/io/element/android/features/invitelist/impl/InviteListView.kt @@ -57,7 +57,7 @@ fun InviteListView( modifier: Modifier = Modifier, ) { if (state.acceptedAction is AsyncData.Success) { - LaunchedEffect(state.acceptedAction) { + LaunchedEffect(state.acceptedAction, onInviteAccepted) { onInviteAccepted(state.acceptedAction.data) } } diff --git a/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/unlock/PinUnlockHelper.kt b/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/unlock/PinUnlockHelper.kt index e1dd7f5be3..6ecf13f591 100644 --- a/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/unlock/PinUnlockHelper.kt +++ b/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/unlock/PinUnlockHelper.kt @@ -18,6 +18,8 @@ package io.element.android.features.lockscreen.impl.unlock import androidx.compose.runtime.Composable import androidx.compose.runtime.DisposableEffect +import androidx.compose.runtime.getValue +import androidx.compose.runtime.rememberUpdatedState import io.element.android.features.lockscreen.impl.biometric.BiometricUnlockManager import io.element.android.features.lockscreen.impl.biometric.DefaultBiometricUnlockCallback import io.element.android.features.lockscreen.impl.pin.DefaultPinCodeManagerCallback @@ -30,15 +32,16 @@ class PinUnlockHelper @Inject constructor( ) { @Composable fun OnUnlockEffect(onUnlock: () -> Unit) { + val latestOnUnlock by rememberUpdatedState(onUnlock) DisposableEffect(Unit) { val biometricUnlockCallback = object : DefaultBiometricUnlockCallback() { override fun onBiometricUnlockSuccess() { - onUnlock() + latestOnUnlock() } } val pinCodeVerifiedCallback = object : DefaultPinCodeManagerCallback() { override fun onPinCodeVerified() { - onUnlock() + latestOnUnlock() } } biometricUnlockManager.addCallback(biometricUnlockCallback) diff --git a/features/login/impl/src/main/kotlin/io/element/android/features/login/impl/changeserver/ChangeServerView.kt b/features/login/impl/src/main/kotlin/io/element/android/features/login/impl/changeserver/ChangeServerView.kt index 132003eafc..ea18ec407e 100644 --- a/features/login/impl/src/main/kotlin/io/element/android/features/login/impl/changeserver/ChangeServerView.kt +++ b/features/login/impl/src/main/kotlin/io/element/android/features/login/impl/changeserver/ChangeServerView.kt @@ -63,7 +63,7 @@ fun ChangeServerView( } } is AsyncData.Loading -> ProgressDialog() - is AsyncData.Success -> LaunchedEffect(state.changeServerAction) { + is AsyncData.Success -> LaunchedEffect(state.changeServerAction, onDone) { onDone() } AsyncData.Uninitialized -> Unit diff --git a/features/logout/impl/src/main/kotlin/io/element/android/features/logout/impl/ui/LogoutActionDialog.kt b/features/logout/impl/src/main/kotlin/io/element/android/features/logout/impl/ui/LogoutActionDialog.kt index 636dd68058..b626836c8b 100644 --- a/features/logout/impl/src/main/kotlin/io/element/android/features/logout/impl/ui/LogoutActionDialog.kt +++ b/features/logout/impl/src/main/kotlin/io/element/android/features/logout/impl/ui/LogoutActionDialog.kt @@ -53,7 +53,7 @@ fun LogoutActionDialog( onDismiss = onDismissError, ) is AsyncAction.Success -> - LaunchedEffect(state) { + LaunchedEffect(state, onSuccessLogout) { onSuccessLogout(state.data) } } diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/MessagesView.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/MessagesView.kt index 394f1f3556..8098f2516c 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/MessagesView.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/MessagesView.kt @@ -294,7 +294,7 @@ private fun AttachmentStateView( ) { when (state) { AttachmentsState.None -> Unit - is AttachmentsState.Previewing -> LaunchedEffect(state) { + is AttachmentsState.Previewing -> LaunchedEffect(state, onPreviewAttachments) { onPreviewAttachments(state.attachments) } is AttachmentsState.Sending -> { diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/attachments/preview/AttachmentsPreviewView.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/attachments/preview/AttachmentsPreviewView.kt index 5b624bd254..5dc7875afc 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/attachments/preview/AttachmentsPreviewView.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/attachments/preview/AttachmentsPreviewView.kt @@ -57,7 +57,7 @@ fun AttachmentsPreviewView( } if (state.sendActionState is SendActionState.Done) { - LaunchedEffect(state.sendActionState) { + LaunchedEffect(state.sendActionState, onDismiss) { onDismiss() } } diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/TimelineView.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/TimelineView.kt index d2ab635e6a..563eb78d78 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/TimelineView.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/TimelineView.kt @@ -42,6 +42,7 @@ import androidx.compose.runtime.derivedStateOf import androidx.compose.runtime.getValue import androidx.compose.runtime.remember import androidx.compose.runtime.rememberCoroutineScope +import androidx.compose.runtime.rememberUpdatedState import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.draw.alpha @@ -193,10 +194,11 @@ private fun BoxScope.TimelineScrollHelper( } } + val latestOnScrollFinishedAt by rememberUpdatedState(onScrollFinishedAt) LaunchedEffect(isScrollFinished, isTimelineEmpty) { if (isScrollFinished && !isTimelineEmpty) { // Notify the parent composable about the first visible item index when scrolling finishes - onScrollFinishedAt(lazyListState.firstVisibleItemIndex) + latestOnScrollFinishedAt(lazyListState.firstVisibleItemIndex) } } diff --git a/features/rageshake/api/src/main/kotlin/io/element/android/features/rageshake/api/detection/RageshakeDetectionView.kt b/features/rageshake/api/src/main/kotlin/io/element/android/features/rageshake/api/detection/RageshakeDetectionView.kt index 996392d879..5982edfdc8 100644 --- a/features/rageshake/api/src/main/kotlin/io/element/android/features/rageshake/api/detection/RageshakeDetectionView.kt +++ b/features/rageshake/api/src/main/kotlin/io/element/android/features/rageshake/api/detection/RageshakeDetectionView.kt @@ -73,7 +73,7 @@ private fun TakeScreenshot( onScreenshotTaken: (ImageResult) -> Unit ) { val view = LocalView.current - LaunchedEffect(Unit) { + LaunchedEffect(onScreenshotTaken) { view.screenshot { onScreenshotTaken(it) } diff --git a/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/components/async/AsyncActionView.kt b/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/components/async/AsyncActionView.kt index 732a3473a3..102769b7be 100644 --- a/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/components/async/AsyncActionView.kt +++ b/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/components/async/AsyncActionView.kt @@ -67,7 +67,7 @@ fun AsyncActionView( } } is AsyncAction.Success -> { - LaunchedEffect(async) { + LaunchedEffect(async, onSuccess) { onSuccess(async.data) } } diff --git a/libraries/textcomposer/impl/src/main/kotlin/io/element/android/libraries/textcomposer/SoftKeyboardEffect.kt b/libraries/textcomposer/impl/src/main/kotlin/io/element/android/libraries/textcomposer/SoftKeyboardEffect.kt index 96b48dca6e..90e9591953 100644 --- a/libraries/textcomposer/impl/src/main/kotlin/io/element/android/libraries/textcomposer/SoftKeyboardEffect.kt +++ b/libraries/textcomposer/impl/src/main/kotlin/io/element/android/libraries/textcomposer/SoftKeyboardEffect.kt @@ -18,6 +18,8 @@ package io.element.android.libraries.textcomposer import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect +import androidx.compose.runtime.getValue +import androidx.compose.runtime.rememberUpdatedState import androidx.compose.ui.platform.LocalView import androidx.compose.ui.viewinterop.AndroidView import io.element.android.libraries.androidutils.ui.awaitWindowFocus @@ -40,7 +42,8 @@ internal fun SoftKeyboardEffect( predicate: (T) -> Boolean, ) { val view = LocalView.current - LaunchedEffect(key) { + val latestOnRequestFocus by rememberUpdatedState(onRequestFocus) + LaunchedEffect(key, predicate) { if (predicate(key)) { // Await window focus in case returning from a dialog view.awaitWindowFocus() @@ -49,7 +52,7 @@ internal fun SoftKeyboardEffect( view.showKeyboard(andRequestFocus = true) // Refocus to the correct view - onRequestFocus() + latestOnRequestFocus() } } } diff --git a/libraries/textcomposer/impl/src/main/kotlin/io/element/android/libraries/textcomposer/TextComposer.kt b/libraries/textcomposer/impl/src/main/kotlin/io/element/android/libraries/textcomposer/TextComposer.kt index 06585d3b31..252e35d652 100644 --- a/libraries/textcomposer/impl/src/main/kotlin/io/element/android/libraries/textcomposer/TextComposer.kt +++ b/libraries/textcomposer/impl/src/main/kotlin/io/element/android/libraries/textcomposer/TextComposer.kt @@ -42,6 +42,7 @@ import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.derivedStateOf import androidx.compose.runtime.getValue import androidx.compose.runtime.remember +import androidx.compose.runtime.rememberUpdatedState import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip @@ -274,12 +275,13 @@ fun TextComposer( } val menuAction = state.menuAction + val latestOnSuggestionReceived by rememberUpdatedState(onSuggestionReceived) LaunchedEffect(menuAction) { if (menuAction is MenuAction.Suggestion) { val suggestion = Suggestion(menuAction.suggestionPattern) - onSuggestionReceived(suggestion) + latestOnSuggestionReceived(suggestion) } else { - onSuggestionReceived(null) + latestOnSuggestionReceived(null) } } } From eb51b49aefe472c6ed38bd33d8acd9951a2f5963 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Tue, 23 Jan 2024 18:13:02 +0100 Subject: [PATCH 075/127] Always use the `latest...` fix. --- .../ftue/impl/migration/MigrationScreenView.kt | 7 +++++-- .../android/features/invitelist/impl/InviteListView.kt | 7 +++++-- .../login/impl/changeserver/ChangeServerView.kt | 9 +++++++-- .../features/logout/impl/ui/LogoutActionDialog.kt | 10 +++++++--- .../android/features/messages/impl/MessagesView.kt | 9 +++++++-- .../impl/attachments/preview/AttachmentsPreviewView.kt | 7 +++++-- .../rageshake/api/detection/RageshakeDetectionView.kt | 7 +++++-- .../designsystem/components/async/AsyncActionView.kt | 7 +++++-- .../libraries/textcomposer/SoftKeyboardEffect.kt | 5 +++-- 9 files changed, 49 insertions(+), 19 deletions(-) diff --git a/features/ftue/impl/src/main/kotlin/io/element/android/features/ftue/impl/migration/MigrationScreenView.kt b/features/ftue/impl/src/main/kotlin/io/element/android/features/ftue/impl/migration/MigrationScreenView.kt index a365b1e4dc..54a1b541be 100644 --- a/features/ftue/impl/src/main/kotlin/io/element/android/features/ftue/impl/migration/MigrationScreenView.kt +++ b/features/ftue/impl/src/main/kotlin/io/element/android/features/ftue/impl/migration/MigrationScreenView.kt @@ -18,6 +18,8 @@ package io.element.android.features.ftue.impl.migration import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect +import androidx.compose.runtime.getValue +import androidx.compose.runtime.rememberUpdatedState import androidx.compose.ui.Modifier import androidx.compose.ui.res.stringResource import io.element.android.features.ftue.impl.R @@ -32,8 +34,9 @@ fun MigrationScreenView( modifier: Modifier = Modifier, ) { if (migrationState.isMigrating.not()) { - LaunchedEffect(onMigrationFinished) { - onMigrationFinished() + val latestOnMigrationFinished by rememberUpdatedState(onMigrationFinished) + LaunchedEffect(Unit) { + latestOnMigrationFinished() } } SunsetPage( diff --git a/features/invitelist/impl/src/main/kotlin/io/element/android/features/invitelist/impl/InviteListView.kt b/features/invitelist/impl/src/main/kotlin/io/element/android/features/invitelist/impl/InviteListView.kt index 93d552237f..ff8ba55c0b 100644 --- a/features/invitelist/impl/src/main/kotlin/io/element/android/features/invitelist/impl/InviteListView.kt +++ b/features/invitelist/impl/src/main/kotlin/io/element/android/features/invitelist/impl/InviteListView.kt @@ -28,6 +28,8 @@ import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.MaterialTheme import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect +import androidx.compose.runtime.getValue +import androidx.compose.runtime.rememberUpdatedState import androidx.compose.ui.Modifier import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.style.TextAlign @@ -57,8 +59,9 @@ fun InviteListView( modifier: Modifier = Modifier, ) { if (state.acceptedAction is AsyncData.Success) { - LaunchedEffect(state.acceptedAction, onInviteAccepted) { - onInviteAccepted(state.acceptedAction.data) + val latestOnInviteAccepted by rememberUpdatedState(onInviteAccepted) + LaunchedEffect(state.acceptedAction) { + latestOnInviteAccepted(state.acceptedAction.data) } } diff --git a/features/login/impl/src/main/kotlin/io/element/android/features/login/impl/changeserver/ChangeServerView.kt b/features/login/impl/src/main/kotlin/io/element/android/features/login/impl/changeserver/ChangeServerView.kt index ea18ec407e..9f71ccc7e5 100644 --- a/features/login/impl/src/main/kotlin/io/element/android/features/login/impl/changeserver/ChangeServerView.kt +++ b/features/login/impl/src/main/kotlin/io/element/android/features/login/impl/changeserver/ChangeServerView.kt @@ -18,6 +18,8 @@ package io.element.android.features.login.impl.changeserver import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect +import androidx.compose.runtime.getValue +import androidx.compose.runtime.rememberUpdatedState import androidx.compose.ui.Modifier import androidx.compose.ui.tooling.preview.PreviewParameter import io.element.android.features.login.impl.dialogs.SlidingSyncNotSupportedDialog @@ -63,8 +65,11 @@ fun ChangeServerView( } } is AsyncData.Loading -> ProgressDialog() - is AsyncData.Success -> LaunchedEffect(state.changeServerAction, onDone) { - onDone() + is AsyncData.Success -> { + val latestOnDone by rememberUpdatedState(onDone) + LaunchedEffect(state.changeServerAction) { + latestOnDone() + } } AsyncData.Uninitialized -> Unit } diff --git a/features/logout/impl/src/main/kotlin/io/element/android/features/logout/impl/ui/LogoutActionDialog.kt b/features/logout/impl/src/main/kotlin/io/element/android/features/logout/impl/ui/LogoutActionDialog.kt index b626836c8b..bf103745b4 100644 --- a/features/logout/impl/src/main/kotlin/io/element/android/features/logout/impl/ui/LogoutActionDialog.kt +++ b/features/logout/impl/src/main/kotlin/io/element/android/features/logout/impl/ui/LogoutActionDialog.kt @@ -18,6 +18,8 @@ package io.element.android.features.logout.impl.ui import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect +import androidx.compose.runtime.getValue +import androidx.compose.runtime.rememberUpdatedState import androidx.compose.ui.res.stringResource import io.element.android.features.logout.impl.R import io.element.android.libraries.architecture.AsyncAction @@ -52,9 +54,11 @@ fun LogoutActionDialog( onRetry = onForceLogoutClicked, onDismiss = onDismissError, ) - is AsyncAction.Success -> - LaunchedEffect(state, onSuccessLogout) { - onSuccessLogout(state.data) + is AsyncAction.Success -> { + val latestOnSuccessLogout by rememberUpdatedState(onSuccessLogout) + LaunchedEffect(state) { + latestOnSuccessLogout(state.data) } + } } } diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/MessagesView.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/MessagesView.kt index 8098f2516c..be3afb6660 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/MessagesView.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/MessagesView.kt @@ -41,8 +41,10 @@ import androidx.compose.material3.MaterialTheme import androidx.compose.runtime.Composable import androidx.compose.runtime.DisposableEffect import androidx.compose.runtime.LaunchedEffect +import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableIntStateOf import androidx.compose.runtime.remember +import androidx.compose.runtime.rememberUpdatedState import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.geometry.Offset @@ -294,8 +296,11 @@ private fun AttachmentStateView( ) { when (state) { AttachmentsState.None -> Unit - is AttachmentsState.Previewing -> LaunchedEffect(state, onPreviewAttachments) { - onPreviewAttachments(state.attachments) + is AttachmentsState.Previewing -> { + val latestOnPreviewAttachments by rememberUpdatedState(onPreviewAttachments) + LaunchedEffect(state) { + latestOnPreviewAttachments(state.attachments) + } } is AttachmentsState.Sending -> { ProgressDialog( diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/attachments/preview/AttachmentsPreviewView.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/attachments/preview/AttachmentsPreviewView.kt index 5dc7875afc..b18d36d61d 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/attachments/preview/AttachmentsPreviewView.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/attachments/preview/AttachmentsPreviewView.kt @@ -24,6 +24,8 @@ import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.padding import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect +import androidx.compose.runtime.getValue +import androidx.compose.runtime.rememberUpdatedState import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.res.stringResource @@ -57,8 +59,9 @@ fun AttachmentsPreviewView( } if (state.sendActionState is SendActionState.Done) { - LaunchedEffect(state.sendActionState, onDismiss) { - onDismiss() + val latestOnDismiss by rememberUpdatedState(onDismiss) + LaunchedEffect(state.sendActionState) { + latestOnDismiss() } } diff --git a/features/rageshake/api/src/main/kotlin/io/element/android/features/rageshake/api/detection/RageshakeDetectionView.kt b/features/rageshake/api/src/main/kotlin/io/element/android/features/rageshake/api/detection/RageshakeDetectionView.kt index 5982edfdc8..e076ceb1a6 100644 --- a/features/rageshake/api/src/main/kotlin/io/element/android/features/rageshake/api/detection/RageshakeDetectionView.kt +++ b/features/rageshake/api/src/main/kotlin/io/element/android/features/rageshake/api/detection/RageshakeDetectionView.kt @@ -18,6 +18,8 @@ package io.element.android.features.rageshake.api.detection import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect +import androidx.compose.runtime.getValue +import androidx.compose.runtime.rememberUpdatedState import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.platform.LocalView import androidx.compose.ui.res.stringResource @@ -73,9 +75,10 @@ private fun TakeScreenshot( onScreenshotTaken: (ImageResult) -> Unit ) { val view = LocalView.current - LaunchedEffect(onScreenshotTaken) { + val latestOnScreenshotTaken by rememberUpdatedState(onScreenshotTaken) + LaunchedEffect(Unit) { view.screenshot { - onScreenshotTaken(it) + latestOnScreenshotTaken(it) } } } diff --git a/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/components/async/AsyncActionView.kt b/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/components/async/AsyncActionView.kt index 102769b7be..f82553d731 100644 --- a/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/components/async/AsyncActionView.kt +++ b/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/components/async/AsyncActionView.kt @@ -18,6 +18,8 @@ package io.element.android.libraries.designsystem.components.async import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect +import androidx.compose.runtime.getValue +import androidx.compose.runtime.rememberUpdatedState import androidx.compose.ui.tooling.preview.PreviewParameter import io.element.android.libraries.architecture.AsyncAction import io.element.android.libraries.designsystem.components.ProgressDialog @@ -67,8 +69,9 @@ fun AsyncActionView( } } is AsyncAction.Success -> { - LaunchedEffect(async, onSuccess) { - onSuccess(async.data) + val latestOnSuccess by rememberUpdatedState(onSuccess) + LaunchedEffect(async) { + latestOnSuccess(async.data) } } } diff --git a/libraries/textcomposer/impl/src/main/kotlin/io/element/android/libraries/textcomposer/SoftKeyboardEffect.kt b/libraries/textcomposer/impl/src/main/kotlin/io/element/android/libraries/textcomposer/SoftKeyboardEffect.kt index 90e9591953..fd5f043b32 100644 --- a/libraries/textcomposer/impl/src/main/kotlin/io/element/android/libraries/textcomposer/SoftKeyboardEffect.kt +++ b/libraries/textcomposer/impl/src/main/kotlin/io/element/android/libraries/textcomposer/SoftKeyboardEffect.kt @@ -43,8 +43,9 @@ internal fun SoftKeyboardEffect( ) { val view = LocalView.current val latestOnRequestFocus by rememberUpdatedState(onRequestFocus) - LaunchedEffect(key, predicate) { - if (predicate(key)) { + val latestPredicate by rememberUpdatedState(predicate) + LaunchedEffect(key) { + if (latestPredicate(key)) { // Await window focus in case returning from a dialog view.awaitWindowFocus() From da4825aa44668be8b3593ec4aed220f1a4d4603d Mon Sep 17 00:00:00 2001 From: Jorge Martin Espinosa Date: Tue, 23 Jan 2024 18:23:20 +0100 Subject: [PATCH 076/127] Return cached room members before fetching new ones, do it in batches (#2274) * Use cached users from the Rust SDK. Also lazy load received users by batches. * Create `RoomMemberListFetcher` to wrap all the room member loading logic * Ensure we clear `RoomMember` Rust references if the fetching coroutine is canceled --- .../android/appnav/room/RoomLoadedFlowNode.kt | 9 +- .../roomdetails/impl/RoomDetailsPresenter.kt | 10 +- .../impl/members/RoomMemberListDataSource.kt | 10 +- .../impl/members/RoomMemberListPresenter.kt | 9 +- .../roomdetails/RoomDetailsPresenterTests.kt | 79 +++-- .../members/RoomMemberListPresenterTests.kt | 7 +- .../libraries/matrix/api/room/MatrixRoom.kt | 2 +- libraries/matrix/impl/build.gradle.kts | 1 + ...imelineEventToNotificationContentMapper.kt | 2 +- .../matrix/impl/room/MatrixRoomInfoMapper.kt | 1 + .../matrix/impl/room/RustMatrixRoom.kt | 42 +-- .../impl/room/member/RoomMemberListFetcher.kt | 129 ++++++++ .../room/{ => member}/RoomMemberMapper.kt | 4 +- .../roomlist/RoomSummaryDetailsFactory.kt | 2 +- .../room/member/RoomMemberListFetcherTest.kt | 303 ++++++++++++++++++ .../matrix/test/room/FakeMatrixRoom.kt | 4 +- .../tests/testutils/WithFakeLifecycleOwner.kt | 49 +++ 17 files changed, 579 insertions(+), 84 deletions(-) create mode 100644 libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/room/member/RoomMemberListFetcher.kt rename libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/room/{ => member}/RoomMemberMapper.kt (94%) create mode 100644 libraries/matrix/impl/src/test/kotlin/io/element/android/libraries/matrix/impl/room/member/RoomMemberListFetcherTest.kt create mode 100644 tests/testutils/src/main/kotlin/io/element/android/tests/testutils/WithFakeLifecycleOwner.kt diff --git a/appnav/src/main/kotlin/io/element/android/appnav/room/RoomLoadedFlowNode.kt b/appnav/src/main/kotlin/io/element/android/appnav/room/RoomLoadedFlowNode.kt index d6ea4fc533..21e412ef63 100644 --- a/appnav/src/main/kotlin/io/element/android/appnav/room/RoomLoadedFlowNode.kt +++ b/appnav/src/main/kotlin/io/element/android/appnav/room/RoomLoadedFlowNode.kt @@ -118,14 +118,7 @@ class RoomLoadedFlowNode @AssistedInject constructor( } private fun fetchRoomMembers() = lifecycleScope.launch { - val room = inputs.room - room.updateMembers() - .onFailure { - Timber.e(it, "Fail to fetch members for room ${room.roomId}") - } - .onSuccess { - Timber.v("Success fetching members for room ${room.roomId}") - } + inputs.room.updateMembers() } private fun createRoomDetailsNode(buildContext: BuildContext, initialTarget: RoomDetailsEntryPoint.InitialTarget): Node { diff --git a/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/RoomDetailsPresenter.kt b/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/RoomDetailsPresenter.kt index c832cab666..a232d4e87e 100644 --- a/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/RoomDetailsPresenter.kt +++ b/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/RoomDetailsPresenter.kt @@ -26,11 +26,13 @@ import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.produceState import androidx.compose.runtime.remember import androidx.compose.runtime.rememberCoroutineScope +import androidx.lifecycle.Lifecycle import io.element.android.features.leaveroom.api.LeaveRoomEvent import io.element.android.features.leaveroom.api.LeaveRoomPresenter import io.element.android.features.roomdetails.impl.members.details.RoomMemberDetailsPresenter import io.element.android.libraries.architecture.Presenter import io.element.android.libraries.core.coroutine.CoroutineDispatchers +import io.element.android.libraries.designsystem.utils.OnLifecycleEvent import io.element.android.libraries.featureflag.api.FeatureFlagService import io.element.android.libraries.featureflag.api.FeatureFlags import io.element.android.libraries.matrix.api.MatrixClient @@ -76,7 +78,13 @@ class RoomDetailsPresenter @Inject constructor( room.updateRoomNotificationSettings() observeNotificationSettings() } - room.updateMembers() + } + + // Update room members only when first presenting the node + OnLifecycleEvent { _, event -> + if (event == Lifecycle.Event.ON_CREATE) { + scope.launch { room.updateMembers() } + } } val membersState by room.membersStateFlow.collectAsState() diff --git a/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/members/RoomMemberListDataSource.kt b/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/members/RoomMemberListDataSource.kt index 867ecd991f..faf1f9fc78 100644 --- a/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/members/RoomMemberListDataSource.kt +++ b/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/members/RoomMemberListDataSource.kt @@ -19,11 +19,8 @@ package io.element.android.features.roomdetails.impl.members import io.element.android.libraries.core.bool.orFalse import io.element.android.libraries.core.coroutine.CoroutineDispatchers import io.element.android.libraries.matrix.api.room.MatrixRoom -import io.element.android.libraries.matrix.api.room.MatrixRoomMembersState import io.element.android.libraries.matrix.api.room.RoomMember import io.element.android.libraries.matrix.api.room.roomMembers -import kotlinx.coroutines.flow.dropWhile -import kotlinx.coroutines.flow.first import kotlinx.coroutines.withContext import javax.inject.Inject @@ -32,11 +29,8 @@ class RoomMemberListDataSource @Inject constructor( private val coroutineDispatchers: CoroutineDispatchers, ) { suspend fun search(query: String): List = withContext(coroutineDispatchers.io) { - val roomMembers = room.membersStateFlow - .dropWhile { it !is MatrixRoomMembersState.Ready } - .first() - .roomMembers() - .orEmpty() + val roomMembersState = room.membersStateFlow.value + val roomMembers = roomMembersState.roomMembers().orEmpty() val filteredMembers = if (query.isBlank()) { roomMembers } else { diff --git a/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/members/RoomMemberListPresenter.kt b/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/members/RoomMemberListPresenter.kt index 6fc5b6ece7..399a2ad1e1 100644 --- a/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/members/RoomMemberListPresenter.kt +++ b/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/members/RoomMemberListPresenter.kt @@ -30,8 +30,10 @@ import io.element.android.libraries.architecture.Presenter import io.element.android.libraries.core.coroutine.CoroutineDispatchers import io.element.android.libraries.designsystem.theme.components.SearchBarResultState import io.element.android.libraries.matrix.api.room.MatrixRoom +import io.element.android.libraries.matrix.api.room.MatrixRoomMembersState import io.element.android.libraries.matrix.api.room.RoomMembershipState import io.element.android.libraries.matrix.api.room.powerlevels.canInvite +import io.element.android.libraries.matrix.api.room.roomMembers import kotlinx.collections.immutable.toImmutableList import kotlinx.coroutines.withContext import javax.inject.Inject @@ -55,9 +57,12 @@ class RoomMemberListPresenter @Inject constructor( value = room.canInvite().getOrElse { false } } - LaunchedEffect(Unit) { + LaunchedEffect(membersState) { + if (membersState is MatrixRoomMembersState.Unknown) { + return@LaunchedEffect + } withContext(coroutineDispatchers.io) { - val members = roomMemberListDataSource.search("").groupBy { it.membership } + val members = membersState.roomMembers().orEmpty().groupBy { it.membership } roomMembers = AsyncData.Success( RoomMembers( invited = members.getOrDefault(RoomMembershipState.INVITE, emptyList()).toImmutableList(), diff --git a/features/roomdetails/impl/src/test/kotlin/io/element/android/features/roomdetails/RoomDetailsPresenterTests.kt b/features/roomdetails/impl/src/test/kotlin/io/element/android/features/roomdetails/RoomDetailsPresenterTests.kt index 95deffad31..299a8120a5 100644 --- a/features/roomdetails/impl/src/test/kotlin/io/element/android/features/roomdetails/RoomDetailsPresenterTests.kt +++ b/features/roomdetails/impl/src/test/kotlin/io/element/android/features/roomdetails/RoomDetailsPresenterTests.kt @@ -16,6 +16,7 @@ package io.element.android.features.roomdetails +import androidx.lifecycle.Lifecycle import app.cash.molecule.RecompositionMode import app.cash.molecule.moleculeFlow import app.cash.turbine.test @@ -47,9 +48,11 @@ import io.element.android.libraries.matrix.test.FakeMatrixClient import io.element.android.libraries.matrix.test.notificationsettings.FakeNotificationSettingsService import io.element.android.libraries.matrix.test.room.FakeMatrixRoom import io.element.android.libraries.matrix.test.room.aRoomInfo +import io.element.android.tests.testutils.FakeLifecycleOwner import io.element.android.tests.testutils.WarmUpRule import io.element.android.tests.testutils.consumeItemsUntilPredicate import io.element.android.tests.testutils.testCoroutineDispatchers +import io.element.android.tests.testutils.withFakeLifecycleOwner import kotlinx.collections.immutable.persistentListOf import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.test.TestScope @@ -63,6 +66,10 @@ class RoomDetailsPresenterTests { @get:Rule val warmUpRule = WarmUpRule() + private val fakeLifecycleOwner = FakeLifecycleOwner().apply { + givenState(Lifecycle.State.RESUMED) + } + private fun TestScope.createRoomDetailsPresenter( room: MatrixRoom, leaveRoomPresenter: LeaveRoomPresenter = FakeLeaveRoomPresenter(), @@ -94,7 +101,9 @@ class RoomDetailsPresenterTests { val room = aMatrixRoom() val presenter = createRoomDetailsPresenter(room) moleculeFlow(RecompositionMode.Immediate) { - presenter.present() + withFakeLifecycleOwner(fakeLifecycleOwner) { + presenter.present() + } }.test { val initialState = awaitItem() assertThat(initialState.roomId).isEqualTo(room.roomId.value) @@ -116,7 +125,9 @@ class RoomDetailsPresenterTests { } val presenter = createRoomDetailsPresenter(room) moleculeFlow(RecompositionMode.Immediate) { - presenter.present() + withFakeLifecycleOwner(fakeLifecycleOwner) { + presenter.present() + } }.test { skipItems(1) val updatedState = awaitItem() @@ -133,7 +144,9 @@ class RoomDetailsPresenterTests { val room = aMatrixRoom(name = null) val presenter = createRoomDetailsPresenter(room) moleculeFlow(RecompositionMode.Immediate) { - presenter.present() + withFakeLifecycleOwner(fakeLifecycleOwner) { + presenter.present() + } }.test { val initialState = awaitItem() assertThat(initialState.roomName).isEqualTo(room.displayName) @@ -155,7 +168,9 @@ class RoomDetailsPresenterTests { } val presenter = createRoomDetailsPresenter(room) moleculeFlow(RecompositionMode.Immediate) { - presenter.present() + withFakeLifecycleOwner(fakeLifecycleOwner) { + presenter.present() + } }.test { val initialState = awaitItem() assertThat(initialState.roomType).isEqualTo(RoomDetailsType.Dm(otherRoomMember)) @@ -171,7 +186,9 @@ class RoomDetailsPresenterTests { } val presenter = createRoomDetailsPresenter(room, dispatchers = testCoroutineDispatchers()) moleculeFlow(RecompositionMode.Immediate) { - presenter.present() + withFakeLifecycleOwner(fakeLifecycleOwner) { + presenter.present() + } }.test { // Initially false assertThat(awaitItem().canInvite).isFalse() @@ -189,7 +206,9 @@ class RoomDetailsPresenterTests { } val presenter = createRoomDetailsPresenter(room) moleculeFlow(RecompositionMode.Immediate) { - presenter.present() + withFakeLifecycleOwner(fakeLifecycleOwner) { + presenter.present() + } }.test { assertThat(awaitItem().canInvite).isFalse() @@ -204,7 +223,9 @@ class RoomDetailsPresenterTests { } val presenter = createRoomDetailsPresenter(room) moleculeFlow(RecompositionMode.Immediate) { - presenter.present() + withFakeLifecycleOwner(fakeLifecycleOwner) { + presenter.present() + } }.test { assertThat(awaitItem().canInvite).isFalse() @@ -222,7 +243,9 @@ class RoomDetailsPresenterTests { } val presenter = createRoomDetailsPresenter(room) moleculeFlow(RecompositionMode.Immediate) { - presenter.present() + withFakeLifecycleOwner(fakeLifecycleOwner) { + presenter.present() + } }.test { // Initially false assertThat(awaitItem().canEdit).isFalse() @@ -251,7 +274,9 @@ class RoomDetailsPresenterTests { } val presenter = createRoomDetailsPresenter(room) moleculeFlow(RecompositionMode.Immediate) { - presenter.present() + withFakeLifecycleOwner(fakeLifecycleOwner) { + presenter.present() + } }.test { // Initially false assertThat(awaitItem().canEdit).isFalse() @@ -281,7 +306,9 @@ class RoomDetailsPresenterTests { } val presenter = createRoomDetailsPresenter(room) moleculeFlow(RecompositionMode.Immediate) { - presenter.present() + withFakeLifecycleOwner(fakeLifecycleOwner) { + presenter.present() + } }.test { skipItems(1) @@ -302,7 +329,9 @@ class RoomDetailsPresenterTests { } val presenter = createRoomDetailsPresenter(room) moleculeFlow(RecompositionMode.Immediate) { - presenter.present() + withFakeLifecycleOwner(fakeLifecycleOwner) { + presenter.present() + } }.test { // Initially false assertThat(awaitItem().canEdit).isFalse() @@ -323,7 +352,9 @@ class RoomDetailsPresenterTests { } val presenter = createRoomDetailsPresenter(room) moleculeFlow(RecompositionMode.Immediate) { - presenter.present() + withFakeLifecycleOwner(fakeLifecycleOwner) { + presenter.present() + } }.test { // Initially false, and no further events assertThat(awaitItem().canEdit).isFalse() @@ -341,7 +372,9 @@ class RoomDetailsPresenterTests { val presenter = createRoomDetailsPresenter(room) moleculeFlow(RecompositionMode.Immediate) { - presenter.present() + withFakeLifecycleOwner(fakeLifecycleOwner) { + presenter.present() + } }.test { // The initial state is "hidden" and no further state changes happen assertThat(awaitItem().roomTopic).isEqualTo(RoomTopicState.Hidden) @@ -360,7 +393,9 @@ class RoomDetailsPresenterTests { val presenter = createRoomDetailsPresenter(room) moleculeFlow(RecompositionMode.Immediate) { - presenter.present() + withFakeLifecycleOwner(fakeLifecycleOwner) { + presenter.present() + } }.test { // Ignore the initial state skipItems(1) @@ -382,7 +417,9 @@ class RoomDetailsPresenterTests { dispatchers = testCoroutineDispatchers() ) moleculeFlow(RecompositionMode.Immediate) { - presenter.present() + withFakeLifecycleOwner(fakeLifecycleOwner) { + presenter.present() + } }.test { awaitItem().eventSink(RoomDetailsEvent.LeaveRoom) @@ -403,7 +440,9 @@ class RoomDetailsPresenterTests { notificationSettingsService = notificationSettingsService, ) moleculeFlow(RecompositionMode.Immediate) { - presenter.present() + withFakeLifecycleOwner(fakeLifecycleOwner) { + presenter.present() + } }.test { notificationSettingsService.setRoomNotificationMode(room.roomId, RoomNotificationMode.MENTIONS_AND_KEYWORDS_ONLY) val updatedState = consumeItemsUntilPredicate { @@ -420,7 +459,9 @@ class RoomDetailsPresenterTests { val room = aMatrixRoom(notificationSettingsService = notificationSettingsService) val presenter = createRoomDetailsPresenter(room = room, notificationSettingsService = notificationSettingsService) moleculeFlow(RecompositionMode.Immediate) { - presenter.present() + withFakeLifecycleOwner(fakeLifecycleOwner) { + presenter.present() + } }.test { awaitItem().eventSink(RoomDetailsEvent.MuteNotification) val updatedState = consumeItemsUntilPredicate(timeout = 250.milliseconds) { @@ -440,7 +481,9 @@ class RoomDetailsPresenterTests { val room = aMatrixRoom(notificationSettingsService = notificationSettingsService) val presenter = createRoomDetailsPresenter(room = room, notificationSettingsService = notificationSettingsService) moleculeFlow(RecompositionMode.Immediate) { - presenter.present() + withFakeLifecycleOwner(fakeLifecycleOwner) { + presenter.present() + } }.test { awaitItem().eventSink(RoomDetailsEvent.UnmuteNotification) val updatedState = consumeItemsUntilPredicate { diff --git a/features/roomdetails/impl/src/test/kotlin/io/element/android/features/roomdetails/members/RoomMemberListPresenterTests.kt b/features/roomdetails/impl/src/test/kotlin/io/element/android/features/roomdetails/members/RoomMemberListPresenterTests.kt index a869bb5e04..88e9c7df86 100644 --- a/features/roomdetails/impl/src/test/kotlin/io/element/android/features/roomdetails/members/RoomMemberListPresenterTests.kt +++ b/features/roomdetails/impl/src/test/kotlin/io/element/android/features/roomdetails/members/RoomMemberListPresenterTests.kt @@ -47,15 +47,20 @@ class RoomMemberListPresenterTests { @Test fun `search is done automatically on start, but is async`() = runTest { - val presenter = createPresenter() + val room = FakeMatrixRoom() + val presenter = createPresenter(matrixRoom = room) moleculeFlow(RecompositionMode.Immediate) { presenter.present() }.test { + skipItems(1) val initialState = awaitItem() assertThat(initialState.roomMembers).isInstanceOf(AsyncData.Loading::class.java) assertThat(initialState.searchQuery).isEmpty() assertThat(initialState.searchResults).isInstanceOf(SearchBarResultState.Initial::class.java) assertThat(initialState.isSearchActive).isFalse() + room.givenRoomMembersState(MatrixRoomMembersState.Ready(aRoomMemberList())) + // Skip item while the new members state is processed + skipItems(1) val loadedState = awaitItem() assertThat(loadedState.roomMembers).isInstanceOf(AsyncData.Success::class.java) assertThat((loadedState.roomMembers as AsyncData.Success).data.invited).isEqualTo(listOf(aVictor(), aWalter())) diff --git a/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/room/MatrixRoom.kt b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/room/MatrixRoom.kt index af6cd81fb2..41043d8ba5 100644 --- a/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/room/MatrixRoom.kt +++ b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/room/MatrixRoom.kt @@ -75,7 +75,7 @@ interface MatrixRoom : Closeable { /** * Try to load the room members and update the membersFlow. */ - suspend fun updateMembers(): Result + suspend fun updateMembers() suspend fun updateRoomNotificationSettings(): Result diff --git a/libraries/matrix/impl/build.gradle.kts b/libraries/matrix/impl/build.gradle.kts index 41c84a0384..8815214dd6 100644 --- a/libraries/matrix/impl/build.gradle.kts +++ b/libraries/matrix/impl/build.gradle.kts @@ -53,4 +53,5 @@ dependencies { testImplementation(libs.test.truth) testImplementation(projects.libraries.matrix.test) testImplementation(libs.coroutines.test) + testImplementation(libs.test.turbine) } diff --git a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/notification/TimelineEventToNotificationContentMapper.kt b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/notification/TimelineEventToNotificationContentMapper.kt index cc14fad815..6526120328 100644 --- a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/notification/TimelineEventToNotificationContentMapper.kt +++ b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/notification/TimelineEventToNotificationContentMapper.kt @@ -18,7 +18,7 @@ package io.element.android.libraries.matrix.impl.notification import io.element.android.libraries.matrix.api.core.UserId import io.element.android.libraries.matrix.api.notification.NotificationContent -import io.element.android.libraries.matrix.impl.room.RoomMemberMapper +import io.element.android.libraries.matrix.impl.room.member.RoomMemberMapper import io.element.android.libraries.matrix.impl.timeline.item.event.EventMessageMapper import org.matrix.rustcomponents.sdk.MessageLikeEventContent import org.matrix.rustcomponents.sdk.StateEventContent diff --git a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/room/MatrixRoomInfoMapper.kt b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/room/MatrixRoomInfoMapper.kt index b2a13fbe4a..909649441f 100644 --- a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/room/MatrixRoomInfoMapper.kt +++ b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/room/MatrixRoomInfoMapper.kt @@ -19,6 +19,7 @@ package io.element.android.libraries.matrix.impl.room import io.element.android.libraries.matrix.api.room.CurrentUserMembership import io.element.android.libraries.matrix.api.room.MatrixRoomInfo import io.element.android.libraries.matrix.api.room.RoomNotificationMode +import io.element.android.libraries.matrix.impl.room.member.RoomMemberMapper import io.element.android.libraries.matrix.impl.timeline.item.event.EventTimelineItemMapper import kotlinx.collections.immutable.toImmutableList import org.matrix.rustcomponents.sdk.use diff --git a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/room/RustMatrixRoom.kt b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/room/RustMatrixRoom.kt index c9a89e558e..647586431a 100644 --- a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/room/RustMatrixRoom.kt +++ b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/room/RustMatrixRoom.kt @@ -18,7 +18,6 @@ package io.element.android.libraries.matrix.impl.room import io.element.android.libraries.core.coroutine.CoroutineDispatchers import io.element.android.libraries.core.coroutine.childScope -import io.element.android.libraries.core.coroutine.parallelMap import io.element.android.libraries.matrix.api.core.EventId import io.element.android.libraries.matrix.api.core.ProgressCallback import io.element.android.libraries.matrix.api.core.RoomId @@ -39,7 +38,6 @@ import io.element.android.libraries.matrix.api.room.Mention import io.element.android.libraries.matrix.api.room.MessageEventType import io.element.android.libraries.matrix.api.room.StateEventType import io.element.android.libraries.matrix.api.room.location.AssetType -import io.element.android.libraries.matrix.api.room.roomMembers import io.element.android.libraries.matrix.api.room.roomNotificationSettings import io.element.android.libraries.matrix.api.timeline.MatrixTimeline import io.element.android.libraries.matrix.api.widget.MatrixWidgetDriver @@ -51,20 +49,17 @@ import io.element.android.libraries.matrix.impl.media.toMSC3246range import io.element.android.libraries.matrix.impl.notificationsettings.RustNotificationSettingsService import io.element.android.libraries.matrix.impl.poll.toInner import io.element.android.libraries.matrix.impl.room.location.toInner +import io.element.android.libraries.matrix.impl.room.member.RoomMemberListFetcher import io.element.android.libraries.matrix.impl.timeline.AsyncMatrixTimeline import io.element.android.libraries.matrix.impl.timeline.RustMatrixTimeline -import io.element.android.libraries.matrix.impl.util.destroyAll import io.element.android.libraries.matrix.impl.util.mxCallbackFlow import io.element.android.libraries.matrix.impl.widget.RustWidgetDriver import io.element.android.libraries.matrix.impl.widget.generateWidgetWebViewUrl import io.element.android.libraries.sessionstorage.api.SessionData import io.element.android.services.toolbox.api.systemclock.SystemClock -import kotlinx.collections.immutable.toImmutableList -import kotlinx.coroutines.CancellationException import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.cancel -import kotlinx.coroutines.ensureActive import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.StateFlow @@ -75,7 +70,6 @@ import org.matrix.rustcomponents.sdk.EventTimelineItem import org.matrix.rustcomponents.sdk.RoomInfo import org.matrix.rustcomponents.sdk.RoomInfoListener import org.matrix.rustcomponents.sdk.RoomListItem -import org.matrix.rustcomponents.sdk.RoomMember import org.matrix.rustcomponents.sdk.RoomMessageEventContentWithoutRelation import org.matrix.rustcomponents.sdk.SendAttachmentJoinHandle import org.matrix.rustcomponents.sdk.WidgetCapabilities @@ -125,8 +119,8 @@ class RustMatrixRoom( private val roomMembersDispatcher = coroutineDispatchers.io.limitedParallelism(8) private val roomCoroutineScope = sessionCoroutineScope.childScope(coroutineDispatchers.main, "RoomScope-$roomId") - private val _membersStateFlow = MutableStateFlow(MatrixRoomMembersState.Unknown) private val _syncUpdateFlow = MutableStateFlow(0L) + private val roomMemberListFetcher = RoomMemberListFetcher(innerRoom, roomMembersDispatcher) private val _roomNotificationSettingsStateFlow = MutableStateFlow(MatrixRoomNotificationSettingsState.Unknown) override val roomNotificationSettingsStateFlow: StateFlow = _roomNotificationSettingsStateFlow @@ -135,7 +129,7 @@ class RustMatrixRoom( _syncUpdateFlow.value = systemClock.epochMillis() } - override val membersStateFlow: StateFlow = _membersStateFlow.asStateFlow() + override val membersStateFlow: StateFlow = roomMemberListFetcher.membersFlow override val syncUpdateFlow: StateFlow = _syncUpdateFlow.asStateFlow() @@ -192,35 +186,7 @@ class RustMatrixRoom( override val activeMemberCount: Long get() = innerRoom.activeMembersCount().toLong() - override suspend fun updateMembers(): Result = withContext(roomMembersDispatcher) { - val currentState = _membersStateFlow.value - val currentMembers = currentState.roomMembers()?.toImmutableList() - _membersStateFlow.value = MatrixRoomMembersState.Pending(prevRoomMembers = currentMembers) - var rustMembers: List? = null - try { - rustMembers = innerRoom.members().use { membersIterator -> - buildList { - while (true) { - // Loading the whole membersIterator as a stop-gap measure. - // We should probably implement some sort of paging in the future. - ensureActive() - addAll(membersIterator.nextChunk(1000u) ?: break) - } - } - } - val mappedMembers = rustMembers.parallelMap(RoomMemberMapper::map) - _membersStateFlow.value = MatrixRoomMembersState.Ready(mappedMembers.toImmutableList()) - Result.success(Unit) - } catch (exception: CancellationException) { - _membersStateFlow.value = MatrixRoomMembersState.Error(prevRoomMembers = currentMembers, failure = exception) - throw exception - } catch (exception: Exception) { - _membersStateFlow.value = MatrixRoomMembersState.Error(prevRoomMembers = currentMembers, failure = exception) - Result.failure(exception) - } finally { - rustMembers?.destroyAll() - } - } + override suspend fun updateMembers() = roomMemberListFetcher.fetchRoomMembers() override suspend fun userDisplayName(userId: UserId): Result = withContext(roomDispatcher) { runCatching { diff --git a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/room/member/RoomMemberListFetcher.kt b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/room/member/RoomMemberListFetcher.kt new file mode 100644 index 0000000000..83850f574b --- /dev/null +++ b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/room/member/RoomMemberListFetcher.kt @@ -0,0 +1,129 @@ +/* + * 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 io.element.android.libraries.matrix.impl.room.member + +import io.element.android.libraries.core.coroutine.parallelMap +import io.element.android.libraries.matrix.api.room.MatrixRoomMembersState +import io.element.android.libraries.matrix.api.room.roomMembers +import io.element.android.libraries.matrix.impl.util.destroyAll +import kotlinx.collections.immutable.toImmutableList +import kotlinx.coroutines.CoroutineDispatcher +import kotlinx.coroutines.ensureActive +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.StateFlow +import kotlinx.coroutines.sync.Mutex +import kotlinx.coroutines.sync.withLock +import kotlinx.coroutines.withContext +import org.matrix.rustcomponents.sdk.RoomInterface +import org.matrix.rustcomponents.sdk.RoomMembersIterator +import org.matrix.rustcomponents.sdk.use +import timber.log.Timber +import kotlin.coroutines.cancellation.CancellationException +import kotlin.coroutines.coroutineContext + +/** + * This class fetches the room members for a given room in a 'paginated' way, and taking into account previous cached values. + */ +internal class RoomMemberListFetcher( + private val room: RoomInterface, + private val dispatcher: CoroutineDispatcher, + private val pageSize: Int = 1000, +) { + private val updatedRoomMemberMutex = Mutex() + private val roomId = room.id() + + private val _membersFlow = MutableStateFlow(MatrixRoomMembersState.Unknown) + val membersFlow: StateFlow = _membersFlow + + /** + * Fetches the room members for the given room. + * It will emit the cached members first, and then the updated members in batches of [pageSize] items, through [membersFlow]. + * @param withCache Whether to load the cached members first. Defaults to true. + */ + suspend fun fetchRoomMembers(withCache: Boolean = true) { + if (updatedRoomMemberMutex.isLocked) { + Timber.i("Room members are already being updated for room $roomId") + return + } + updatedRoomMemberMutex.withLock { + withContext(dispatcher) { + // Load cached members as fallback and to get faster results + if (withCache) { + if (_membersFlow.value !is MatrixRoomMembersState.Ready) { + fetchCachedRoomMembers() + } else { + Timber.i("No need to load cached members found for room $roomId") + } + } + + val prevRoomMembers = (_membersFlow.value as? MatrixRoomMembersState.Ready)?.roomMembers?.toImmutableList() + _membersFlow.value = MatrixRoomMembersState.Pending(prevRoomMembers = prevRoomMembers) + + try { + // Start loading new members + parseAndEmitMembers(room.members()) + } catch (exception: CancellationException) { + Timber.d("Cancelled loading updated members for room $roomId") + throw exception + } catch (exception: Exception) { + Timber.e(exception, "Failed to load updated members for room $roomId") + _membersFlow.value = MatrixRoomMembersState.Error(exception, prevRoomMembers) + } + } + } + } + + internal suspend fun fetchCachedRoomMembers() = withContext(dispatcher) { + Timber.i("Loading cached members for room $roomId") + try { + val iterator = room.membersNoSync() + parseAndEmitMembers(iterator) + } catch (exception: CancellationException) { + Timber.d("Cancelled loading cached members for room $roomId") + throw exception + } catch (exception: Exception) { + Timber.e(exception, "Failed to load cached members for room $roomId") + _membersFlow.value = MatrixRoomMembersState.Error(exception, _membersFlow.value.roomMembers()?.toImmutableList()) + } + } + + private suspend fun parseAndEmitMembers(roomMembersIterator: RoomMembersIterator) { + roomMembersIterator.use { iterator -> + val results = buildList { + while (true) { + // Loading the whole membersIterator as a stop-gap measure. + // We should probably implement some sort of paging in the future. + coroutineContext.ensureActive() + val chunk = iterator.nextChunk(pageSize.toUInt()) + val members = try { + // Load next chunk. If null (no more items), exit the loop + chunk?.parallelMap(RoomMemberMapper::map) ?: break + } finally { + // Make sure we clear all member references + chunk?.destroyAll() + } + addAll(members) + Timber.i("Emitting first $size members for room $roomId") + _membersFlow.value = MatrixRoomMembersState.Ready(toImmutableList()) + } + } + if (results.isEmpty()) { + _membersFlow.value = MatrixRoomMembersState.Ready(results.toImmutableList()) + } + } + } +} diff --git a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/room/RoomMemberMapper.kt b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/room/member/RoomMemberMapper.kt similarity index 94% rename from libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/room/RoomMemberMapper.kt rename to libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/room/member/RoomMemberMapper.kt index 3354abbe16..e3d5b37cd4 100644 --- a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/room/RoomMemberMapper.kt +++ b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/room/member/RoomMemberMapper.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 New Vector Ltd + * Copyright (c) 2024 New Vector Ltd * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -14,7 +14,7 @@ * limitations under the License. */ -package io.element.android.libraries.matrix.impl.room +package io.element.android.libraries.matrix.impl.room.member import io.element.android.libraries.matrix.api.core.UserId import io.element.android.libraries.matrix.api.room.RoomMember diff --git a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/roomlist/RoomSummaryDetailsFactory.kt b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/roomlist/RoomSummaryDetailsFactory.kt index d308f2b1d3..59be0ba4ce 100644 --- a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/roomlist/RoomSummaryDetailsFactory.kt +++ b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/roomlist/RoomSummaryDetailsFactory.kt @@ -19,7 +19,7 @@ package io.element.android.libraries.matrix.impl.roomlist import io.element.android.libraries.matrix.api.core.RoomId import io.element.android.libraries.matrix.api.roomlist.RoomSummaryDetails import io.element.android.libraries.matrix.impl.notificationsettings.RoomNotificationSettingsMapper -import io.element.android.libraries.matrix.impl.room.RoomMemberMapper +import io.element.android.libraries.matrix.impl.room.member.RoomMemberMapper import io.element.android.libraries.matrix.impl.room.message.RoomMessageFactory import org.matrix.rustcomponents.sdk.RoomInfo import org.matrix.rustcomponents.sdk.use diff --git a/libraries/matrix/impl/src/test/kotlin/io/element/android/libraries/matrix/impl/room/member/RoomMemberListFetcherTest.kt b/libraries/matrix/impl/src/test/kotlin/io/element/android/libraries/matrix/impl/room/member/RoomMemberListFetcherTest.kt new file mode 100644 index 0000000000..1c153435db --- /dev/null +++ b/libraries/matrix/impl/src/test/kotlin/io/element/android/libraries/matrix/impl/room/member/RoomMemberListFetcherTest.kt @@ -0,0 +1,303 @@ +/* + * 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 io.element.android.libraries.matrix.impl.room.member + +import app.cash.turbine.test +import com.google.common.truth.Truth.assertThat +import io.element.android.libraries.matrix.api.core.UserId +import io.element.android.libraries.matrix.api.room.MatrixRoomMembersState +import io.element.android.libraries.matrix.api.room.roomMembers +import io.element.android.libraries.matrix.test.A_ROOM_ID +import io.element.android.libraries.matrix.test.A_USER_ID +import io.element.android.libraries.matrix.test.A_USER_ID_2 +import io.element.android.libraries.matrix.test.A_USER_ID_3 +import io.element.android.libraries.matrix.test.A_USER_ID_4 +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.test.runTest +import org.junit.Test +import org.matrix.rustcomponents.sdk.MembershipState +import org.matrix.rustcomponents.sdk.NoPointer +import org.matrix.rustcomponents.sdk.Room +import org.matrix.rustcomponents.sdk.RoomMember +import org.matrix.rustcomponents.sdk.RoomMembersIterator + +class RoomMemberListFetcherTest { + @Test + fun `fetchCachedRoomMembers - emits cached members, if any`() = runTest { + val room = FakeRustRoom(getMembersNoSync = { + FakeRoomMembersIterator( + listOf( + FakeRustRoomMember(A_USER_ID), + FakeRustRoomMember(A_USER_ID_2), + FakeRustRoomMember(A_USER_ID_3), + ) + ) + }) + + val fetcher = RoomMemberListFetcher(room, Dispatchers.Default) + fetcher.membersFlow.test { + assertThat(awaitItem()).isInstanceOf(MatrixRoomMembersState.Unknown::class.java) + + fetcher.fetchCachedRoomMembers() + + val readyItem = awaitItem() + assertThat(readyItem).isInstanceOf(MatrixRoomMembersState.Ready::class.java) + assertThat((readyItem as? MatrixRoomMembersState.Ready)?.roomMembers?.size).isEqualTo(3) + } + } + + @Test + fun `fetchCachedRoomMembers - emits empty list, if no members exist`() = runTest { + val room = FakeRustRoom(getMembersNoSync = { + FakeRoomMembersIterator(emptyList()) + }) + + val fetcher = RoomMemberListFetcher(room, Dispatchers.Default) + fetcher.membersFlow.test { + fetcher.fetchCachedRoomMembers() + assertThat(awaitItem()).isInstanceOf(MatrixRoomMembersState.Unknown::class.java) + assertThat(awaitItem().roomMembers()).isEmpty() + } + } + + @Test + fun `fetchCachedRoomMembers - emits Error on error found`() = runTest { + val room = FakeRustRoom(getMembersNoSync = { + error("Some unexpected issue") + }) + + val fetcher = RoomMemberListFetcher(room, Dispatchers.Default) + fetcher.membersFlow.test { + fetcher.fetchCachedRoomMembers() + assertThat(awaitItem()).isInstanceOf(MatrixRoomMembersState.Unknown::class.java) + assertThat(awaitItem()).isInstanceOf(MatrixRoomMembersState.Error::class.java) + } + } + + @Test + fun `fetchCachedRoomMembers - emits items using page size`() = runTest { + val room = FakeRustRoom(getMembersNoSync = { + FakeRoomMembersIterator( + listOf( + FakeRustRoomMember(A_USER_ID), + FakeRustRoomMember(A_USER_ID_2), + FakeRustRoomMember(A_USER_ID_3), + ) + ) + }) + + val fetcher = RoomMemberListFetcher(room, Dispatchers.Default, pageSize = 2) + fetcher.membersFlow.test { + fetcher.fetchCachedRoomMembers() + + assertThat(awaitItem()).isInstanceOf(MatrixRoomMembersState.Unknown::class.java) + assertThat((awaitItem() as? MatrixRoomMembersState.Ready)?.roomMembers?.size).isEqualTo(2) + assertThat((awaitItem() as? MatrixRoomMembersState.Ready)?.roomMembers?.size).isEqualTo(3) + + ensureAllEventsConsumed() + } + } + + @Test + fun `fetchRoomMembers - with 'withCache' set to false emits only new members, if any`() = runTest { + val room = FakeRustRoom(getMembers = { + FakeRoomMembersIterator( + listOf( + FakeRustRoomMember(A_USER_ID), + FakeRustRoomMember(A_USER_ID_2), + FakeRustRoomMember(A_USER_ID_3), + ) + ) + }) + + val fetcher = RoomMemberListFetcher(room, Dispatchers.Default) + fetcher.membersFlow.test { + fetcher.fetchRoomMembers(withCache = false) + + assertThat(awaitItem()).isInstanceOf(MatrixRoomMembersState.Unknown::class.java) + assertThat(awaitItem()).isInstanceOf(MatrixRoomMembersState.Pending::class.java) + assertThat((awaitItem() as? MatrixRoomMembersState.Ready)?.roomMembers?.size).isEqualTo(3) + } + } + + @Test + fun `fetchRoomMembers - on error it emits an Error item`() = runTest { + val room = FakeRustRoom(getMembers = { error("An unexpected error") }) + + val fetcher = RoomMemberListFetcher(room, Dispatchers.Default) + fetcher.membersFlow.test { + fetcher.fetchRoomMembers(withCache = false) + + assertThat(awaitItem()).isInstanceOf(MatrixRoomMembersState.Unknown::class.java) + assertThat(awaitItem()).isInstanceOf(MatrixRoomMembersState.Pending::class.java) + assertThat(awaitItem()).isInstanceOf(MatrixRoomMembersState.Error::class.java) + } + } + + @Test + fun `fetchRoomMembers - with 'withCache' returns cached items first, then new ones`() = runTest { + val room = FakeRustRoom( + getMembersNoSync = { + FakeRoomMembersIterator(listOf(FakeRustRoomMember(A_USER_ID_4))) + }, + getMembers = { + FakeRoomMembersIterator( + listOf( + FakeRustRoomMember(A_USER_ID), + FakeRustRoomMember(A_USER_ID_2), + FakeRustRoomMember(A_USER_ID_3), + ) + ) + } + ) + + val fetcher = RoomMemberListFetcher(room, Dispatchers.Default) + fetcher.membersFlow.test { + fetcher.fetchRoomMembers(withCache = true) + // Initial + assertThat(awaitItem()).isInstanceOf(MatrixRoomMembersState.Unknown::class.java) + // Loaded cached + awaitItem().let { cached -> + assertThat(cached).isInstanceOf(MatrixRoomMembersState.Ready::class.java) + assertThat(cached.roomMembers()).hasSize(1) + } + // Start loading new + assertThat(awaitItem()).isInstanceOf(MatrixRoomMembersState.Pending::class.java) + awaitItem().let { ready -> + assertThat(ready).isInstanceOf(MatrixRoomMembersState.Ready::class.java) + assertThat(ready.roomMembers()).hasSize(3) + } + } + } + + @Test + fun `fetchRoomMembers - with 'withCache' skips cache if there is already a ready state`() = runTest { + val room = FakeRustRoom( + getMembersNoSync = { + FakeRoomMembersIterator(listOf(FakeRustRoomMember(A_USER_ID_4))) + }, + getMembers = { + FakeRoomMembersIterator( + listOf( + FakeRustRoomMember(A_USER_ID), + FakeRustRoomMember(A_USER_ID_2), + FakeRustRoomMember(A_USER_ID_3), + ) + ) + } + ) + + val fetcher = RoomMemberListFetcher(room, Dispatchers.Default) + // Set a ready state + fetcher.fetchRoomMembers(withCache = false) + + fetcher.membersFlow.test { + // Start loading new members + fetcher.fetchRoomMembers(withCache = true) + // Previous ready state + assertThat(awaitItem()).isInstanceOf(MatrixRoomMembersState.Ready::class.java) + // New pending state + assertThat(awaitItem()).isInstanceOf(MatrixRoomMembersState.Pending::class.java) + // New ready state + awaitItem().let { ready -> + assertThat(ready).isInstanceOf(MatrixRoomMembersState.Ready::class.java) + assertThat(ready.roomMembers()).hasSize(3) + } + } + } +} + +class FakeRustRoom( + private val getMembers: () -> RoomMembersIterator = { FakeRoomMembersIterator() }, + private val getMembersNoSync: () -> RoomMembersIterator = { FakeRoomMembersIterator() }, +) : Room(NoPointer) { + override fun id(): String { + return A_ROOM_ID.value + } + + override suspend fun members(): RoomMembersIterator { + return getMembers() + } + + override suspend fun membersNoSync(): RoomMembersIterator { + return getMembersNoSync() + } + + override fun close() { + // No-op + } +} + +class FakeRoomMembersIterator( + private var members: List? = null +) : RoomMembersIterator(NoPointer) { + override fun len(): UInt { + return members?.size?.toUInt() ?: 0u + } + + override fun nextChunk(chunkSize: UInt): List? { + if (members?.isEmpty() == true) { + return null + } + return members?.let { + val result = it.take(chunkSize.toInt()) + members = it.subList(result.size, it.size) + result + } + } +} + +class FakeRustRoomMember( + private val userId: UserId, + private val displayName: String? = null, + private val avatarUrl: String? = null, + private val membership: MembershipState = MembershipState.JOIN, + private val isNameAmbiguous: Boolean = false, + private val powerLevel: Long = 0L, +) : RoomMember(NoPointer) { + override fun userId(): String { + return userId.value + } + + override fun displayName(): String? { + return displayName + } + + override fun avatarUrl(): String? { + return avatarUrl + } + + override fun membership(): MembershipState { + return membership + } + + override fun isNameAmbiguous(): Boolean { + return isNameAmbiguous + } + + override fun powerLevel(): Long { + return powerLevel + } + + override fun normalizedPowerLevel(): Long { + return powerLevel + } + + override fun isIgnored(): Boolean { + return false + } +} diff --git a/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/room/FakeMatrixRoom.kt b/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/room/FakeMatrixRoom.kt index fbddf28bbe..19b5132016 100644 --- a/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/room/FakeMatrixRoom.kt +++ b/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/room/FakeMatrixRoom.kt @@ -171,9 +171,7 @@ class FakeMatrixRoom( override val roomNotificationSettingsStateFlow: MutableStateFlow = MutableStateFlow(MatrixRoomNotificationSettingsState.Unknown) - override suspend fun updateMembers(): Result = simulateLongTask { - updateMembersResult - } + override suspend fun updateMembers() = Unit override suspend fun updateRoomNotificationSettings(): Result = simulateLongTask { val notificationSettings = notificationSettingsService.getRoomNotificationSettings(roomId, isEncrypted, isOneToOne).getOrThrow() diff --git a/tests/testutils/src/main/kotlin/io/element/android/tests/testutils/WithFakeLifecycleOwner.kt b/tests/testutils/src/main/kotlin/io/element/android/tests/testutils/WithFakeLifecycleOwner.kt new file mode 100644 index 0000000000..e49dc0317b --- /dev/null +++ b/tests/testutils/src/main/kotlin/io/element/android/tests/testutils/WithFakeLifecycleOwner.kt @@ -0,0 +1,49 @@ +/* + * 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 io.element.android.tests.testutils + +import android.annotation.SuppressLint +import androidx.compose.runtime.Composable +import androidx.compose.runtime.CompositionLocalProvider +import androidx.compose.runtime.Stable +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.runtime.setValue +import androidx.compose.ui.platform.LocalLifecycleOwner +import androidx.lifecycle.Lifecycle +import androidx.lifecycle.LifecycleOwner +import androidx.lifecycle.LifecycleRegistry + +@Stable +@Composable +fun withFakeLifecycleOwner(lifecycleOwner: FakeLifecycleOwner = FakeLifecycleOwner(), block: @Composable () -> T): T { + var state: T? by remember { mutableStateOf(null) } + CompositionLocalProvider(LocalLifecycleOwner provides lifecycleOwner) { + state = block() + } + return state!! +} + +@SuppressLint("VisibleForTests") +class FakeLifecycleOwner : LifecycleOwner { + override val lifecycle: Lifecycle = LifecycleRegistry.createUnsafe(this) + + fun givenState(state: Lifecycle.State) { + (lifecycle as LifecycleRegistry).currentState = state + } +} From 15e3ecc88edef7ca516959e6b2e96117d40b525a Mon Sep 17 00:00:00 2001 From: Jorge Martin Espinosa Date: Wed, 24 Jan 2024 08:07:15 +0100 Subject: [PATCH 077/127] Update timeline items read receipts when the room members are loaded (#2194) * Update timeline items' sender info and read receipts when the room members info is loaded * Only update this info if we have loaded the room members --- changelog.d/2176.bugfix | 1 + .../impl/timeline/TimelinePresenter.kt | 10 ++-- .../factories/TimelineItemsFactory.kt | 11 +++- .../event/TimelineItemEventFactory.kt | 46 ++++++++++------ .../impl/timeline/TimelinePresenterTest.kt | 52 ++++++++++++++++++- 5 files changed, 97 insertions(+), 23 deletions(-) create mode 100644 changelog.d/2176.bugfix diff --git a/changelog.d/2176.bugfix b/changelog.d/2176.bugfix new file mode 100644 index 0000000000..7588dfdd3a --- /dev/null +++ b/changelog.d/2176.bugfix @@ -0,0 +1 @@ +Update timeline items' read receipts when the room members info is loaded. diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/TimelinePresenter.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/TimelinePresenter.kt index 85b555fa7c..f1f934c4ba 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/TimelinePresenter.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/TimelinePresenter.kt @@ -53,6 +53,7 @@ import io.element.android.libraries.matrix.api.verification.SessionVerifiedStatu import io.element.android.libraries.matrix.ui.room.canSendMessageAsState import kotlinx.collections.immutable.ImmutableList import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.launchIn import kotlinx.coroutines.flow.onEach import kotlinx.coroutines.launch @@ -111,8 +112,6 @@ class TimelinePresenter @AssistedInject constructor( } } - val membersState by room.membersStateFlow.collectAsState() - fun handleEvents(event: TimelineEvents) { when (event) { TimelineEvents.LoadMore -> localScope.paginateBackwards() @@ -149,13 +148,12 @@ class TimelinePresenter @AssistedInject constructor( } LaunchedEffect(Unit) { - timeline - .timelineItems - .onEach { + combine(timeline.timelineItems, room.membersStateFlow) { items, membersState -> timelineItemsFactory.replaceWith( - timelineItems = it, + timelineItems = items, roomMembers = membersState.roomMembers().orEmpty() ) + items } .onEach { timelineItems -> if (timelineItems.isEmpty()) { diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/factories/TimelineItemsFactory.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/factories/TimelineItemsFactory.kt index ffc1a1b3f1..29ea3abcfc 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/factories/TimelineItemsFactory.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/factories/TimelineItemsFactory.kt @@ -87,7 +87,16 @@ class TimelineItemsFactory @Inject constructor( newTimelineItemStates.add(timelineItemState) } } else { - newTimelineItemStates.add(cacheItem) + val updatedItem = if (cacheItem is TimelineItem.Event && roomMembers.isNotEmpty()) { + eventItemFactory.update( + timelineItem = cacheItem, + receivedMatrixTimelineItem = timelineItems[index] as MatrixTimelineItem.Event, + roomMembers = roomMembers + ) + } else { + cacheItem + } + newTimelineItemStates.add(updatedItem) } } val result = timelineItemGrouper.group(newTimelineItemStates).toPersistentList() diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/factories/event/TimelineItemEventFactory.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/factories/event/TimelineItemEventFactory.kt index 29ea9df6c2..38125dcef7 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/factories/event/TimelineItemEventFactory.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/factories/event/TimelineItemEventFactory.kt @@ -53,21 +53,7 @@ class TimelineItemEventFactory @Inject constructor( val currentSender = currentTimelineItem.event.sender val groupPosition = computeGroupPosition(currentTimelineItem, timelineItems, index) - val senderDisplayName: String? - val senderAvatarUrl: String? - - when (val senderProfile = currentTimelineItem.event.senderProfile) { - ProfileTimelineDetails.Unavailable, - ProfileTimelineDetails.Pending, - is ProfileTimelineDetails.Error -> { - senderDisplayName = null - senderAvatarUrl = null - } - is ProfileTimelineDetails.Ready -> { - senderDisplayName = senderProfile.getDisambiguatedDisplayName(currentSender) - senderAvatarUrl = senderProfile.avatarUrl - } - } + val (senderDisplayName, senderAvatarUrl) = currentTimelineItem.getSenderInfo() val timeFormatter = DateFormat.getTimeInstance(DateFormat.SHORT) val sentTime = timeFormatter.format(Date(currentTimelineItem.event.timestamp)) @@ -101,6 +87,36 @@ class TimelineItemEventFactory @Inject constructor( ) } + fun update( + timelineItem: TimelineItem.Event, + receivedMatrixTimelineItem: MatrixTimelineItem.Event, + roomMembers: List, + ): TimelineItem.Event { + return timelineItem.copy( + readReceiptState = receivedMatrixTimelineItem.computeReadReceiptState(roomMembers) + ) + } + + private fun MatrixTimelineItem.Event.getSenderInfo(): Pair { + val senderDisplayName: String? + val senderAvatarUrl: String? + + when (val senderProfile = event.senderProfile) { + ProfileTimelineDetails.Unavailable, + ProfileTimelineDetails.Pending, + is ProfileTimelineDetails.Error -> { + senderDisplayName = null + senderAvatarUrl = null + } + is ProfileTimelineDetails.Ready -> { + senderDisplayName = senderProfile.getDisambiguatedDisplayName(event.sender) + senderAvatarUrl = senderProfile.avatarUrl + } + } + + return senderDisplayName to senderAvatarUrl + } + private fun MatrixTimelineItem.Event.computeReactionsState(): TimelineItemReactions { val timeFormatter = DateFormat.getTimeInstance(DateFormat.SHORT) var aggregatedReactions = event.reactions.map { reaction -> diff --git a/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/timeline/TimelinePresenterTest.kt b/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/timeline/TimelinePresenterTest.kt index 5f68622c4d..be06965fa6 100644 --- a/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/timeline/TimelinePresenterTest.kt +++ b/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/timeline/TimelinePresenterTest.kt @@ -35,14 +35,18 @@ import io.element.android.features.poll.api.actions.SendPollResponseAction import io.element.android.features.poll.test.actions.FakeEndPollAction import io.element.android.features.poll.test.actions.FakeSendPollResponseAction import io.element.android.libraries.featureflag.api.FeatureFlags +import io.element.android.libraries.matrix.api.room.MatrixRoomMembersState import io.element.android.libraries.matrix.api.timeline.MatrixTimeline import io.element.android.libraries.matrix.api.timeline.MatrixTimelineItem import io.element.android.libraries.matrix.api.timeline.item.event.EventReaction import io.element.android.libraries.matrix.api.timeline.item.event.ReactionSender +import io.element.android.libraries.matrix.api.timeline.item.event.Receipt import io.element.android.libraries.matrix.api.timeline.item.virtual.VirtualTimelineItem import io.element.android.libraries.matrix.test.AN_EVENT_ID +import io.element.android.libraries.matrix.test.A_USER_ID import io.element.android.libraries.matrix.test.encryption.FakeEncryptionService import io.element.android.libraries.matrix.test.room.FakeMatrixRoom +import io.element.android.libraries.matrix.test.room.aRoomMember import io.element.android.libraries.matrix.test.timeline.FakeMatrixTimeline import io.element.android.libraries.matrix.test.timeline.aMessageContent import io.element.android.libraries.matrix.test.timeline.anEventTimelineItem @@ -60,6 +64,7 @@ import kotlinx.coroutines.test.runTest import org.junit.Rule import org.junit.Test import java.util.Date +import kotlin.time.Duration.Companion.seconds private const val FAKE_UNIQUE_ID = "FAKE_UNIQUE_ID" @@ -353,6 +358,50 @@ class TimelinePresenterTest { } } + @Test + fun `present - when room member info is loaded, read receipts info should be updated`() = runTest { + val timeline = FakeMatrixTimeline( + listOf( + MatrixTimelineItem.Event( + FAKE_UNIQUE_ID, + anEventTimelineItem( + sender = A_USER_ID, + receipts = persistentListOf( + Receipt( + userId = A_USER_ID, + timestamp = 0L, + ) + ) + ) + ) + ) + ) + val room = FakeMatrixRoom(matrixTimeline = timeline).apply { + givenRoomMembersState(MatrixRoomMembersState.Unknown) + } + + val avatarUrl = "https://domain.com/avatar.jpg" + + val presenter = createTimelinePresenter(timeline, room) + moleculeFlow(RecompositionMode.Immediate) { + presenter.present() + }.test { + val initialState = consumeItemsUntilPredicate(30.seconds) { it.timelineItems.isNotEmpty() }.last() + val event = initialState.timelineItems.first() as TimelineItem.Event + assertThat(event.senderAvatar.url).isNull() + assertThat(event.readReceiptState.receipts.first().avatarData.url).isNull() + + room.givenRoomMembersState( + MatrixRoomMembersState.Ready( + persistentListOf(aRoomMember(userId = A_USER_ID, avatarUrl = avatarUrl)) + ) + ) + + val updatedEvent = awaitItem().timelineItems.first() as TimelineItem.Event + assertThat(updatedEvent.readReceiptState.receipts.first().avatarData.url).isEqualTo(avatarUrl) + } + } + private suspend fun ReceiveTurbine.awaitFirstItem(): T { // Skip 1 item if Mentions feature is enabled if (FeatureFlags.Mentions.defaultValue) { @@ -363,6 +412,7 @@ class TimelinePresenterTest { private fun TestScope.createTimelinePresenter( timeline: MatrixTimeline = FakeMatrixTimeline(), + room: FakeMatrixRoom = FakeMatrixRoom(matrixTimeline = timeline), timelineItemsFactory: TimelineItemsFactory = aTimelineItemsFactory(), redactedVoiceMessageManager: RedactedVoiceMessageManager = FakeRedactedVoiceMessageManager(), messagesNavigator: FakeMessagesNavigator = FakeMessagesNavigator(), @@ -371,7 +421,7 @@ class TimelinePresenterTest { ): TimelinePresenter { return TimelinePresenter( timelineItemsFactory = timelineItemsFactory, - room = FakeMatrixRoom(matrixTimeline = timeline), + room = room, dispatchers = testCoroutineDispatchers(), appScope = this, navigator = messagesNavigator, From 6a0e038cb5164d9d3d19a975de0a4ce7b2f8d15f Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 24 Jan 2024 09:29:56 +0100 Subject: [PATCH 078/127] Update android.gradle.plugin to v8.2.2 (#2280) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 71d8e10d0b..8db607ed44 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -3,7 +3,7 @@ [versions] # Project -android_gradle_plugin = "8.2.1" +android_gradle_plugin = "8.2.2" kotlin = "1.9.22" ksp = "1.9.22-1.0.17" firebaseAppDistribution = "4.0.1" From acf63be0406c760b344e7e12d175f5374ecb869b Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 24 Jan 2024 19:00:09 +0000 Subject: [PATCH 079/127] Update dependency com.posthog:posthog-android to v3.1.5 --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 8db607ed44..69bd6fd2f6 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -173,7 +173,7 @@ opusencoder = "io.element.android:opusencoder:1.1.0" kotlinpoet = "com.squareup:kotlinpoet:1.16.0" # Analytics -posthog = "com.posthog:posthog-android:3.1.4" +posthog = "com.posthog:posthog-android:3.1.5" sentry = "io.sentry:sentry-android:7.2.0" matrix_analytics_events = "com.github.matrix-org:matrix-analytics-events:aa14cbcdf81af2746d20a71779ec751f971e1d7f" From 983d2f41be7c9325763c86787c967b808bed0b80 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 24 Jan 2024 21:29:33 +0000 Subject: [PATCH 080/127] Update dependency androidx.compose:compose-bom to v2024 --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 8db607ed44..525f4b8631 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -18,7 +18,7 @@ activity = "1.8.2" media3 = "1.2.1" # Compose -compose_bom = "2023.10.01" +compose_bom = "2024.01.00" composecompiler = "1.5.8" # Coroutines From 5fa396d616c7e2bb5ca251163b38a98e1064ab30 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Wed, 24 Jan 2024 23:11:52 +0100 Subject: [PATCH 081/127] View Folders and files Add test Add test --- appnav/build.gradle.kts | 1 + .../io/element/android/appnav/RootFlowNode.kt | 26 +++ .../api/bugreport/BugReportEntryPoint.kt | 1 + .../rageshake/api/reporter/BugReporter.kt | 5 + .../rageshake/impl/bugreport/BugReportNode.kt | 11 + .../rageshake/impl/bugreport/BugReportView.kt | 8 + .../impl/reporter/DefaultBugReporter.kt | 23 +- .../impl/src/main/res/values/localazy.xml | 1 + features/viewfolder/api/build.gradle.kts | 26 +++ .../viewfolder/api/ViewFolderEntryPoint.kt | 40 ++++ features/viewfolder/impl/build.gradle.kts | 50 +++++ .../impl/DefaultViewFolderEntryPoint.kt | 50 +++++ .../viewfolder/impl/file/FileContentReader.kt | 44 ++++ .../features/viewfolder/impl/file/FileSave.kt | 100 +++++++++ .../viewfolder/impl/file/FileShare.kt | 72 ++++++ .../viewfolder/impl/file/ViewFileEvents.kt | 22 ++ .../viewfolder/impl/file/ViewFileNode.kt | 67 ++++++ .../viewfolder/impl/file/ViewFilePresenter.kt | 78 +++++++ .../viewfolder/impl/file/ViewFileState.kt | 25 +++ .../impl/file/ViewFileStateProvider.kt | 50 +++++ .../viewfolder/impl/file/ViewFileView.kt | 206 ++++++++++++++++++ .../viewfolder/impl/folder/FolderExplorer.kt | 61 ++++++ .../viewfolder/impl/folder/ViewFolderNode.kt | 74 +++++++ .../impl/folder/ViewFolderPresenter.kt | 56 +++++ .../viewfolder/impl/folder/ViewFolderState.kt | 25 +++ .../impl/folder/ViewFolderStateProvider.kt | 43 ++++ .../viewfolder/impl/folder/ViewFolderView.kt | 165 ++++++++++++++ .../features/viewfolder/impl/model/Item.kt | 35 +++ .../impl/root/ViewFolderRootNode.kt | 148 +++++++++++++ .../test/file/FakeFileContentReader.kt | 29 +++ .../viewfolder/test/file/FakeFileSave.kt | 28 +++ .../viewfolder/test/file/FakeFileShare.kt | 28 +++ .../test/file/ViewFilePresenterTest.kt | 105 +++++++++ .../test/folder/FakeFolderExplorer.kt | 30 +++ .../test/folder/ViewFolderPresenterTest.kt | 99 +++++++++ 35 files changed, 1817 insertions(+), 15 deletions(-) create mode 100644 features/viewfolder/api/build.gradle.kts create mode 100644 features/viewfolder/api/src/main/kotlin/io/element/android/features/viewfolder/api/ViewFolderEntryPoint.kt create mode 100644 features/viewfolder/impl/build.gradle.kts create mode 100644 features/viewfolder/impl/src/main/kotlin/io/element/android/features/viewfolder/impl/DefaultViewFolderEntryPoint.kt create mode 100644 features/viewfolder/impl/src/main/kotlin/io/element/android/features/viewfolder/impl/file/FileContentReader.kt create mode 100644 features/viewfolder/impl/src/main/kotlin/io/element/android/features/viewfolder/impl/file/FileSave.kt create mode 100644 features/viewfolder/impl/src/main/kotlin/io/element/android/features/viewfolder/impl/file/FileShare.kt create mode 100644 features/viewfolder/impl/src/main/kotlin/io/element/android/features/viewfolder/impl/file/ViewFileEvents.kt create mode 100644 features/viewfolder/impl/src/main/kotlin/io/element/android/features/viewfolder/impl/file/ViewFileNode.kt create mode 100644 features/viewfolder/impl/src/main/kotlin/io/element/android/features/viewfolder/impl/file/ViewFilePresenter.kt create mode 100644 features/viewfolder/impl/src/main/kotlin/io/element/android/features/viewfolder/impl/file/ViewFileState.kt create mode 100644 features/viewfolder/impl/src/main/kotlin/io/element/android/features/viewfolder/impl/file/ViewFileStateProvider.kt create mode 100644 features/viewfolder/impl/src/main/kotlin/io/element/android/features/viewfolder/impl/file/ViewFileView.kt create mode 100644 features/viewfolder/impl/src/main/kotlin/io/element/android/features/viewfolder/impl/folder/FolderExplorer.kt create mode 100644 features/viewfolder/impl/src/main/kotlin/io/element/android/features/viewfolder/impl/folder/ViewFolderNode.kt create mode 100644 features/viewfolder/impl/src/main/kotlin/io/element/android/features/viewfolder/impl/folder/ViewFolderPresenter.kt create mode 100644 features/viewfolder/impl/src/main/kotlin/io/element/android/features/viewfolder/impl/folder/ViewFolderState.kt create mode 100644 features/viewfolder/impl/src/main/kotlin/io/element/android/features/viewfolder/impl/folder/ViewFolderStateProvider.kt create mode 100644 features/viewfolder/impl/src/main/kotlin/io/element/android/features/viewfolder/impl/folder/ViewFolderView.kt create mode 100644 features/viewfolder/impl/src/main/kotlin/io/element/android/features/viewfolder/impl/model/Item.kt create mode 100644 features/viewfolder/impl/src/main/kotlin/io/element/android/features/viewfolder/impl/root/ViewFolderRootNode.kt create mode 100644 features/viewfolder/impl/src/test/kotlin/io/element/android/features/viewfolder/test/file/FakeFileContentReader.kt create mode 100644 features/viewfolder/impl/src/test/kotlin/io/element/android/features/viewfolder/test/file/FakeFileSave.kt create mode 100644 features/viewfolder/impl/src/test/kotlin/io/element/android/features/viewfolder/test/file/FakeFileShare.kt create mode 100644 features/viewfolder/impl/src/test/kotlin/io/element/android/features/viewfolder/test/file/ViewFilePresenterTest.kt create mode 100644 features/viewfolder/impl/src/test/kotlin/io/element/android/features/viewfolder/test/folder/FakeFolderExplorer.kt create mode 100644 features/viewfolder/impl/src/test/kotlin/io/element/android/features/viewfolder/test/folder/ViewFolderPresenterTest.kt diff --git a/appnav/build.gradle.kts b/appnav/build.gradle.kts index 9407b16592..4e436ec718 100644 --- a/appnav/build.gradle.kts +++ b/appnav/build.gradle.kts @@ -52,6 +52,7 @@ dependencies { implementation(libs.coil) implementation(projects.features.ftue.api) + implementation(projects.features.viewfolder.api) implementation(projects.services.apperror.impl) implementation(projects.services.appnavstate.api) diff --git a/appnav/src/main/kotlin/io/element/android/appnav/RootFlowNode.kt b/appnav/src/main/kotlin/io/element/android/appnav/RootFlowNode.kt index fa7820b5d5..e4ecdd8864 100644 --- a/appnav/src/main/kotlin/io/element/android/appnav/RootFlowNode.kt +++ b/appnav/src/main/kotlin/io/element/android/appnav/RootFlowNode.kt @@ -45,6 +45,7 @@ import io.element.android.features.login.api.oidc.OidcAction import io.element.android.features.login.api.oidc.OidcActionFlow import io.element.android.features.rageshake.api.bugreport.BugReportEntryPoint import io.element.android.features.signedout.api.SignedOutEntryPoint +import io.element.android.features.viewfolder.api.ViewFolderEntryPoint import io.element.android.libraries.architecture.BackstackView import io.element.android.libraries.architecture.BaseFlowNode import io.element.android.libraries.architecture.createNode @@ -70,6 +71,7 @@ class RootFlowNode @AssistedInject constructor( private val matrixClientsHolder: MatrixClientsHolder, private val presenter: RootPresenter, private val bugReportEntryPoint: BugReportEntryPoint, + private val viewFolderEntryPoint: ViewFolderEntryPoint, private val signedOutEntryPoint: SignedOutEntryPoint, private val intentResolver: IntentResolver, private val oidcActionFlow: OidcActionFlow, @@ -194,6 +196,11 @@ class RootFlowNode @AssistedInject constructor( @Parcelize data object BugReport : NavTarget + + @Parcelize + data class ViewLogs( + val rootPath: String, + ) : NavTarget } override fun resolve(navTarget: NavTarget, buildContext: BuildContext): Node { @@ -233,12 +240,31 @@ class RootFlowNode @AssistedInject constructor( override fun onBugReportSent() { backstack.pop() } + + override fun onViewLogs(basePath: String) { + backstack.push(NavTarget.ViewLogs(rootPath = basePath)) + } } bugReportEntryPoint .nodeBuilder(this, buildContext) .callback(callback) .build() } + is NavTarget.ViewLogs -> { + val callback = object : ViewFolderEntryPoint.Callback { + override fun onDone() { + backstack.pop() + } + } + val params = ViewFolderEntryPoint.Params( + rootPath = navTarget.rootPath, + ) + viewFolderEntryPoint + .nodeBuilder(this, buildContext) + .params(params) + .callback(callback) + .build() + } } } diff --git a/features/rageshake/api/src/main/kotlin/io/element/android/features/rageshake/api/bugreport/BugReportEntryPoint.kt b/features/rageshake/api/src/main/kotlin/io/element/android/features/rageshake/api/bugreport/BugReportEntryPoint.kt index cebc94f31d..758c153671 100644 --- a/features/rageshake/api/src/main/kotlin/io/element/android/features/rageshake/api/bugreport/BugReportEntryPoint.kt +++ b/features/rageshake/api/src/main/kotlin/io/element/android/features/rageshake/api/bugreport/BugReportEntryPoint.kt @@ -31,5 +31,6 @@ interface BugReportEntryPoint : FeatureEntryPoint { interface Callback : Plugin { fun onBugReportSent() + fun onViewLogs(basePath: String) } } diff --git a/features/rageshake/api/src/main/kotlin/io/element/android/features/rageshake/api/reporter/BugReporter.kt b/features/rageshake/api/src/main/kotlin/io/element/android/features/rageshake/api/reporter/BugReporter.kt index d50ce28778..d8e05f947b 100644 --- a/features/rageshake/api/src/main/kotlin/io/element/android/features/rageshake/api/reporter/BugReporter.kt +++ b/features/rageshake/api/src/main/kotlin/io/element/android/features/rageshake/api/reporter/BugReporter.kt @@ -52,4 +52,9 @@ interface BugReporter { * Set the current tracing filter. */ fun setCurrentTracingFilter(tracingFilter: String) + + /** + * Save the logcat. + */ + fun saveLogCat() } diff --git a/features/rageshake/impl/src/main/kotlin/io/element/android/features/rageshake/impl/bugreport/BugReportNode.kt b/features/rageshake/impl/src/main/kotlin/io/element/android/features/rageshake/impl/bugreport/BugReportNode.kt index 90a81e279d..caed077228 100644 --- a/features/rageshake/impl/src/main/kotlin/io/element/android/features/rageshake/impl/bugreport/BugReportNode.kt +++ b/features/rageshake/impl/src/main/kotlin/io/element/android/features/rageshake/impl/bugreport/BugReportNode.kt @@ -28,6 +28,7 @@ import dagger.assisted.Assisted import dagger.assisted.AssistedInject import io.element.android.anvilannotations.ContributesNode import io.element.android.features.rageshake.api.bugreport.BugReportEntryPoint +import io.element.android.features.rageshake.api.reporter.BugReporter import io.element.android.libraries.androidutils.system.toast import io.element.android.libraries.di.AppScope import io.element.android.libraries.ui.strings.CommonStrings @@ -37,7 +38,12 @@ class BugReportNode @AssistedInject constructor( @Assisted buildContext: BuildContext, @Assisted plugins: List, private val presenter: BugReportPresenter, + private val bugReporter: BugReporter, ) : Node(buildContext, plugins = plugins) { + private fun onViewLogs(basePath: String) { + plugins().forEach { it.onViewLogs(basePath) } + } + @Composable override fun View(modifier: Modifier) { val state = presenter.present() @@ -50,6 +56,11 @@ class BugReportNode @AssistedInject constructor( activity?.toast(CommonStrings.common_report_submitted) onDone() }, + onViewLogs = { + // Force a logcat dump + bugReporter.saveLogCat() + onViewLogs(bugReporter.logDirectory().absolutePath) + } ) } diff --git a/features/rageshake/impl/src/main/kotlin/io/element/android/features/rageshake/impl/bugreport/BugReportView.kt b/features/rageshake/impl/src/main/kotlin/io/element/android/features/rageshake/impl/bugreport/BugReportView.kt index 11843553e8..80f7d931e0 100644 --- a/features/rageshake/impl/src/main/kotlin/io/element/android/features/rageshake/impl/bugreport/BugReportView.kt +++ b/features/rageshake/impl/src/main/kotlin/io/element/android/features/rageshake/impl/bugreport/BugReportView.kt @@ -43,6 +43,7 @@ import io.element.android.libraries.designsystem.components.form.textFieldState import io.element.android.libraries.designsystem.components.preferences.PreferencePage import io.element.android.libraries.designsystem.components.preferences.PreferenceRow import io.element.android.libraries.designsystem.components.preferences.PreferenceSwitch +import io.element.android.libraries.designsystem.components.preferences.PreferenceText import io.element.android.libraries.designsystem.preview.ElementPreview import io.element.android.libraries.designsystem.preview.PreviewsDayNight import io.element.android.libraries.designsystem.preview.debugPlaceholderBackground @@ -55,6 +56,7 @@ import io.element.android.libraries.ui.strings.CommonStrings @Composable fun BugReportView( state: BugReportState, + onViewLogs: () -> Unit, onDone: () -> Unit, onBackPressed: () -> Unit, modifier: Modifier = Modifier, @@ -97,6 +99,11 @@ fun BugReportView( ) } Spacer(modifier = Modifier.height(16.dp)) + PreferenceText( + title = stringResource(id = R.string.screen_bug_report_view_logs), + enabled = isFormEnabled, + onClick = onViewLogs, + ) PreferenceSwitch( isChecked = state.formState.sendLogs, onCheckedChange = { eventSink(BugReportEvents.SetSendLog(it)) }, @@ -169,5 +176,6 @@ internal fun BugReportViewPreview(@PreviewParameter(BugReportStateProvider::clas state = state, onDone = {}, onBackPressed = {}, + onViewLogs = {}, ) } diff --git a/features/rageshake/impl/src/main/kotlin/io/element/android/features/rageshake/impl/reporter/DefaultBugReporter.kt b/features/rageshake/impl/src/main/kotlin/io/element/android/features/rageshake/impl/reporter/DefaultBugReporter.kt index 2123717f8e..2295ab8808 100755 --- a/features/rageshake/impl/src/main/kotlin/io/element/android/features/rageshake/impl/reporter/DefaultBugReporter.kt +++ b/features/rageshake/impl/src/main/kotlin/io/element/android/features/rageshake/impl/reporter/DefaultBugReporter.kt @@ -94,6 +94,8 @@ class DefaultBugReporter @Inject constructor( private val logcatCommandDebug = arrayOf("logcat", "-d", "-v", "threadtime", "*:*") private var currentTracingFilter: String? = null + private val logCatErrFile = File(logDirectory().absolutePath, LOG_CAT_FILENAME) + override suspend fun sendBugReport( withDevicesLogs: Boolean, withCrashLogs: Boolean, @@ -130,8 +132,8 @@ class DefaultBugReporter @Inject constructor( } if (!isCancelled && (withCrashLogs || withDevicesLogs)) { - val gzippedLogcat = saveLogCat() - + saveLogCat() + val gzippedLogcat = compressFile(logCatErrFile) if (null != gzippedLogcat) { if (gzippedFiles.size == 0) { gzippedFiles.add(gzippedLogcat) @@ -321,7 +323,9 @@ class DefaultBugReporter @Inject constructor( } override fun logDirectory(): File { - return File(context.cacheDir, LOG_DIRECTORY_NAME) + return File(context.cacheDir, LOG_DIRECTORY_NAME).apply { + mkdirs() + } } override fun cleanLogDirectoryIfNeeded() { @@ -381,30 +385,19 @@ class DefaultBugReporter @Inject constructor( * * @return the file if the operation succeeds */ - private fun saveLogCat(): File? { - val logCatErrFile = File(context.cacheDir.absolutePath, LOG_CAT_FILENAME) - + override fun saveLogCat() { if (logCatErrFile.exists()) { logCatErrFile.safeDelete() } - try { logCatErrFile.writer().use { getLogCatError(it) } - - return compressFile(logCatErrFile) } catch (error: OutOfMemoryError) { Timber.e(error, "## saveLogCat() : fail to write logcat OOM") } catch (e: Exception) { Timber.e(e, "## saveLogCat() : fail to write logcat") - } finally { - if (logCatErrFile.exists()) { - logCatErrFile.safeDelete() - } } - - return null } /** diff --git a/features/rageshake/impl/src/main/res/values/localazy.xml b/features/rageshake/impl/src/main/res/values/localazy.xml index 34ba8b5b30..83413c3919 100644 --- a/features/rageshake/impl/src/main/res/values/localazy.xml +++ b/features/rageshake/impl/src/main/res/values/localazy.xml @@ -11,5 +11,6 @@ "Allow logs" "Send screenshot" "Logs will be included with your message to make sure that everything is working properly. To send your message without logs, turn off this setting." + "View logs" "%1$s crashed the last time it was used. Would you like to share a crash report with us?" diff --git a/features/viewfolder/api/build.gradle.kts b/features/viewfolder/api/build.gradle.kts new file mode 100644 index 0000000000..98a53dad87 --- /dev/null +++ b/features/viewfolder/api/build.gradle.kts @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2024 New Vector Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +plugins { + id("io.element.android-library") +} + +android { + namespace = "io.element.android.features.viewfolder.api" +} + +dependencies { + implementation(projects.libraries.architecture) +} diff --git a/features/viewfolder/api/src/main/kotlin/io/element/android/features/viewfolder/api/ViewFolderEntryPoint.kt b/features/viewfolder/api/src/main/kotlin/io/element/android/features/viewfolder/api/ViewFolderEntryPoint.kt new file mode 100644 index 0000000000..f3fb62374e --- /dev/null +++ b/features/viewfolder/api/src/main/kotlin/io/element/android/features/viewfolder/api/ViewFolderEntryPoint.kt @@ -0,0 +1,40 @@ +/* + * 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 io.element.android.features.viewfolder.api + +import com.bumble.appyx.core.modality.BuildContext +import com.bumble.appyx.core.node.Node +import com.bumble.appyx.core.plugin.Plugin +import io.element.android.libraries.architecture.FeatureEntryPoint + +interface ViewFolderEntryPoint : FeatureEntryPoint { + data class Params( + val rootPath: String, + ) + + fun nodeBuilder(parentNode: Node, buildContext: BuildContext): NodeBuilder + + interface NodeBuilder { + fun params(params: Params): NodeBuilder + fun callback(callback: Callback): NodeBuilder + fun build(): Node + } + + interface Callback : Plugin { + fun onDone() + } +} diff --git a/features/viewfolder/impl/build.gradle.kts b/features/viewfolder/impl/build.gradle.kts new file mode 100644 index 0000000000..d3e838e1f5 --- /dev/null +++ b/features/viewfolder/impl/build.gradle.kts @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2024 New Vector Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +plugins { + id("io.element.android-compose-library") + alias(libs.plugins.anvil) + alias(libs.plugins.ksp) + id("kotlin-parcelize") +} + +android { + namespace = "io.element.android.features.viewfolder.impl" +} + +anvil { + generateDaggerFactories.set(true) +} + +dependencies { + implementation(projects.anvilannotations) + anvil(projects.anvilcodegen) + implementation(projects.libraries.androidutils) + implementation(projects.libraries.architecture) + implementation(projects.libraries.core) + implementation(projects.libraries.designsystem) + implementation(projects.libraries.uiStrings) + api(projects.features.viewfolder.api) + ksp(libs.showkase.processor) + + testImplementation(libs.test.junit) + testImplementation(libs.test.robolectric) + testImplementation(libs.coroutines.test) + testImplementation(libs.molecule.runtime) + testImplementation(libs.test.truth) + testImplementation(libs.test.turbine) + testImplementation(projects.tests.testutils) +} diff --git a/features/viewfolder/impl/src/main/kotlin/io/element/android/features/viewfolder/impl/DefaultViewFolderEntryPoint.kt b/features/viewfolder/impl/src/main/kotlin/io/element/android/features/viewfolder/impl/DefaultViewFolderEntryPoint.kt new file mode 100644 index 0000000000..0383c03b8f --- /dev/null +++ b/features/viewfolder/impl/src/main/kotlin/io/element/android/features/viewfolder/impl/DefaultViewFolderEntryPoint.kt @@ -0,0 +1,50 @@ +/* + * 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 io.element.android.features.viewfolder.impl + +import com.bumble.appyx.core.modality.BuildContext +import com.bumble.appyx.core.node.Node +import com.bumble.appyx.core.plugin.Plugin +import com.squareup.anvil.annotations.ContributesBinding +import io.element.android.features.viewfolder.api.ViewFolderEntryPoint +import io.element.android.features.viewfolder.impl.root.ViewFolderRootNode +import io.element.android.libraries.architecture.createNode +import io.element.android.libraries.di.AppScope +import javax.inject.Inject + +@ContributesBinding(AppScope::class) +class DefaultViewFolderEntryPoint @Inject constructor() : ViewFolderEntryPoint { + override fun nodeBuilder(parentNode: Node, buildContext: BuildContext): ViewFolderEntryPoint.NodeBuilder { + val plugins = ArrayList() + + return object : ViewFolderEntryPoint.NodeBuilder { + override fun params(params: ViewFolderEntryPoint.Params): ViewFolderEntryPoint.NodeBuilder { + plugins += ViewFolderRootNode.Inputs(params.rootPath) + return this + } + + override fun callback(callback: ViewFolderEntryPoint.Callback): ViewFolderEntryPoint.NodeBuilder { + plugins += callback + return this + } + + override fun build(): Node { + return parentNode.createNode(buildContext, plugins) + } + } + } +} diff --git a/features/viewfolder/impl/src/main/kotlin/io/element/android/features/viewfolder/impl/file/FileContentReader.kt b/features/viewfolder/impl/src/main/kotlin/io/element/android/features/viewfolder/impl/file/FileContentReader.kt new file mode 100644 index 0000000000..877f841fcb --- /dev/null +++ b/features/viewfolder/impl/src/main/kotlin/io/element/android/features/viewfolder/impl/file/FileContentReader.kt @@ -0,0 +1,44 @@ +/* + * 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 io.element.android.features.viewfolder.impl.file + +import com.squareup.anvil.annotations.ContributesBinding +import io.element.android.libraries.core.coroutine.CoroutineDispatchers +import io.element.android.libraries.di.AppScope +import kotlinx.coroutines.withContext +import java.io.File +import javax.inject.Inject + +interface FileContentReader { + suspend fun getLines(path: String): List +} + +@ContributesBinding(AppScope::class) +class DefaultFileContentReader @Inject constructor( + private val dispatchers: CoroutineDispatchers, +) : FileContentReader { + override suspend fun getLines(path: String): List = withContext(dispatchers.io) { + try { + File(path).readLines() + } catch (exception: Exception) { + buildList { + add("Error reading file $path") + add(exception.toString()) + } + } + } +} diff --git a/features/viewfolder/impl/src/main/kotlin/io/element/android/features/viewfolder/impl/file/FileSave.kt b/features/viewfolder/impl/src/main/kotlin/io/element/android/features/viewfolder/impl/file/FileSave.kt new file mode 100644 index 0000000000..9c78bb21aa --- /dev/null +++ b/features/viewfolder/impl/src/main/kotlin/io/element/android/features/viewfolder/impl/file/FileSave.kt @@ -0,0 +1,100 @@ +/* + * 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 io.element.android.features.viewfolder.impl.file + +import android.content.ContentValues +import android.content.Context +import android.os.Build +import android.os.Environment +import android.provider.MediaStore +import androidx.annotation.RequiresApi +import com.squareup.anvil.annotations.ContributesBinding +import io.element.android.libraries.androidutils.system.toast +import io.element.android.libraries.core.coroutine.CoroutineDispatchers +import io.element.android.libraries.core.mimetype.MimeTypes +import io.element.android.libraries.di.AppScope +import io.element.android.libraries.di.ApplicationContext +import kotlinx.coroutines.withContext +import timber.log.Timber +import java.io.File +import java.io.FileOutputStream +import javax.inject.Inject + +interface FileSave { + suspend fun save( + path: String, + ) +} + +@ContributesBinding(AppScope::class) +class DefaultFileSave @Inject constructor( + @ApplicationContext private val context: Context, + private val dispatchers: CoroutineDispatchers, +) : FileSave { + override suspend fun save( + path: String, + ) { + withContext(dispatchers.io) { + runCatching { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { + saveOnDiskUsingMediaStore(path) + } else { + saveOnDiskUsingExternalStorageApi(path) + } + }.onSuccess { + Timber.v("Save on disk succeed") + withContext(dispatchers.main) { + context.toast("Save on disk succeed") + } + }.onFailure { + Timber.e(it, "Save on disk failed") + } + } + } + + @RequiresApi(Build.VERSION_CODES.Q) + private fun saveOnDiskUsingMediaStore(path: String) { + val file = File(path) + val contentValues = ContentValues().apply { + put(MediaStore.MediaColumns.DISPLAY_NAME, file.name) + put(MediaStore.MediaColumns.MIME_TYPE, MimeTypes.OctetStream) + put(MediaStore.MediaColumns.RELATIVE_PATH, Environment.DIRECTORY_DOWNLOADS) + } + val resolver = context.contentResolver + val outputUri = resolver.insert(MediaStore.Downloads.EXTERNAL_CONTENT_URI, contentValues) + if (outputUri != null) { + file.inputStream().use { input -> + resolver.openOutputStream(outputUri).use { output -> + input.copyTo(output!!, DEFAULT_BUFFER_SIZE) + } + } + } + } + + private fun saveOnDiskUsingExternalStorageApi(path: String) { + val file = File(path) + val target = File( + Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS), + file.name + ) + file.inputStream().use { input -> + FileOutputStream(target).use { output -> + input.copyTo(output) + } + } + } +} diff --git a/features/viewfolder/impl/src/main/kotlin/io/element/android/features/viewfolder/impl/file/FileShare.kt b/features/viewfolder/impl/src/main/kotlin/io/element/android/features/viewfolder/impl/file/FileShare.kt new file mode 100644 index 0000000000..c0dd573a3e --- /dev/null +++ b/features/viewfolder/impl/src/main/kotlin/io/element/android/features/viewfolder/impl/file/FileShare.kt @@ -0,0 +1,72 @@ +/* + * 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 io.element.android.features.viewfolder.impl.file + +import android.content.Context +import android.content.Intent +import android.net.Uri +import androidx.core.content.FileProvider +import com.squareup.anvil.annotations.ContributesBinding +import io.element.android.libraries.core.coroutine.CoroutineDispatchers +import io.element.android.libraries.core.meta.BuildMeta +import io.element.android.libraries.core.mimetype.MimeTypes +import io.element.android.libraries.di.AppScope +import io.element.android.libraries.di.ApplicationContext +import kotlinx.coroutines.withContext +import timber.log.Timber +import java.io.File +import javax.inject.Inject + +interface FileShare { + suspend fun share( + path: String + ) +} + +@ContributesBinding(AppScope::class) +class DefaultFileShare @Inject constructor( + @ApplicationContext private val context: Context, + private val dispatchers: CoroutineDispatchers, + private val buildMeta: BuildMeta, +) : FileShare { + override suspend fun share( + path: String, + ) { + runCatching { + val file = File(path) + val shareableUri = file.toShareableUri() + val shareMediaIntent = Intent(Intent.ACTION_SEND) + .setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION) + .putExtra(Intent.EXTRA_STREAM, shareableUri) + .setTypeAndNormalize(MimeTypes.OctetStream) + withContext(dispatchers.main) { + val intent = Intent.createChooser(shareMediaIntent, null) + intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) + context.startActivity(intent) + } + }.onSuccess { + Timber.v("Share file succeed") + }.onFailure { + Timber.e(it, "Share file failed") + } + } + + private fun File.toShareableUri(): Uri { + val authority = "${buildMeta.applicationId}.fileprovider" + return FileProvider.getUriForFile(context, authority, this).normalizeScheme() + } +} diff --git a/features/viewfolder/impl/src/main/kotlin/io/element/android/features/viewfolder/impl/file/ViewFileEvents.kt b/features/viewfolder/impl/src/main/kotlin/io/element/android/features/viewfolder/impl/file/ViewFileEvents.kt new file mode 100644 index 0000000000..dfea39d2e6 --- /dev/null +++ b/features/viewfolder/impl/src/main/kotlin/io/element/android/features/viewfolder/impl/file/ViewFileEvents.kt @@ -0,0 +1,22 @@ +/* + * 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 io.element.android.features.viewfolder.impl.file + +sealed interface ViewFileEvents { + data object SaveOnDisk : ViewFileEvents + data object Share : ViewFileEvents +} diff --git a/features/viewfolder/impl/src/main/kotlin/io/element/android/features/viewfolder/impl/file/ViewFileNode.kt b/features/viewfolder/impl/src/main/kotlin/io/element/android/features/viewfolder/impl/file/ViewFileNode.kt new file mode 100644 index 0000000000..3d4ad727fe --- /dev/null +++ b/features/viewfolder/impl/src/main/kotlin/io/element/android/features/viewfolder/impl/file/ViewFileNode.kt @@ -0,0 +1,67 @@ +/* + * 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 io.element.android.features.viewfolder.impl.file + +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import com.bumble.appyx.core.modality.BuildContext +import com.bumble.appyx.core.node.Node +import com.bumble.appyx.core.plugin.Plugin +import com.bumble.appyx.core.plugin.plugins +import dagger.assisted.Assisted +import dagger.assisted.AssistedInject +import io.element.android.anvilannotations.ContributesNode +import io.element.android.libraries.architecture.NodeInputs +import io.element.android.libraries.architecture.inputs +import io.element.android.libraries.di.AppScope + +@ContributesNode(AppScope::class) +class ViewFileNode @AssistedInject constructor( + @Assisted buildContext: BuildContext, + @Assisted plugins: List, + presenterFactory: ViewFilePresenter.Factory, +) : Node(buildContext, plugins = plugins) { + data class Inputs( + val path: String, + val name: String, + ) : NodeInputs + + interface Callback : Plugin { + fun onBackPressed() + } + + private val inputs: Inputs = inputs() + + private val presenter = presenterFactory.create( + path = inputs.path, + name = inputs.name, + ) + + private fun onBackPressed() { + plugins().forEach { it.onBackPressed() } + } + + @Composable + override fun View(modifier: Modifier) { + val state = presenter.present() + ViewFileView( + state = state, + modifier = modifier, + onBackPressed = ::onBackPressed, + ) + } +} diff --git a/features/viewfolder/impl/src/main/kotlin/io/element/android/features/viewfolder/impl/file/ViewFilePresenter.kt b/features/viewfolder/impl/src/main/kotlin/io/element/android/features/viewfolder/impl/file/ViewFilePresenter.kt new file mode 100644 index 0000000000..1a1e5ba3dd --- /dev/null +++ b/features/viewfolder/impl/src/main/kotlin/io/element/android/features/viewfolder/impl/file/ViewFilePresenter.kt @@ -0,0 +1,78 @@ +/* + * 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 io.element.android.features.viewfolder.impl.file + +import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.runtime.rememberCoroutineScope +import androidx.compose.runtime.setValue +import dagger.assisted.Assisted +import dagger.assisted.AssistedFactory +import dagger.assisted.AssistedInject +import io.element.android.libraries.architecture.Presenter +import kotlinx.collections.immutable.toImmutableList +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.launch + +class ViewFilePresenter @AssistedInject constructor( + @Assisted("path") val path: String, + @Assisted("name") val name: String, + private val fileContentReader: FileContentReader, + private val fileShare: FileShare, + private val fileSave: FileSave, +) : Presenter { + @AssistedFactory + interface Factory { + fun create( + @Assisted("path") path: String, + @Assisted("name") name: String, + ): ViewFilePresenter + } + + @Composable + override fun present(): ViewFileState { + val coroutineScope = rememberCoroutineScope() + + fun handleEvent(event: ViewFileEvents) { + when (event) { + ViewFileEvents.Share -> coroutineScope.share(path) + ViewFileEvents.SaveOnDisk -> coroutineScope.save(path) + } + } + + var lines by remember { mutableStateOf(emptyList()) } + LaunchedEffect(Unit) { + lines = fileContentReader.getLines(path) + } + return ViewFileState( + name = name, + lines = lines.toImmutableList(), + eventSink = ::handleEvent, + ) + } + + private fun CoroutineScope.share(path: String) = launch { + fileShare.share(path) + } + + private fun CoroutineScope.save(path: String) = launch { + fileSave.save(path) + } +} diff --git a/features/viewfolder/impl/src/main/kotlin/io/element/android/features/viewfolder/impl/file/ViewFileState.kt b/features/viewfolder/impl/src/main/kotlin/io/element/android/features/viewfolder/impl/file/ViewFileState.kt new file mode 100644 index 0000000000..9971c4b7d0 --- /dev/null +++ b/features/viewfolder/impl/src/main/kotlin/io/element/android/features/viewfolder/impl/file/ViewFileState.kt @@ -0,0 +1,25 @@ +/* + * 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 io.element.android.features.viewfolder.impl.file + +import kotlinx.collections.immutable.ImmutableList + +data class ViewFileState( + val name: String, + val lines: ImmutableList, + val eventSink: (ViewFileEvents) -> Unit, +) diff --git a/features/viewfolder/impl/src/main/kotlin/io/element/android/features/viewfolder/impl/file/ViewFileStateProvider.kt b/features/viewfolder/impl/src/main/kotlin/io/element/android/features/viewfolder/impl/file/ViewFileStateProvider.kt new file mode 100644 index 0000000000..9687e82405 --- /dev/null +++ b/features/viewfolder/impl/src/main/kotlin/io/element/android/features/viewfolder/impl/file/ViewFileStateProvider.kt @@ -0,0 +1,50 @@ +/* + * 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 io.element.android.features.viewfolder.impl.file + +import androidx.compose.ui.tooling.preview.PreviewParameterProvider +import kotlinx.collections.immutable.toImmutableList + +open class ViewFileStateProvider : PreviewParameterProvider { + override val values: Sequence + get() = sequenceOf( + aViewFileState(), + aViewFileState( + lines = listOf( + "Line 1", + "Line 2", + "Line 3 lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor" + + " incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam,", + "01-23 13:14:50.740 25818 25818 V verbose", + "01-23 13:14:50.740 25818 25818 D debug", + "01-23 13:14:50.740 25818 25818 I info", + "01-23 13:14:50.740 25818 25818 W warning", + "01-23 13:14:50.740 25818 25818 E error", + "01-23 13:14:50.740 25818 25818 A assertion", + ) + ) + ) +} + +fun aViewFileState( + name: String = "aName", + lines: List = emptyList(), +) = ViewFileState( + name = name, + lines = lines.toImmutableList(), + eventSink = {}, +) diff --git a/features/viewfolder/impl/src/main/kotlin/io/element/android/features/viewfolder/impl/file/ViewFileView.kt b/features/viewfolder/impl/src/main/kotlin/io/element/android/features/viewfolder/impl/file/ViewFileView.kt new file mode 100644 index 0000000000..265f6892ad --- /dev/null +++ b/features/viewfolder/impl/src/main/kotlin/io/element/android/features/viewfolder/impl/file/ViewFileView.kt @@ -0,0 +1,206 @@ +/* + * 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 io.element.android.features.viewfolder.impl.file + +import androidx.compose.foundation.clickable +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.consumeWindowInsets +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.size +import androidx.compose.foundation.layout.widthIn +import androidx.compose.foundation.lazy.LazyColumn +import androidx.compose.foundation.lazy.itemsIndexed +import androidx.compose.material3.ExperimentalMaterial3Api +import androidx.compose.material3.MaterialTheme +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.drawWithContent +import androidx.compose.ui.geometry.Offset +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.platform.LocalContext +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.text.style.TextAlign +import androidx.compose.ui.tooling.preview.PreviewParameter +import androidx.compose.ui.unit.dp +import io.element.android.compound.theme.ElementTheme +import io.element.android.libraries.androidutils.system.copyToClipboard +import io.element.android.libraries.designsystem.components.button.BackButton +import io.element.android.libraries.designsystem.icons.CompoundDrawables +import io.element.android.libraries.designsystem.preview.ElementPreview +import io.element.android.libraries.designsystem.preview.PreviewsDayNight +import io.element.android.libraries.designsystem.theme.aliasScreenTitle +import io.element.android.libraries.designsystem.theme.components.Icon +import io.element.android.libraries.designsystem.theme.components.IconButton +import io.element.android.libraries.designsystem.theme.components.Scaffold +import io.element.android.libraries.designsystem.theme.components.Text +import io.element.android.libraries.designsystem.theme.components.TopAppBar +import io.element.android.libraries.ui.strings.CommonStrings + +@OptIn(ExperimentalMaterial3Api::class) +@Composable +fun ViewFileView( + state: ViewFileState, + onBackPressed: () -> Unit, + modifier: Modifier = Modifier, +) { + Scaffold( + modifier = modifier, + topBar = { + TopAppBar( + navigationIcon = { + BackButton(onClick = onBackPressed) + }, + title = { + Text( + text = state.name, + style = ElementTheme.typography.aliasScreenTitle, + ) + }, + actions = { + IconButton( + onClick = { + state.eventSink(ViewFileEvents.Share) + }, + ) { + Icon( + resourceId = CompoundDrawables.ic_share_android, + contentDescription = stringResource(id = CommonStrings.action_share), + ) + } + IconButton( + onClick = { + state.eventSink(ViewFileEvents.SaveOnDisk) + }, + ) { + Icon( + resourceId = CompoundDrawables.ic_download, + contentDescription = stringResource(id = CommonStrings.action_save), + ) + } + } + ) + }, + content = { padding -> + Column( + modifier = Modifier + .padding(padding) + .consumeWindowInsets(padding) + ) { + LazyColumn( + modifier = Modifier.weight(1f) + ) { + if (state.lines.isEmpty()) { + item { + Spacer(Modifier.size(80.dp)) + Text( + text = "Empty file", + textAlign = TextAlign.Center, + color = MaterialTheme.colorScheme.tertiary, + modifier = Modifier.fillMaxWidth() + ) + } + } else { + itemsIndexed( + items = state.lines, + ) { index, line -> + LineRow( + lineNumber = index + 1, + line = line, + ) + } + } + } + } + } + ) +} + +@Composable +private fun LineRow( + lineNumber: Int, + line: String, +) { + val context = LocalContext.current + Row( + modifier = Modifier + .fillMaxWidth() + .clickable(onClick = { + context.copyToClipboard( + line, + "Line copied to clipboard", + ) + }) + ) { + Text( + modifier = Modifier + .widthIn(min = 36.dp) + .padding(horizontal = 4.dp), + text = "$lineNumber", + textAlign = TextAlign.End, + color = ElementTheme.colors.textSecondary, + style = ElementTheme.typography.fontBodyMdMedium, + ) + val color = ElementTheme.colors.textSecondary + val width = 0.5.dp.value + Text( + modifier = Modifier + .weight(1f) + .drawWithContent { + // Using .height(IntrinsicSize.Min) on the Row does not work well inside LazyColumn + drawLine( + color = color, + start = Offset(0f, 0f), + end = Offset(0f, size.height), + strokeWidth = width + ) + drawContent() + } + .padding(horizontal = 4.dp), + text = line, + color = line.toColor(), + style = ElementTheme.typography.fontBodyMdRegular + ) + } +} + +/** + * Convert a logcat line to a color. + * Ex: `01-23 13:14:50.740 25818 25818 D org.matrix.rust.sdk: elementx: SyncIndicator = Hide | RustRoomListService.kt:81` + */ +@Composable +private fun String.toColor(): Color { + return when (getOrNull(31)) { + 'D' -> Color(0xFF299999) + 'I' -> Color(0xFFABC023) + 'W' -> Color(0xFFBBB529) + 'E' -> Color(0xFFFF6B68) + 'A' -> Color(0xFFFF6B68) + else -> ElementTheme.colors.textPrimary + } +} + +@PreviewsDayNight +@Composable +internal fun ViewFileViewPreview(@PreviewParameter(ViewFileStateProvider::class) state: ViewFileState) = ElementPreview { + ViewFileView( + state = state, + onBackPressed = {}, + ) +} diff --git a/features/viewfolder/impl/src/main/kotlin/io/element/android/features/viewfolder/impl/folder/FolderExplorer.kt b/features/viewfolder/impl/src/main/kotlin/io/element/android/features/viewfolder/impl/folder/FolderExplorer.kt new file mode 100644 index 0000000000..68a0373b8a --- /dev/null +++ b/features/viewfolder/impl/src/main/kotlin/io/element/android/features/viewfolder/impl/folder/FolderExplorer.kt @@ -0,0 +1,61 @@ +/* + * 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 io.element.android.features.viewfolder.impl.folder + +import com.squareup.anvil.annotations.ContributesBinding +import io.element.android.features.viewfolder.impl.model.Item +import io.element.android.libraries.androidutils.filesize.FileSizeFormatter +import io.element.android.libraries.core.coroutine.CoroutineDispatchers +import io.element.android.libraries.di.AppScope +import kotlinx.coroutines.withContext +import java.io.File +import javax.inject.Inject + +interface FolderExplorer { + suspend fun getItems(path: String): List +} + +@ContributesBinding(AppScope::class) +class DefaultFolderExplorer @Inject constructor( + private val fileSizeFormatter: FileSizeFormatter, + private val dispatchers: CoroutineDispatchers, +) : FolderExplorer { + override suspend fun getItems(path: String): List = withContext(dispatchers.io) { + val current = File(path) + if (current.isFile) { + error("Not a folder") + } + val folderContent = current.listFiles().orEmpty().map { file -> + if (file.isDirectory) { + Item.Folder( + path = file.path, + name = file.name + ) + } else { + Item.File( + path = file.path, + name = file.name, + formattedSize = fileSizeFormatter.format(file.length()), + ) + } + } + buildList { + addAll(folderContent.filterIsInstance().sortedBy(Item.Folder::name)) + addAll(folderContent.filterIsInstance().sortedBy(Item.File::name)) + } + } +} diff --git a/features/viewfolder/impl/src/main/kotlin/io/element/android/features/viewfolder/impl/folder/ViewFolderNode.kt b/features/viewfolder/impl/src/main/kotlin/io/element/android/features/viewfolder/impl/folder/ViewFolderNode.kt new file mode 100644 index 0000000000..23dac7bc4e --- /dev/null +++ b/features/viewfolder/impl/src/main/kotlin/io/element/android/features/viewfolder/impl/folder/ViewFolderNode.kt @@ -0,0 +1,74 @@ +/* + * 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 io.element.android.features.viewfolder.impl.folder + +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import com.bumble.appyx.core.modality.BuildContext +import com.bumble.appyx.core.node.Node +import com.bumble.appyx.core.plugin.Plugin +import com.bumble.appyx.core.plugin.plugins +import dagger.assisted.Assisted +import dagger.assisted.AssistedInject +import io.element.android.anvilannotations.ContributesNode +import io.element.android.features.viewfolder.impl.model.Item +import io.element.android.libraries.architecture.NodeInputs +import io.element.android.libraries.architecture.inputs +import io.element.android.libraries.di.AppScope + +@ContributesNode(AppScope::class) +class ViewFolderNode @AssistedInject constructor( + @Assisted buildContext: BuildContext, + @Assisted plugins: List, + presenterFactory: ViewFolderPresenter.Factory, +) : Node(buildContext, plugins = plugins) { + data class Inputs( + val canGoUp: Boolean, + val path: String, + ) : NodeInputs + + interface Callback : Plugin { + fun onBackPressed() + fun onNavigateTo(item: Item) + } + + private val inputs: Inputs = inputs() + + private val presenter = presenterFactory.create( + canGoUp = inputs.canGoUp, + path = inputs.path, + ) + + private fun onBackPressed() { + plugins().forEach { it.onBackPressed() } + } + + private fun onNavigateTo(item: Item) { + plugins().forEach { it.onNavigateTo(item) } + } + + @Composable + override fun View(modifier: Modifier) { + val state = presenter.present() + ViewFolderView( + state = state, + modifier = modifier, + onNavigateTo = ::onNavigateTo, + onBackPressed = ::onBackPressed, + ) + } +} diff --git a/features/viewfolder/impl/src/main/kotlin/io/element/android/features/viewfolder/impl/folder/ViewFolderPresenter.kt b/features/viewfolder/impl/src/main/kotlin/io/element/android/features/viewfolder/impl/folder/ViewFolderPresenter.kt new file mode 100644 index 0000000000..64e58036e2 --- /dev/null +++ b/features/viewfolder/impl/src/main/kotlin/io/element/android/features/viewfolder/impl/folder/ViewFolderPresenter.kt @@ -0,0 +1,56 @@ +/* + * 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 io.element.android.features.viewfolder.impl.folder + +import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.runtime.setValue +import dagger.assisted.Assisted +import dagger.assisted.AssistedFactory +import dagger.assisted.AssistedInject +import io.element.android.features.viewfolder.impl.model.Item +import io.element.android.libraries.architecture.Presenter +import kotlinx.collections.immutable.toImmutableList + +class ViewFolderPresenter @AssistedInject constructor( + @Assisted val canGoUp: Boolean, + @Assisted val path: String, + private val folderExplorer: FolderExplorer, +) : Presenter { + @AssistedFactory + interface Factory { + fun create(canGoUp: Boolean, path: String): ViewFolderPresenter + } + + @Composable + override fun present(): ViewFolderState { + var content by remember { mutableStateOf(emptyList()) } + LaunchedEffect(Unit) { + content = buildList { + if (canGoUp) add(Item.Parent) + addAll(folderExplorer.getItems(path)) + } + } + return ViewFolderState( + path = path, + content = content.toImmutableList(), + ) + } +} diff --git a/features/viewfolder/impl/src/main/kotlin/io/element/android/features/viewfolder/impl/folder/ViewFolderState.kt b/features/viewfolder/impl/src/main/kotlin/io/element/android/features/viewfolder/impl/folder/ViewFolderState.kt new file mode 100644 index 0000000000..d31e2ff3cd --- /dev/null +++ b/features/viewfolder/impl/src/main/kotlin/io/element/android/features/viewfolder/impl/folder/ViewFolderState.kt @@ -0,0 +1,25 @@ +/* + * 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 io.element.android.features.viewfolder.impl.folder + +import io.element.android.features.viewfolder.impl.model.Item +import kotlinx.collections.immutable.ImmutableList + +data class ViewFolderState( + val path: String, + val content: ImmutableList, +) diff --git a/features/viewfolder/impl/src/main/kotlin/io/element/android/features/viewfolder/impl/folder/ViewFolderStateProvider.kt b/features/viewfolder/impl/src/main/kotlin/io/element/android/features/viewfolder/impl/folder/ViewFolderStateProvider.kt new file mode 100644 index 0000000000..76e7fbbe8d --- /dev/null +++ b/features/viewfolder/impl/src/main/kotlin/io/element/android/features/viewfolder/impl/folder/ViewFolderStateProvider.kt @@ -0,0 +1,43 @@ +/* + * 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 io.element.android.features.viewfolder.impl.folder + +import androidx.compose.ui.tooling.preview.PreviewParameterProvider +import io.element.android.features.viewfolder.impl.model.Item +import kotlinx.collections.immutable.toImmutableList + +open class ViewFolderStateProvider : PreviewParameterProvider { + override val values: Sequence + get() = sequenceOf( + aViewFolderState(), + aViewFolderState( + content = listOf( + Item.Parent, + Item.Folder("aPath", "aFolder"), + Item.File("aPath", "aFile", "12kB"), + ) + ) + ) +} + +fun aViewFolderState( + path: String = "aPath", + content: List = emptyList(), +) = ViewFolderState( + path = path, + content = content.toImmutableList(), +) diff --git a/features/viewfolder/impl/src/main/kotlin/io/element/android/features/viewfolder/impl/folder/ViewFolderView.kt b/features/viewfolder/impl/src/main/kotlin/io/element/android/features/viewfolder/impl/folder/ViewFolderView.kt new file mode 100644 index 0000000000..44453c253e --- /dev/null +++ b/features/viewfolder/impl/src/main/kotlin/io/element/android/features/viewfolder/impl/folder/ViewFolderView.kt @@ -0,0 +1,165 @@ +/* + * 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 io.element.android.features.viewfolder.impl.folder + +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.consumeWindowInsets +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.size +import androidx.compose.foundation.lazy.LazyColumn +import androidx.compose.foundation.lazy.items +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.outlined.Description +import androidx.compose.material.icons.outlined.Folder +import androidx.compose.material.icons.outlined.SubdirectoryArrowLeft +import androidx.compose.material3.ExperimentalMaterial3Api +import androidx.compose.material3.MaterialTheme +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.text.style.TextAlign +import androidx.compose.ui.tooling.preview.PreviewParameter +import androidx.compose.ui.unit.dp +import io.element.android.compound.theme.ElementTheme +import io.element.android.features.viewfolder.impl.model.Item +import io.element.android.libraries.designsystem.components.button.BackButton +import io.element.android.libraries.designsystem.components.list.ListItemContent +import io.element.android.libraries.designsystem.preview.ElementPreview +import io.element.android.libraries.designsystem.preview.PreviewsDayNight +import io.element.android.libraries.designsystem.theme.aliasScreenTitle +import io.element.android.libraries.designsystem.theme.components.IconSource +import io.element.android.libraries.designsystem.theme.components.ListItem +import io.element.android.libraries.designsystem.theme.components.Scaffold +import io.element.android.libraries.designsystem.theme.components.Text +import io.element.android.libraries.designsystem.theme.components.TopAppBar + +@OptIn(ExperimentalMaterial3Api::class) +@Composable +fun ViewFolderView( + state: ViewFolderState, + onNavigateTo: (Item) -> Unit, + onBackPressed: () -> Unit, + modifier: Modifier = Modifier, +) { + Scaffold( + modifier = modifier, + topBar = { + TopAppBar( + navigationIcon = { + BackButton(onClick = onBackPressed) + }, + title = { + Text( + text = state.path, + style = ElementTheme.typography.aliasScreenTitle, + ) + } + ) + }, + content = { padding -> + Column( + modifier = Modifier + .padding(padding) + .consumeWindowInsets(padding) + ) { + LazyColumn( + modifier = Modifier.weight(1f) + ) { + items( + items = state.content, + ) { item -> + ItemRow( + item = item, + onItemClicked = { onNavigateTo(item) }, + ) + } + if (state.content.none { it !is Item.Parent }) { + item { + Spacer(Modifier.size(80.dp)) + Text( + text = "Empty folder", + textAlign = TextAlign.Center, + color = MaterialTheme.colorScheme.tertiary, + modifier = Modifier.fillMaxWidth() + ) + } + } + } + } + } + ) +} + +@Composable +private fun ItemRow( + item: Item, + onItemClicked: () -> Unit, +) { + when (item) { + Item.Parent -> { + ListItem( + leadingContent = ListItemContent.Icon(IconSource.Vector(Icons.Outlined.SubdirectoryArrowLeft)), + headlineContent = { + Text( + text = "..", + modifier = Modifier.padding(16.dp), + style = ElementTheme.typography.fontBodyMdMedium, + ) + }, + onClick = onItemClicked, + ) + } + is Item.Folder -> { + ListItem( + leadingContent = ListItemContent.Icon(IconSource.Vector(Icons.Outlined.Folder)), + headlineContent = { + Text( + text = item.name, + modifier = Modifier.padding(16.dp), + style = ElementTheme.typography.fontBodyMdMedium, + ) + }, + onClick = onItemClicked, + ) + } + is Item.File -> { + ListItem( + leadingContent = ListItemContent.Icon(IconSource.Vector(Icons.Outlined.Description)), + headlineContent = { + Text( + text = item.name, + modifier = Modifier.padding(16.dp), + style = ElementTheme.typography.fontBodyMdMedium, + ) + }, + trailingContent = ListItemContent.Text(item.formattedSize), + onClick = onItemClicked, + ) + } + } +} + +@PreviewsDayNight +@Composable +internal fun ViewFolderViewPreview(@PreviewParameter(ViewFolderStateProvider::class) state: ViewFolderState) = ElementPreview { + ViewFolderView( + state = state, + onNavigateTo = {}, + onBackPressed = {}, + ) +} diff --git a/features/viewfolder/impl/src/main/kotlin/io/element/android/features/viewfolder/impl/model/Item.kt b/features/viewfolder/impl/src/main/kotlin/io/element/android/features/viewfolder/impl/model/Item.kt new file mode 100644 index 0000000000..2969ec3018 --- /dev/null +++ b/features/viewfolder/impl/src/main/kotlin/io/element/android/features/viewfolder/impl/model/Item.kt @@ -0,0 +1,35 @@ +/* + * 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 io.element.android.features.viewfolder.impl.model + +import androidx.compose.runtime.Immutable + +@Immutable +sealed interface Item { + data object Parent : Item + + data class Folder( + val path: String, + val name: String, + ) : Item + + data class File( + val path: String, + val name: String, + val formattedSize: String, + ) : Item +} diff --git a/features/viewfolder/impl/src/main/kotlin/io/element/android/features/viewfolder/impl/root/ViewFolderRootNode.kt b/features/viewfolder/impl/src/main/kotlin/io/element/android/features/viewfolder/impl/root/ViewFolderRootNode.kt new file mode 100644 index 0000000000..697bd76d13 --- /dev/null +++ b/features/viewfolder/impl/src/main/kotlin/io/element/android/features/viewfolder/impl/root/ViewFolderRootNode.kt @@ -0,0 +1,148 @@ +/* + * 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 io.element.android.features.viewfolder.impl.root + +import android.os.Parcelable +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import com.bumble.appyx.core.modality.BuildContext +import com.bumble.appyx.core.node.Node +import com.bumble.appyx.core.plugin.Plugin +import com.bumble.appyx.core.plugin.plugins +import com.bumble.appyx.navmodel.backstack.BackStack +import com.bumble.appyx.navmodel.backstack.operation.pop +import com.bumble.appyx.navmodel.backstack.operation.push +import dagger.assisted.Assisted +import dagger.assisted.AssistedInject +import io.element.android.anvilannotations.ContributesNode +import io.element.android.features.viewfolder.api.ViewFolderEntryPoint +import io.element.android.features.viewfolder.impl.file.ViewFileNode +import io.element.android.features.viewfolder.impl.folder.ViewFolderNode +import io.element.android.features.viewfolder.impl.model.Item +import io.element.android.libraries.architecture.BackstackView +import io.element.android.libraries.architecture.BaseFlowNode +import io.element.android.libraries.architecture.NodeInputs +import io.element.android.libraries.architecture.createNode +import io.element.android.libraries.architecture.inputs +import io.element.android.libraries.di.AppScope +import kotlinx.parcelize.Parcelize + +@ContributesNode(AppScope::class) +class ViewFolderRootNode @AssistedInject constructor( + @Assisted buildContext: BuildContext, + @Assisted plugins: List, +) : BaseFlowNode( + backstack = BackStack( + initialElement = NavTarget.Root, + savedStateMap = buildContext.savedStateMap, + ), + buildContext = buildContext, + plugins = plugins +) { + sealed interface NavTarget : Parcelable { + @Parcelize + data object Root : NavTarget + + @Parcelize + data class Folder( + val path: String, + ) : NavTarget + + @Parcelize + data class File( + val path: String, + val name: String, + ) : NavTarget + } + + data class Inputs( + val rootPath: String, + ) : NodeInputs + + private val inputs: Inputs = inputs() + + override fun resolve(navTarget: NavTarget, buildContext: BuildContext): Node { + return when (navTarget) { + is NavTarget.Root -> { + createViewFolderNode( + buildContext, + inputs = ViewFolderNode.Inputs( + canGoUp = false, + path = inputs.rootPath, + ) + ) + } + is NavTarget.Folder -> { + createViewFolderNode( + buildContext, + inputs = ViewFolderNode.Inputs( + canGoUp = true, + path = navTarget.path, + ) + ) + } + is NavTarget.File -> { + val callback: ViewFileNode.Callback = object : ViewFileNode.Callback { + override fun onBackPressed() { + backstack.pop() + } + } + val inputs = ViewFileNode.Inputs( + path = navTarget.path, + name = navTarget.name, + ) + createNode(buildContext, plugins = listOf(inputs, callback)) + } + } + } + + private fun createViewFolderNode( + buildContext: BuildContext, + inputs: ViewFolderNode.Inputs, + ): Node { + val callback: ViewFolderNode.Callback = object : ViewFolderNode.Callback { + override fun onBackPressed() { + onDone() + } + + override fun onNavigateTo(item: Item) { + when (item) { + Item.Parent -> { + // Should not happen when in Root since parent is not accessible from root (canGoUp set to false) + backstack.pop() + } + is Item.Folder -> { + backstack.push(NavTarget.Folder(path = item.path)) + } + is Item.File -> { + backstack.push(NavTarget.File(path = item.path, name = item.name)) + } + } + } + } + return createNode(buildContext, plugins = listOf(inputs, callback)) + } + + @Composable + override fun View(modifier: Modifier) { + BackstackView() + } + + private fun onDone() { + plugins().forEach { it.onDone() } + } +} diff --git a/features/viewfolder/impl/src/test/kotlin/io/element/android/features/viewfolder/test/file/FakeFileContentReader.kt b/features/viewfolder/impl/src/test/kotlin/io/element/android/features/viewfolder/test/file/FakeFileContentReader.kt new file mode 100644 index 0000000000..9a8d51e329 --- /dev/null +++ b/features/viewfolder/impl/src/test/kotlin/io/element/android/features/viewfolder/test/file/FakeFileContentReader.kt @@ -0,0 +1,29 @@ +/* + * 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 io.element.android.features.viewfolder.test.file + +import io.element.android.features.viewfolder.impl.file.FileContentReader + +class FakeFileContentReader : FileContentReader { + private var result: List = emptyList() + + fun givenResult(result: List) { + this.result = result + } + + override suspend fun getLines(path: String): List = result +} diff --git a/features/viewfolder/impl/src/test/kotlin/io/element/android/features/viewfolder/test/file/FakeFileSave.kt b/features/viewfolder/impl/src/test/kotlin/io/element/android/features/viewfolder/test/file/FakeFileSave.kt new file mode 100644 index 0000000000..0a35526188 --- /dev/null +++ b/features/viewfolder/impl/src/test/kotlin/io/element/android/features/viewfolder/test/file/FakeFileSave.kt @@ -0,0 +1,28 @@ +/* + * 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 io.element.android.features.viewfolder.test.file + +import io.element.android.features.viewfolder.impl.file.FileSave + +class FakeFileSave : FileSave { + var hasBeenCalled = false + private set + + override suspend fun save(path: String) { + hasBeenCalled = true + } +} diff --git a/features/viewfolder/impl/src/test/kotlin/io/element/android/features/viewfolder/test/file/FakeFileShare.kt b/features/viewfolder/impl/src/test/kotlin/io/element/android/features/viewfolder/test/file/FakeFileShare.kt new file mode 100644 index 0000000000..34b30a99ef --- /dev/null +++ b/features/viewfolder/impl/src/test/kotlin/io/element/android/features/viewfolder/test/file/FakeFileShare.kt @@ -0,0 +1,28 @@ +/* + * 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 io.element.android.features.viewfolder.test.file + +import io.element.android.features.viewfolder.impl.file.FileShare + +class FakeFileShare : FileShare { + var hasBeenCalled = false + private set + + override suspend fun share(path: String) { + hasBeenCalled = true + } +} diff --git a/features/viewfolder/impl/src/test/kotlin/io/element/android/features/viewfolder/test/file/ViewFilePresenterTest.kt b/features/viewfolder/impl/src/test/kotlin/io/element/android/features/viewfolder/test/file/ViewFilePresenterTest.kt new file mode 100644 index 0000000000..868a812eb2 --- /dev/null +++ b/features/viewfolder/impl/src/test/kotlin/io/element/android/features/viewfolder/test/file/ViewFilePresenterTest.kt @@ -0,0 +1,105 @@ +/* + * 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 io.element.android.features.viewfolder.test.file + +import app.cash.molecule.RecompositionMode +import app.cash.molecule.moleculeFlow +import app.cash.turbine.test +import com.google.common.truth.Truth.assertThat +import io.element.android.features.viewfolder.impl.file.FileContentReader +import io.element.android.features.viewfolder.impl.file.FileSave +import io.element.android.features.viewfolder.impl.file.FileShare +import io.element.android.features.viewfolder.impl.file.ViewFileEvents +import io.element.android.features.viewfolder.impl.file.ViewFilePresenter +import io.element.android.tests.testutils.WarmUpRule +import kotlinx.coroutines.test.runTest +import org.junit.Rule +import org.junit.Test + +class ViewFilePresenterTest { + @get:Rule + val warmUpRule = WarmUpRule() + + @Test + fun `present - initial state`() = runTest { + val fileContentReader = FakeFileContentReader().apply { + givenResult(listOf("aLine")) + } + val presenter = createPresenter(fileContentReader = fileContentReader) + moleculeFlow(RecompositionMode.Immediate) { + presenter.present() + }.test { + skipItems(1) + val initialState = awaitItem() + assertThat(initialState.name).isEqualTo("aName") + assertThat(initialState.lines.size).isEqualTo(1) + assertThat(initialState.lines.first()).isEqualTo("aLine") + } + } + + @Test + fun `present - share should not have any side effect`() = runTest { + val fileContentReader = FakeFileContentReader().apply { + givenResult(listOf("aLine")) + } + val fileShare = FakeFileShare() + val fileSave = FakeFileSave() + val presenter = createPresenter(fileContentReader = fileContentReader, fileShare = fileShare, fileSave = fileSave) + moleculeFlow(RecompositionMode.Immediate) { + presenter.present() + }.test { + skipItems(1) + val initialState = awaitItem() + initialState.eventSink(ViewFileEvents.Share) + assertThat(fileShare.hasBeenCalled).isTrue() + assertThat(fileSave.hasBeenCalled).isFalse() + } + } + + @Test + fun `present - save should not have any side effect`() = runTest { + val fileContentReader = FakeFileContentReader().apply { + givenResult(listOf("aLine")) + } + val fileShare = FakeFileShare() + val fileSave = FakeFileSave() + val presenter = createPresenter(fileContentReader = fileContentReader, fileShare = fileShare, fileSave = fileSave) + moleculeFlow(RecompositionMode.Immediate) { + presenter.present() + }.test { + skipItems(1) + val initialState = awaitItem() + initialState.eventSink(ViewFileEvents.SaveOnDisk) + assertThat(fileShare.hasBeenCalled).isFalse() + assertThat(fileSave.hasBeenCalled).isTrue() + } + } + + private fun createPresenter( + path: String = "aPath", + name: String = "aName", + fileContentReader: FileContentReader = FakeFileContentReader(), + fileShare: FileShare = FakeFileShare(), + fileSave: FileSave = FakeFileSave(), + ) = ViewFilePresenter( + path = path, + name = name, + fileContentReader = fileContentReader, + fileShare = fileShare, + fileSave = fileSave, + ) +} diff --git a/features/viewfolder/impl/src/test/kotlin/io/element/android/features/viewfolder/test/folder/FakeFolderExplorer.kt b/features/viewfolder/impl/src/test/kotlin/io/element/android/features/viewfolder/test/folder/FakeFolderExplorer.kt new file mode 100644 index 0000000000..c4a60303b8 --- /dev/null +++ b/features/viewfolder/impl/src/test/kotlin/io/element/android/features/viewfolder/test/folder/FakeFolderExplorer.kt @@ -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 io.element.android.features.viewfolder.test.folder + +import io.element.android.features.viewfolder.impl.folder.FolderExplorer +import io.element.android.features.viewfolder.impl.model.Item + +class FakeFolderExplorer : FolderExplorer { + private var result: List = emptyList() + + fun givenResult(result: List) { + this.result = result + } + + override suspend fun getItems(path: String): List = result +} diff --git a/features/viewfolder/impl/src/test/kotlin/io/element/android/features/viewfolder/test/folder/ViewFolderPresenterTest.kt b/features/viewfolder/impl/src/test/kotlin/io/element/android/features/viewfolder/test/folder/ViewFolderPresenterTest.kt new file mode 100644 index 0000000000..209d76cb9d --- /dev/null +++ b/features/viewfolder/impl/src/test/kotlin/io/element/android/features/viewfolder/test/folder/ViewFolderPresenterTest.kt @@ -0,0 +1,99 @@ +/* + * 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 io.element.android.features.viewfolder.test.folder + +import app.cash.molecule.RecompositionMode +import app.cash.molecule.moleculeFlow +import app.cash.turbine.test +import com.google.common.truth.Truth.assertThat +import io.element.android.features.viewfolder.impl.folder.FolderExplorer +import io.element.android.features.viewfolder.impl.folder.ViewFolderPresenter +import io.element.android.features.viewfolder.impl.model.Item +import io.element.android.tests.testutils.WarmUpRule +import kotlinx.coroutines.test.runTest +import org.junit.Rule +import org.junit.Test + +class ViewFolderPresenterTest { + @get:Rule + val warmUpRule = WarmUpRule() + + @Test + fun `present - initial state`() = runTest { + val presenter = createPresenter() + moleculeFlow(RecompositionMode.Immediate) { + presenter.present() + }.test { + val initialState = awaitItem() + assertThat(initialState.path).isEqualTo("aPath") + assertThat(initialState.content).isEmpty() + } + } + + @Test + fun `present - list items from root`() = runTest { + val items = listOf( + Item.Folder("aFilePath", "aFilename"), + Item.File("aFolderPath", "aFolderName", "aSize"), + ) + val folderExplorer = FakeFolderExplorer().apply { + givenResult(items) + } + val presenter = createPresenter(folderExplorer = folderExplorer) + moleculeFlow(RecompositionMode.Immediate) { + presenter.present() + }.test { + skipItems(1) + val initialState = awaitItem() + assertThat(initialState.path).isEqualTo("aPath") + assertThat(initialState.content.toList()).isEqualTo(items) + } + } + + @Test + fun `present - list items from a folder`() = runTest { + val items = listOf( + Item.Folder("aFilePath", "aFilename"), + Item.File("aFolderPath", "aFolderName", "aSize"), + ) + val folderExplorer = FakeFolderExplorer().apply { + givenResult(items) + } + val presenter = createPresenter( + canGoUp = true, + folderExplorer = folderExplorer + ) + moleculeFlow(RecompositionMode.Immediate) { + presenter.present() + }.test { + skipItems(1) + val initialState = awaitItem() + assertThat(initialState.path).isEqualTo("aPath") + assertThat(initialState.content.toList()).isEqualTo(listOf(Item.Parent) + items) + } + } + + private fun createPresenter( + canGoUp: Boolean = false, + path: String = "aPath", + folderExplorer: FolderExplorer = FakeFolderExplorer(), + ) = ViewFolderPresenter( + path = path, + canGoUp = canGoUp, + folderExplorer = folderExplorer, + ) +} From a26fbaf840098548cdac0bf1404fda5c93357dda Mon Sep 17 00:00:00 2001 From: ElementBot Date: Wed, 24 Jan 2024 22:22:03 +0000 Subject: [PATCH 082/127] Update screenshots --- ...View_null_BugReportView-Day-0_1_null_0,NEXUS_5,1.0,en].png | 4 ++-- ...View_null_BugReportView-Day-0_1_null_1,NEXUS_5,1.0,en].png | 4 ++-- ...View_null_BugReportView-Day-0_1_null_2,NEXUS_5,1.0,en].png | 4 ++-- ...View_null_BugReportView-Day-0_1_null_3,NEXUS_5,1.0,en].png | 4 ++-- ...ew_null_BugReportView-Night-0_2_null_0,NEXUS_5,1.0,en].png | 4 ++-- ...ew_null_BugReportView-Night-0_2_null_1,NEXUS_5,1.0,en].png | 4 ++-- ...ew_null_BugReportView-Night-0_2_null_2,NEXUS_5,1.0,en].png | 4 ++-- ...ew_null_BugReportView-Night-0_2_null_3,NEXUS_5,1.0,en].png | 4 ++-- ...eView_null_ViewFileView-Day-0_1_null_0,NEXUS_5,1.0,en].png | 3 +++ ...eView_null_ViewFileView-Day-0_1_null_1,NEXUS_5,1.0,en].png | 3 +++ ...iew_null_ViewFileView-Night-0_2_null_0,NEXUS_5,1.0,en].png | 3 +++ ...iew_null_ViewFileView-Night-0_2_null_1,NEXUS_5,1.0,en].png | 3 +++ ...iew_null_ViewFolderView-Day-1_2_null_0,NEXUS_5,1.0,en].png | 3 +++ ...iew_null_ViewFolderView-Day-1_2_null_1,NEXUS_5,1.0,en].png | 3 +++ ...w_null_ViewFolderView-Night-1_3_null_0,NEXUS_5,1.0,en].png | 3 +++ ...w_null_ViewFolderView-Night-1_3_null_1,NEXUS_5,1.0,en].png | 3 +++ 16 files changed, 40 insertions(+), 16 deletions(-) create mode 100644 tests/uitests/src/test/snapshots/images/ui_S_t[f.viewfolder.impl.file_ViewFileView_null_ViewFileView-Day-0_1_null_0,NEXUS_5,1.0,en].png create mode 100644 tests/uitests/src/test/snapshots/images/ui_S_t[f.viewfolder.impl.file_ViewFileView_null_ViewFileView-Day-0_1_null_1,NEXUS_5,1.0,en].png create mode 100644 tests/uitests/src/test/snapshots/images/ui_S_t[f.viewfolder.impl.file_ViewFileView_null_ViewFileView-Night-0_2_null_0,NEXUS_5,1.0,en].png create mode 100644 tests/uitests/src/test/snapshots/images/ui_S_t[f.viewfolder.impl.file_ViewFileView_null_ViewFileView-Night-0_2_null_1,NEXUS_5,1.0,en].png create mode 100644 tests/uitests/src/test/snapshots/images/ui_S_t[f.viewfolder.impl.folder_ViewFolderView_null_ViewFolderView-Day-1_2_null_0,NEXUS_5,1.0,en].png create mode 100644 tests/uitests/src/test/snapshots/images/ui_S_t[f.viewfolder.impl.folder_ViewFolderView_null_ViewFolderView-Day-1_2_null_1,NEXUS_5,1.0,en].png create mode 100644 tests/uitests/src/test/snapshots/images/ui_S_t[f.viewfolder.impl.folder_ViewFolderView_null_ViewFolderView-Night-1_3_null_0,NEXUS_5,1.0,en].png create mode 100644 tests/uitests/src/test/snapshots/images/ui_S_t[f.viewfolder.impl.folder_ViewFolderView_null_ViewFolderView-Night-1_3_null_1,NEXUS_5,1.0,en].png diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.rageshake.impl.bugreport_BugReportView_null_BugReportView-Day-0_1_null_0,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.rageshake.impl.bugreport_BugReportView_null_BugReportView-Day-0_1_null_0,NEXUS_5,1.0,en].png index 85063d3c6b..377c44d62b 100644 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.rageshake.impl.bugreport_BugReportView_null_BugReportView-Day-0_1_null_0,NEXUS_5,1.0,en].png +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.rageshake.impl.bugreport_BugReportView_null_BugReportView-Day-0_1_null_0,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:9ae7fef08fe8f5d08892406cc4c979cebdc8e7751dfda78bac85f4bb0956c245 -size 70071 +oid sha256:510c3b614956dc4caafa9b803243e5f7a77e9ff41a50c28c854bf836dd17bfbb +size 72603 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.rageshake.impl.bugreport_BugReportView_null_BugReportView-Day-0_1_null_1,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.rageshake.impl.bugreport_BugReportView_null_BugReportView-Day-0_1_null_1,NEXUS_5,1.0,en].png index e02ea695e0..b205c3f83f 100644 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.rageshake.impl.bugreport_BugReportView_null_BugReportView-Day-0_1_null_1,NEXUS_5,1.0,en].png +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.rageshake.impl.bugreport_BugReportView_null_BugReportView-Day-0_1_null_1,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:3fc0cdabd97d39da8369f1945b9c3d7c9c05baa6da83c029c8ff99ddd8c8b300 -size 206672 +oid sha256:d9b95973e3fb7cd82992e7a97a24baacd3cb84886f9d94173941ca9b2ac64d07 +size 146787 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.rageshake.impl.bugreport_BugReportView_null_BugReportView-Day-0_1_null_2,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.rageshake.impl.bugreport_BugReportView_null_BugReportView-Day-0_1_null_2,NEXUS_5,1.0,en].png index 0ed580ca73..11e2681985 100644 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.rageshake.impl.bugreport_BugReportView_null_BugReportView-Day-0_1_null_2,NEXUS_5,1.0,en].png +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.rageshake.impl.bugreport_BugReportView_null_BugReportView-Day-0_1_null_2,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:e4e898a358de8246f7a835805994f9865e519a894b426f9a1234a998d13c54ab -size 61356 +oid sha256:ec0097e9379e6b757d7a2db0ce7b95a1bf6ca2387da4c281324764ddadc7b178 +size 63779 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.rageshake.impl.bugreport_BugReportView_null_BugReportView-Day-0_1_null_3,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.rageshake.impl.bugreport_BugReportView_null_BugReportView-Day-0_1_null_3,NEXUS_5,1.0,en].png index 85063d3c6b..377c44d62b 100644 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.rageshake.impl.bugreport_BugReportView_null_BugReportView-Day-0_1_null_3,NEXUS_5,1.0,en].png +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.rageshake.impl.bugreport_BugReportView_null_BugReportView-Day-0_1_null_3,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:9ae7fef08fe8f5d08892406cc4c979cebdc8e7751dfda78bac85f4bb0956c245 -size 70071 +oid sha256:510c3b614956dc4caafa9b803243e5f7a77e9ff41a50c28c854bf836dd17bfbb +size 72603 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.rageshake.impl.bugreport_BugReportView_null_BugReportView-Night-0_2_null_0,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.rageshake.impl.bugreport_BugReportView_null_BugReportView-Night-0_2_null_0,NEXUS_5,1.0,en].png index a8be95376f..4956ae764e 100644 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.rageshake.impl.bugreport_BugReportView_null_BugReportView-Night-0_2_null_0,NEXUS_5,1.0,en].png +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.rageshake.impl.bugreport_BugReportView_null_BugReportView-Night-0_2_null_0,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:f421bfb415b006742fc889588b983f682b82b63d4c28c8b896e94709672ca671 -size 67100 +oid sha256:b63d6e1221d56b8ad8e88757d7a20beafeeb31c3f908dc56a8a27e26aa752b57 +size 69478 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.rageshake.impl.bugreport_BugReportView_null_BugReportView-Night-0_2_null_1,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.rageshake.impl.bugreport_BugReportView_null_BugReportView-Night-0_2_null_1,NEXUS_5,1.0,en].png index c4f73feb5d..a7721efc92 100644 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.rageshake.impl.bugreport_BugReportView_null_BugReportView-Night-0_2_null_1,NEXUS_5,1.0,en].png +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.rageshake.impl.bugreport_BugReportView_null_BugReportView-Night-0_2_null_1,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:0c853ca824f30bb99ab2032e87d9f7ebf8ffb187aae769062381db6afce64a9a -size 202452 +oid sha256:e529a5a5fc1fde9b37321bef36c1c2162a3f6a1a0509c042fc9fe8e515f88220 +size 142480 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.rageshake.impl.bugreport_BugReportView_null_BugReportView-Night-0_2_null_2,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.rageshake.impl.bugreport_BugReportView_null_BugReportView-Night-0_2_null_2,NEXUS_5,1.0,en].png index 2f9f29cafb..5393e8581b 100644 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.rageshake.impl.bugreport_BugReportView_null_BugReportView-Night-0_2_null_2,NEXUS_5,1.0,en].png +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.rageshake.impl.bugreport_BugReportView_null_BugReportView-Night-0_2_null_2,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:ca56f3993bc4713aa16e54bdcff24f96804f84dc8e9557247c56caf53fd14831 -size 56251 +oid sha256:4494a8a23762ca963a3d76969a407021fb3301030ecc5471af63d0d306d768fd +size 58207 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.rageshake.impl.bugreport_BugReportView_null_BugReportView-Night-0_2_null_3,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.rageshake.impl.bugreport_BugReportView_null_BugReportView-Night-0_2_null_3,NEXUS_5,1.0,en].png index a8be95376f..4956ae764e 100644 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.rageshake.impl.bugreport_BugReportView_null_BugReportView-Night-0_2_null_3,NEXUS_5,1.0,en].png +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.rageshake.impl.bugreport_BugReportView_null_BugReportView-Night-0_2_null_3,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:f421bfb415b006742fc889588b983f682b82b63d4c28c8b896e94709672ca671 -size 67100 +oid sha256:b63d6e1221d56b8ad8e88757d7a20beafeeb31c3f908dc56a8a27e26aa752b57 +size 69478 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.viewfolder.impl.file_ViewFileView_null_ViewFileView-Day-0_1_null_0,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.viewfolder.impl.file_ViewFileView_null_ViewFileView-Day-0_1_null_0,NEXUS_5,1.0,en].png new file mode 100644 index 0000000000..36edcb8b83 --- /dev/null +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.viewfolder.impl.file_ViewFileView_null_ViewFileView-Day-0_1_null_0,NEXUS_5,1.0,en].png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:b8678bfa52be0664119038250fa9b009f5bca7694c13bca346a87f78e1dd00a2 +size 10295 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.viewfolder.impl.file_ViewFileView_null_ViewFileView-Day-0_1_null_1,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.viewfolder.impl.file_ViewFileView_null_ViewFileView-Day-0_1_null_1,NEXUS_5,1.0,en].png new file mode 100644 index 0000000000..f5be6b5490 --- /dev/null +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.viewfolder.impl.file_ViewFileView_null_ViewFileView-Day-0_1_null_1,NEXUS_5,1.0,en].png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:52ea44b4be9b858f64a886ded5427f8ef5c2149914e348166a2fbb333ffc41f8 +size 70418 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.viewfolder.impl.file_ViewFileView_null_ViewFileView-Night-0_2_null_0,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.viewfolder.impl.file_ViewFileView_null_ViewFileView-Night-0_2_null_0,NEXUS_5,1.0,en].png new file mode 100644 index 0000000000..f632e7c8c6 --- /dev/null +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.viewfolder.impl.file_ViewFileView_null_ViewFileView-Night-0_2_null_0,NEXUS_5,1.0,en].png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:c9b2398f048d9f544a717a7a5f7e6c16f0584403748e76914f4aa2ab69baa13b +size 9799 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.viewfolder.impl.file_ViewFileView_null_ViewFileView-Night-0_2_null_1,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.viewfolder.impl.file_ViewFileView_null_ViewFileView-Night-0_2_null_1,NEXUS_5,1.0,en].png new file mode 100644 index 0000000000..339e893381 --- /dev/null +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.viewfolder.impl.file_ViewFileView_null_ViewFileView-Night-0_2_null_1,NEXUS_5,1.0,en].png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:304c5c94e3b408c744f0b6c86d35ac781f368e6e0d5742d5b2ff36ac1682538a +size 67297 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.viewfolder.impl.folder_ViewFolderView_null_ViewFolderView-Day-1_2_null_0,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.viewfolder.impl.folder_ViewFolderView_null_ViewFolderView-Day-1_2_null_0,NEXUS_5,1.0,en].png new file mode 100644 index 0000000000..4e8dd75a9c --- /dev/null +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.viewfolder.impl.folder_ViewFolderView_null_ViewFolderView-Day-1_2_null_0,NEXUS_5,1.0,en].png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:ea29d83cb5184a5490de6b3d4a15a41db7c7cb8431b6dfd0eff873b991a3a9c2 +size 9245 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.viewfolder.impl.folder_ViewFolderView_null_ViewFolderView-Day-1_2_null_1,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.viewfolder.impl.folder_ViewFolderView_null_ViewFolderView-Day-1_2_null_1,NEXUS_5,1.0,en].png new file mode 100644 index 0000000000..a01c1f03af --- /dev/null +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.viewfolder.impl.folder_ViewFolderView_null_ViewFolderView-Day-1_2_null_1,NEXUS_5,1.0,en].png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:843c33c966df9a1178fea5f319c3d5c313ab4d8f45166fda644650f9aa3c8550 +size 10949 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.viewfolder.impl.folder_ViewFolderView_null_ViewFolderView-Night-1_3_null_0,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.viewfolder.impl.folder_ViewFolderView_null_ViewFolderView-Night-1_3_null_0,NEXUS_5,1.0,en].png new file mode 100644 index 0000000000..7abe67d050 --- /dev/null +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.viewfolder.impl.folder_ViewFolderView_null_ViewFolderView-Night-1_3_null_0,NEXUS_5,1.0,en].png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:27f7fbaba83b994a0baf3b002c95bc27aa6d6097b0af1cb566ccece35cc5f4c5 +size 9010 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.viewfolder.impl.folder_ViewFolderView_null_ViewFolderView-Night-1_3_null_1,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.viewfolder.impl.folder_ViewFolderView_null_ViewFolderView-Night-1_3_null_1,NEXUS_5,1.0,en].png new file mode 100644 index 0000000000..ec410fbb75 --- /dev/null +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.viewfolder.impl.folder_ViewFolderView_null_ViewFolderView-Night-1_3_null_1,NEXUS_5,1.0,en].png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:aa145b94e5cf20f651d965cfa932163759e3c0dd7f3b8589e53d43b25ff94102 +size 10566 From a98749bad7ecef7fcb610d932c803e740c4db352 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 24 Jan 2024 22:25:02 +0000 Subject: [PATCH 083/127] Update gradle/gradle-build-action action to v2.12.0 --- .github/workflows/build.yml | 2 +- .github/workflows/nightlyReports.yml | 2 +- .github/workflows/quality.yml | 2 +- .github/workflows/recordScreenshots.yml | 2 +- .github/workflows/release.yml | 2 +- .github/workflows/sonar.yml | 2 +- .github/workflows/tests.yml | 2 +- 7 files changed, 7 insertions(+), 7 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index dd138f8e67..09ba964a0c 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -38,7 +38,7 @@ jobs: distribution: 'temurin' # See 'Supported distributions' for available options java-version: '17' - name: Configure gradle - uses: gradle/gradle-build-action@v2.11.1 + uses: gradle/gradle-build-action@v2.12.0 with: cache-read-only: ${{ github.ref != 'refs/heads/develop' }} - name: Assemble debug APK diff --git a/.github/workflows/nightlyReports.yml b/.github/workflows/nightlyReports.yml index 7861425e28..9b5a01a14e 100644 --- a/.github/workflows/nightlyReports.yml +++ b/.github/workflows/nightlyReports.yml @@ -62,7 +62,7 @@ jobs: distribution: 'temurin' # See 'Supported distributions' for available options java-version: '17' - name: Configure gradle - uses: gradle/gradle-build-action@v2.11.1 + uses: gradle/gradle-build-action@v2.12.0 with: cache-read-only: ${{ github.ref != 'refs/heads/develop' }} - name: Dependency analysis diff --git a/.github/workflows/quality.yml b/.github/workflows/quality.yml index 3a36faf6d3..e1eb132ee7 100644 --- a/.github/workflows/quality.yml +++ b/.github/workflows/quality.yml @@ -40,7 +40,7 @@ jobs: distribution: 'temurin' # See 'Supported distributions' for available options java-version: '17' - name: Configure gradle - uses: gradle/gradle-build-action@v2.11.1 + uses: gradle/gradle-build-action@v2.12.0 with: cache-read-only: ${{ github.ref != 'refs/heads/develop' }} - name: Run code quality check suite diff --git a/.github/workflows/recordScreenshots.yml b/.github/workflows/recordScreenshots.yml index 11cd8e3352..5024bea3af 100644 --- a/.github/workflows/recordScreenshots.yml +++ b/.github/workflows/recordScreenshots.yml @@ -39,7 +39,7 @@ jobs: java-version: '17' # Add gradle cache, this should speed up the process - name: Configure gradle - uses: gradle/gradle-build-action@v2.11.1 + uses: gradle/gradle-build-action@v2.12.0 with: cache-read-only: ${{ github.ref != 'refs/heads/develop' }} - name: Record screenshots diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 97e3634a6a..bf672d8315 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -25,7 +25,7 @@ jobs: distribution: 'temurin' # See 'Supported distributions' for available options java-version: '17' - name: Configure gradle - uses: gradle/gradle-build-action@v2.11.1 + uses: gradle/gradle-build-action@v2.12.0 - name: Create app bundle env: ELEMENT_ANDROID_MAPTILER_API_KEY: ${{ secrets.MAPTILER_KEY }} diff --git a/.github/workflows/sonar.yml b/.github/workflows/sonar.yml index 705d937bce..130eb573d4 100644 --- a/.github/workflows/sonar.yml +++ b/.github/workflows/sonar.yml @@ -32,7 +32,7 @@ jobs: distribution: 'temurin' # See 'Supported distributions' for available options java-version: '17' - name: Configure gradle - uses: gradle/gradle-build-action@v2.11.1 + uses: gradle/gradle-build-action@v2.12.0 with: cache-read-only: ${{ github.ref != 'refs/heads/develop' }} - name: 🔊 Publish results to Sonar diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index bf0379f6b6..3cbda49612 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -44,7 +44,7 @@ jobs: distribution: 'temurin' # See 'Supported distributions' for available options java-version: '17' - name: Configure gradle - uses: gradle/gradle-build-action@v2.11.1 + uses: gradle/gradle-build-action@v2.12.0 with: cache-read-only: ${{ github.ref != 'refs/heads/develop' }} From a6932c6c645c41018cd9c3767e4630de76fbe21b Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Thu, 25 Jan 2024 09:24:39 +0100 Subject: [PATCH 084/127] Fix test compilation issue. --- .../features/rageshake/impl/bugreport/FakeBugReporter.kt | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/features/rageshake/impl/src/test/kotlin/io/element/android/features/rageshake/impl/bugreport/FakeBugReporter.kt b/features/rageshake/impl/src/test/kotlin/io/element/android/features/rageshake/impl/bugreport/FakeBugReporter.kt index 2cd9e61398..0a67a79f57 100644 --- a/features/rageshake/impl/src/test/kotlin/io/element/android/features/rageshake/impl/bugreport/FakeBugReporter.kt +++ b/features/rageshake/impl/src/test/kotlin/io/element/android/features/rageshake/impl/bugreport/FakeBugReporter.kt @@ -63,6 +63,10 @@ class FakeBugReporter(val mode: FakeBugReporterMode = FakeBugReporterMode.Succes override fun setCurrentTracingFilter(tracingFilter: String) { // No op } + + override fun saveLogCat() { + // No op + } } enum class FakeBugReporterMode { From a5eff37335b06e12de6cdefc3c0a39009d291265 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Thu, 25 Jan 2024 09:26:04 +0100 Subject: [PATCH 085/127] changelog. --- changelog.d/2276.misc | 1 + 1 file changed, 1 insertion(+) create mode 100644 changelog.d/2276.misc diff --git a/changelog.d/2276.misc b/changelog.d/2276.misc new file mode 100644 index 0000000000..47efbb63e9 --- /dev/null +++ b/changelog.d/2276.misc @@ -0,0 +1 @@ +Add in app logs viewer to the "Report a problem" screen. From bed9fcfae18bfbb1cde87213a14795c90bfd139c Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Thu, 25 Jan 2024 09:49:36 +0100 Subject: [PATCH 086/127] Add some Divider around the "View logs" item. --- .../android/features/rageshake/impl/bugreport/BugReportView.kt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/features/rageshake/impl/src/main/kotlin/io/element/android/features/rageshake/impl/bugreport/BugReportView.kt b/features/rageshake/impl/src/main/kotlin/io/element/android/features/rageshake/impl/bugreport/BugReportView.kt index 80f7d931e0..e10e9250e3 100644 --- a/features/rageshake/impl/src/main/kotlin/io/element/android/features/rageshake/impl/bugreport/BugReportView.kt +++ b/features/rageshake/impl/src/main/kotlin/io/element/android/features/rageshake/impl/bugreport/BugReportView.kt @@ -40,6 +40,7 @@ import io.element.android.features.rageshake.impl.R import io.element.android.libraries.architecture.AsyncAction import io.element.android.libraries.designsystem.components.async.AsyncActionView import io.element.android.libraries.designsystem.components.form.textFieldState +import io.element.android.libraries.designsystem.components.preferences.PreferenceDivider import io.element.android.libraries.designsystem.components.preferences.PreferencePage import io.element.android.libraries.designsystem.components.preferences.PreferenceRow import io.element.android.libraries.designsystem.components.preferences.PreferenceSwitch @@ -99,11 +100,13 @@ fun BugReportView( ) } Spacer(modifier = Modifier.height(16.dp)) + PreferenceDivider() PreferenceText( title = stringResource(id = R.string.screen_bug_report_view_logs), enabled = isFormEnabled, onClick = onViewLogs, ) + PreferenceDivider() PreferenceSwitch( isChecked = state.formState.sendLogs, onCheckedChange = { eventSink(BugReportEvents.SetSendLog(it)) }, From 4601e2acd33c67bd60920cb4b9351946941dba8d Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Thu, 25 Jan 2024 10:19:56 +0100 Subject: [PATCH 087/127] Change type of `ViewFileState.lines` from `ImmutableList` to `AsyncData>` to properly handle loading and error states. --- features/viewfolder/impl/build.gradle.kts | 1 + .../viewfolder/impl/file/FileContentReader.kt | 11 +--- .../viewfolder/impl/file/ViewFilePresenter.kt | 11 ++-- .../viewfolder/impl/file/ViewFileState.kt | 4 +- .../impl/file/ViewFileStateProvider.kt | 33 ++++++---- .../viewfolder/impl/file/ViewFileView.kt | 65 ++++++++++++------- .../test/file/FakeFileContentReader.kt | 6 +- .../test/file/ViewFilePresenterTest.kt | 31 +++++++-- 8 files changed, 102 insertions(+), 60 deletions(-) diff --git a/features/viewfolder/impl/build.gradle.kts b/features/viewfolder/impl/build.gradle.kts index d3e838e1f5..67c818f185 100644 --- a/features/viewfolder/impl/build.gradle.kts +++ b/features/viewfolder/impl/build.gradle.kts @@ -47,4 +47,5 @@ dependencies { testImplementation(libs.test.truth) testImplementation(libs.test.turbine) testImplementation(projects.tests.testutils) + testImplementation(projects.libraries.matrix.test) } diff --git a/features/viewfolder/impl/src/main/kotlin/io/element/android/features/viewfolder/impl/file/FileContentReader.kt b/features/viewfolder/impl/src/main/kotlin/io/element/android/features/viewfolder/impl/file/FileContentReader.kt index 877f841fcb..bc723f70cb 100644 --- a/features/viewfolder/impl/src/main/kotlin/io/element/android/features/viewfolder/impl/file/FileContentReader.kt +++ b/features/viewfolder/impl/src/main/kotlin/io/element/android/features/viewfolder/impl/file/FileContentReader.kt @@ -24,21 +24,16 @@ import java.io.File import javax.inject.Inject interface FileContentReader { - suspend fun getLines(path: String): List + suspend fun getLines(path: String): Result> } @ContributesBinding(AppScope::class) class DefaultFileContentReader @Inject constructor( private val dispatchers: CoroutineDispatchers, ) : FileContentReader { - override suspend fun getLines(path: String): List = withContext(dispatchers.io) { - try { + override suspend fun getLines(path: String): Result> = withContext(dispatchers.io) { + runCatching { File(path).readLines() - } catch (exception: Exception) { - buildList { - add("Error reading file $path") - add(exception.toString()) - } } } } diff --git a/features/viewfolder/impl/src/main/kotlin/io/element/android/features/viewfolder/impl/file/ViewFilePresenter.kt b/features/viewfolder/impl/src/main/kotlin/io/element/android/features/viewfolder/impl/file/ViewFilePresenter.kt index 1a1e5ba3dd..91cc59ec05 100644 --- a/features/viewfolder/impl/src/main/kotlin/io/element/android/features/viewfolder/impl/file/ViewFilePresenter.kt +++ b/features/viewfolder/impl/src/main/kotlin/io/element/android/features/viewfolder/impl/file/ViewFilePresenter.kt @@ -26,8 +26,8 @@ import androidx.compose.runtime.setValue import dagger.assisted.Assisted import dagger.assisted.AssistedFactory import dagger.assisted.AssistedInject +import io.element.android.libraries.architecture.AsyncData import io.element.android.libraries.architecture.Presenter -import kotlinx.collections.immutable.toImmutableList import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.launch @@ -57,13 +57,16 @@ class ViewFilePresenter @AssistedInject constructor( } } - var lines by remember { mutableStateOf(emptyList()) } + var lines: AsyncData> by remember { mutableStateOf(AsyncData.Loading()) } LaunchedEffect(Unit) { - lines = fileContentReader.getLines(path) + lines = fileContentReader.getLines(path).fold( + onSuccess = { AsyncData.Success(it) }, + onFailure = { AsyncData.Failure(it) } + ) } return ViewFileState( name = name, - lines = lines.toImmutableList(), + lines = lines, eventSink = ::handleEvent, ) } diff --git a/features/viewfolder/impl/src/main/kotlin/io/element/android/features/viewfolder/impl/file/ViewFileState.kt b/features/viewfolder/impl/src/main/kotlin/io/element/android/features/viewfolder/impl/file/ViewFileState.kt index 9971c4b7d0..9fb531c478 100644 --- a/features/viewfolder/impl/src/main/kotlin/io/element/android/features/viewfolder/impl/file/ViewFileState.kt +++ b/features/viewfolder/impl/src/main/kotlin/io/element/android/features/viewfolder/impl/file/ViewFileState.kt @@ -16,10 +16,10 @@ package io.element.android.features.viewfolder.impl.file -import kotlinx.collections.immutable.ImmutableList +import io.element.android.libraries.architecture.AsyncData data class ViewFileState( val name: String, - val lines: ImmutableList, + val lines: AsyncData>, val eventSink: (ViewFileEvents) -> Unit, ) diff --git a/features/viewfolder/impl/src/main/kotlin/io/element/android/features/viewfolder/impl/file/ViewFileStateProvider.kt b/features/viewfolder/impl/src/main/kotlin/io/element/android/features/viewfolder/impl/file/ViewFileStateProvider.kt index 9687e82405..f0612c0714 100644 --- a/features/viewfolder/impl/src/main/kotlin/io/element/android/features/viewfolder/impl/file/ViewFileStateProvider.kt +++ b/features/viewfolder/impl/src/main/kotlin/io/element/android/features/viewfolder/impl/file/ViewFileStateProvider.kt @@ -17,24 +17,29 @@ package io.element.android.features.viewfolder.impl.file import androidx.compose.ui.tooling.preview.PreviewParameterProvider -import kotlinx.collections.immutable.toImmutableList +import io.element.android.libraries.architecture.AsyncData open class ViewFileStateProvider : PreviewParameterProvider { override val values: Sequence get() = sequenceOf( aViewFileState(), + aViewFileState(lines = AsyncData.Loading()), + aViewFileState(lines = AsyncData.Failure(Exception("A failure"))), + aViewFileState(lines = AsyncData.Success(emptyList())), aViewFileState( - lines = listOf( - "Line 1", - "Line 2", - "Line 3 lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor" + - " incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam,", - "01-23 13:14:50.740 25818 25818 V verbose", - "01-23 13:14:50.740 25818 25818 D debug", - "01-23 13:14:50.740 25818 25818 I info", - "01-23 13:14:50.740 25818 25818 W warning", - "01-23 13:14:50.740 25818 25818 E error", - "01-23 13:14:50.740 25818 25818 A assertion", + lines = AsyncData.Success( + listOf( + "Line 1", + "Line 2", + "Line 3 lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor" + + " incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam,", + "01-23 13:14:50.740 25818 25818 V verbose", + "01-23 13:14:50.740 25818 25818 D debug", + "01-23 13:14:50.740 25818 25818 I info", + "01-23 13:14:50.740 25818 25818 W warning", + "01-23 13:14:50.740 25818 25818 E error", + "01-23 13:14:50.740 25818 25818 A assertion", + ) ) ) ) @@ -42,9 +47,9 @@ open class ViewFileStateProvider : PreviewParameterProvider { fun aViewFileState( name: String = "aName", - lines: List = emptyList(), + lines: AsyncData> = AsyncData.Uninitialized, ) = ViewFileState( name = name, - lines = lines.toImmutableList(), + lines = lines, eventSink = {}, ) diff --git a/features/viewfolder/impl/src/main/kotlin/io/element/android/features/viewfolder/impl/file/ViewFileView.kt b/features/viewfolder/impl/src/main/kotlin/io/element/android/features/viewfolder/impl/file/ViewFileView.kt index 265f6892ad..f98c13200c 100644 --- a/features/viewfolder/impl/src/main/kotlin/io/element/android/features/viewfolder/impl/file/ViewFileView.kt +++ b/features/viewfolder/impl/src/main/kotlin/io/element/android/features/viewfolder/impl/file/ViewFileView.kt @@ -41,6 +41,9 @@ import androidx.compose.ui.tooling.preview.PreviewParameter import androidx.compose.ui.unit.dp import io.element.android.compound.theme.ElementTheme import io.element.android.libraries.androidutils.system.copyToClipboard +import io.element.android.libraries.architecture.AsyncData +import io.element.android.libraries.designsystem.components.async.AsyncFailure +import io.element.android.libraries.designsystem.components.async.AsyncLoading import io.element.android.libraries.designsystem.components.button.BackButton import io.element.android.libraries.designsystem.icons.CompoundDrawables import io.element.android.libraries.designsystem.preview.ElementPreview @@ -103,35 +106,51 @@ fun ViewFileView( .padding(padding) .consumeWindowInsets(padding) ) { - LazyColumn( - modifier = Modifier.weight(1f) - ) { - if (state.lines.isEmpty()) { - item { - Spacer(Modifier.size(80.dp)) - Text( - text = "Empty file", - textAlign = TextAlign.Center, - color = MaterialTheme.colorScheme.tertiary, - modifier = Modifier.fillMaxWidth() - ) - } - } else { - itemsIndexed( - items = state.lines, - ) { index, line -> - LineRow( - lineNumber = index + 1, - line = line, - ) - } - } + when (state.lines) { + AsyncData.Uninitialized, + is AsyncData.Loading -> AsyncLoading() + is AsyncData.Success -> FileContent( + modifier = modifier.weight(1f), + lines = state.lines.data, + ) + is AsyncData.Failure -> AsyncFailure(throwable = state.lines.error, onRetry = null) } } } ) } +@Composable +private fun FileContent( + lines: List, + modifier: Modifier = Modifier, +) { + LazyColumn( + modifier = modifier + ) { + if (lines.isEmpty()) { + item { + Spacer(Modifier.size(80.dp)) + Text( + text = "Empty file", + textAlign = TextAlign.Center, + color = MaterialTheme.colorScheme.tertiary, + modifier = Modifier.fillMaxWidth() + ) + } + } else { + itemsIndexed( + items = lines, + ) { index, line -> + LineRow( + lineNumber = index + 1, + line = line, + ) + } + } + } +} + @Composable private fun LineRow( lineNumber: Int, diff --git a/features/viewfolder/impl/src/test/kotlin/io/element/android/features/viewfolder/test/file/FakeFileContentReader.kt b/features/viewfolder/impl/src/test/kotlin/io/element/android/features/viewfolder/test/file/FakeFileContentReader.kt index 9a8d51e329..5d8b658587 100644 --- a/features/viewfolder/impl/src/test/kotlin/io/element/android/features/viewfolder/test/file/FakeFileContentReader.kt +++ b/features/viewfolder/impl/src/test/kotlin/io/element/android/features/viewfolder/test/file/FakeFileContentReader.kt @@ -19,11 +19,11 @@ package io.element.android.features.viewfolder.test.file import io.element.android.features.viewfolder.impl.file.FileContentReader class FakeFileContentReader : FileContentReader { - private var result: List = emptyList() + private var result: Result> = Result.success(emptyList()) - fun givenResult(result: List) { + fun givenResult(result: Result>) { this.result = result } - override suspend fun getLines(path: String): List = result + override suspend fun getLines(path: String): Result> = result } diff --git a/features/viewfolder/impl/src/test/kotlin/io/element/android/features/viewfolder/test/file/ViewFilePresenterTest.kt b/features/viewfolder/impl/src/test/kotlin/io/element/android/features/viewfolder/test/file/ViewFilePresenterTest.kt index 868a812eb2..3b593410b2 100644 --- a/features/viewfolder/impl/src/test/kotlin/io/element/android/features/viewfolder/test/file/ViewFilePresenterTest.kt +++ b/features/viewfolder/impl/src/test/kotlin/io/element/android/features/viewfolder/test/file/ViewFilePresenterTest.kt @@ -25,6 +25,8 @@ import io.element.android.features.viewfolder.impl.file.FileSave import io.element.android.features.viewfolder.impl.file.FileShare import io.element.android.features.viewfolder.impl.file.ViewFileEvents import io.element.android.features.viewfolder.impl.file.ViewFilePresenter +import io.element.android.libraries.architecture.AsyncData +import io.element.android.libraries.matrix.test.AN_EXCEPTION import io.element.android.tests.testutils.WarmUpRule import kotlinx.coroutines.test.runTest import org.junit.Rule @@ -37,24 +39,26 @@ class ViewFilePresenterTest { @Test fun `present - initial state`() = runTest { val fileContentReader = FakeFileContentReader().apply { - givenResult(listOf("aLine")) + givenResult(Result.success(listOf("aLine"))) } val presenter = createPresenter(fileContentReader = fileContentReader) moleculeFlow(RecompositionMode.Immediate) { presenter.present() }.test { - skipItems(1) val initialState = awaitItem() assertThat(initialState.name).isEqualTo("aName") - assertThat(initialState.lines.size).isEqualTo(1) - assertThat(initialState.lines.first()).isEqualTo("aLine") + assertThat(initialState.lines).isInstanceOf(AsyncData.Loading::class.java) + val loadedState = awaitItem() + val lines = (loadedState.lines as AsyncData.Success).data + assertThat(lines.size).isEqualTo(1) + assertThat(lines.first()).isEqualTo("aLine") } } @Test fun `present - share should not have any side effect`() = runTest { val fileContentReader = FakeFileContentReader().apply { - givenResult(listOf("aLine")) + givenResult(Result.success(listOf("aLine"))) } val fileShare = FakeFileShare() val fileSave = FakeFileSave() @@ -70,10 +74,25 @@ class ViewFilePresenterTest { } } + @Test + fun `present - with error loading file`() = runTest { + val fileContentReader = FakeFileContentReader().apply { + givenResult(Result.failure(AN_EXCEPTION)) + } + val presenter = createPresenter(fileContentReader = fileContentReader) + moleculeFlow(RecompositionMode.Immediate) { + presenter.present() + }.test { + skipItems(1) + val errorState = awaitItem() + assertThat(errorState.lines).isInstanceOf(AsyncData.Failure::class.java) + } + } + @Test fun `present - save should not have any side effect`() = runTest { val fileContentReader = FakeFileContentReader().apply { - givenResult(listOf("aLine")) + givenResult(Result.success(listOf("aLine"))) } val fileShare = FakeFileShare() val fileSave = FakeFileSave() From 676b8edcaceccb599655e9708a2d404287014ce5 Mon Sep 17 00:00:00 2001 From: ElementBot Date: Thu, 25 Jan 2024 09:36:39 +0000 Subject: [PATCH 088/127] Update screenshots --- ...View_null_BugReportView-Day-0_1_null_0,NEXUS_5,1.0,en].png | 4 ++-- ...View_null_BugReportView-Day-0_1_null_1,NEXUS_5,1.0,en].png | 4 ++-- ...View_null_BugReportView-Day-0_1_null_2,NEXUS_5,1.0,en].png | 4 ++-- ...View_null_BugReportView-Day-0_1_null_3,NEXUS_5,1.0,en].png | 4 ++-- ...ew_null_BugReportView-Night-0_2_null_0,NEXUS_5,1.0,en].png | 4 ++-- ...ew_null_BugReportView-Night-0_2_null_1,NEXUS_5,1.0,en].png | 4 ++-- ...ew_null_BugReportView-Night-0_2_null_2,NEXUS_5,1.0,en].png | 4 ++-- ...ew_null_BugReportView-Night-0_2_null_3,NEXUS_5,1.0,en].png | 4 ++-- ...eView_null_ViewFileView-Day-0_1_null_0,NEXUS_5,1.0,en].png | 4 ++-- ...eView_null_ViewFileView-Day-0_1_null_1,NEXUS_5,1.0,en].png | 4 ++-- ...eView_null_ViewFileView-Day-0_1_null_2,NEXUS_5,1.0,en].png | 3 +++ ...eView_null_ViewFileView-Day-0_1_null_3,NEXUS_5,1.0,en].png | 3 +++ ...eView_null_ViewFileView-Day-0_1_null_4,NEXUS_5,1.0,en].png | 3 +++ ...iew_null_ViewFileView-Night-0_2_null_0,NEXUS_5,1.0,en].png | 4 ++-- ...iew_null_ViewFileView-Night-0_2_null_1,NEXUS_5,1.0,en].png | 4 ++-- ...iew_null_ViewFileView-Night-0_2_null_2,NEXUS_5,1.0,en].png | 3 +++ ...iew_null_ViewFileView-Night-0_2_null_3,NEXUS_5,1.0,en].png | 3 +++ ...iew_null_ViewFileView-Night-0_2_null_4,NEXUS_5,1.0,en].png | 3 +++ 18 files changed, 42 insertions(+), 24 deletions(-) create mode 100644 tests/uitests/src/test/snapshots/images/ui_S_t[f.viewfolder.impl.file_ViewFileView_null_ViewFileView-Day-0_1_null_2,NEXUS_5,1.0,en].png create mode 100644 tests/uitests/src/test/snapshots/images/ui_S_t[f.viewfolder.impl.file_ViewFileView_null_ViewFileView-Day-0_1_null_3,NEXUS_5,1.0,en].png create mode 100644 tests/uitests/src/test/snapshots/images/ui_S_t[f.viewfolder.impl.file_ViewFileView_null_ViewFileView-Day-0_1_null_4,NEXUS_5,1.0,en].png create mode 100644 tests/uitests/src/test/snapshots/images/ui_S_t[f.viewfolder.impl.file_ViewFileView_null_ViewFileView-Night-0_2_null_2,NEXUS_5,1.0,en].png create mode 100644 tests/uitests/src/test/snapshots/images/ui_S_t[f.viewfolder.impl.file_ViewFileView_null_ViewFileView-Night-0_2_null_3,NEXUS_5,1.0,en].png create mode 100644 tests/uitests/src/test/snapshots/images/ui_S_t[f.viewfolder.impl.file_ViewFileView_null_ViewFileView-Night-0_2_null_4,NEXUS_5,1.0,en].png diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.rageshake.impl.bugreport_BugReportView_null_BugReportView-Day-0_1_null_0,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.rageshake.impl.bugreport_BugReportView_null_BugReportView-Day-0_1_null_0,NEXUS_5,1.0,en].png index 377c44d62b..1c8b28b5ad 100644 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.rageshake.impl.bugreport_BugReportView_null_BugReportView-Day-0_1_null_0,NEXUS_5,1.0,en].png +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.rageshake.impl.bugreport_BugReportView_null_BugReportView-Day-0_1_null_0,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:510c3b614956dc4caafa9b803243e5f7a77e9ff41a50c28c854bf836dd17bfbb -size 72603 +oid sha256:b80e48cadbb6e76fc6675eb0a2c49d6495be6a8145d649ad90c2bce10e8695a6 +size 72701 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.rageshake.impl.bugreport_BugReportView_null_BugReportView-Day-0_1_null_1,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.rageshake.impl.bugreport_BugReportView_null_BugReportView-Day-0_1_null_1,NEXUS_5,1.0,en].png index b205c3f83f..d43f744d13 100644 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.rageshake.impl.bugreport_BugReportView_null_BugReportView-Day-0_1_null_1,NEXUS_5,1.0,en].png +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.rageshake.impl.bugreport_BugReportView_null_BugReportView-Day-0_1_null_1,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:d9b95973e3fb7cd82992e7a97a24baacd3cb84886f9d94173941ca9b2ac64d07 -size 146787 +oid sha256:52caeed04914fee9ee74c28427b3a51215eca02104f544dd53dc280c3c1c5f98 +size 145307 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.rageshake.impl.bugreport_BugReportView_null_BugReportView-Day-0_1_null_2,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.rageshake.impl.bugreport_BugReportView_null_BugReportView-Day-0_1_null_2,NEXUS_5,1.0,en].png index 11e2681985..db397c15a6 100644 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.rageshake.impl.bugreport_BugReportView_null_BugReportView-Day-0_1_null_2,NEXUS_5,1.0,en].png +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.rageshake.impl.bugreport_BugReportView_null_BugReportView-Day-0_1_null_2,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:ec0097e9379e6b757d7a2db0ce7b95a1bf6ca2387da4c281324764ddadc7b178 -size 63779 +oid sha256:350ae21a44e27292bb1ea44fbad0e9cea8dc695997482c9fa3ad6cafa6330a4c +size 63792 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.rageshake.impl.bugreport_BugReportView_null_BugReportView-Day-0_1_null_3,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.rageshake.impl.bugreport_BugReportView_null_BugReportView-Day-0_1_null_3,NEXUS_5,1.0,en].png index 377c44d62b..1c8b28b5ad 100644 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.rageshake.impl.bugreport_BugReportView_null_BugReportView-Day-0_1_null_3,NEXUS_5,1.0,en].png +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.rageshake.impl.bugreport_BugReportView_null_BugReportView-Day-0_1_null_3,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:510c3b614956dc4caafa9b803243e5f7a77e9ff41a50c28c854bf836dd17bfbb -size 72603 +oid sha256:b80e48cadbb6e76fc6675eb0a2c49d6495be6a8145d649ad90c2bce10e8695a6 +size 72701 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.rageshake.impl.bugreport_BugReportView_null_BugReportView-Night-0_2_null_0,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.rageshake.impl.bugreport_BugReportView_null_BugReportView-Night-0_2_null_0,NEXUS_5,1.0,en].png index 4956ae764e..6ae1a1f2ed 100644 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.rageshake.impl.bugreport_BugReportView_null_BugReportView-Night-0_2_null_0,NEXUS_5,1.0,en].png +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.rageshake.impl.bugreport_BugReportView_null_BugReportView-Night-0_2_null_0,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:b63d6e1221d56b8ad8e88757d7a20beafeeb31c3f908dc56a8a27e26aa752b57 -size 69478 +oid sha256:7696307abd3ca96ae3c036cbf3088c2be08b4e4aabb861b0c7472460ab795303 +size 69558 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.rageshake.impl.bugreport_BugReportView_null_BugReportView-Night-0_2_null_1,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.rageshake.impl.bugreport_BugReportView_null_BugReportView-Night-0_2_null_1,NEXUS_5,1.0,en].png index a7721efc92..542fc8d94c 100644 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.rageshake.impl.bugreport_BugReportView_null_BugReportView-Night-0_2_null_1,NEXUS_5,1.0,en].png +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.rageshake.impl.bugreport_BugReportView_null_BugReportView-Night-0_2_null_1,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:e529a5a5fc1fde9b37321bef36c1c2162a3f6a1a0509c042fc9fe8e515f88220 -size 142480 +oid sha256:f7409716efc9323aafb52eeb498330029753ad9ec319afa1027d22feb238e589 +size 141187 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.rageshake.impl.bugreport_BugReportView_null_BugReportView-Night-0_2_null_2,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.rageshake.impl.bugreport_BugReportView_null_BugReportView-Night-0_2_null_2,NEXUS_5,1.0,en].png index 5393e8581b..58120c675c 100644 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.rageshake.impl.bugreport_BugReportView_null_BugReportView-Night-0_2_null_2,NEXUS_5,1.0,en].png +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.rageshake.impl.bugreport_BugReportView_null_BugReportView-Night-0_2_null_2,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:4494a8a23762ca963a3d76969a407021fb3301030ecc5471af63d0d306d768fd -size 58207 +oid sha256:98368df14dcc182d759ac104189ebf43aff4e1a0445b0af1d6909a614cd2102b +size 58283 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.rageshake.impl.bugreport_BugReportView_null_BugReportView-Night-0_2_null_3,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.rageshake.impl.bugreport_BugReportView_null_BugReportView-Night-0_2_null_3,NEXUS_5,1.0,en].png index 4956ae764e..6ae1a1f2ed 100644 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.rageshake.impl.bugreport_BugReportView_null_BugReportView-Night-0_2_null_3,NEXUS_5,1.0,en].png +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.rageshake.impl.bugreport_BugReportView_null_BugReportView-Night-0_2_null_3,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:b63d6e1221d56b8ad8e88757d7a20beafeeb31c3f908dc56a8a27e26aa752b57 -size 69478 +oid sha256:7696307abd3ca96ae3c036cbf3088c2be08b4e4aabb861b0c7472460ab795303 +size 69558 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.viewfolder.impl.file_ViewFileView_null_ViewFileView-Day-0_1_null_0,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.viewfolder.impl.file_ViewFileView_null_ViewFileView-Day-0_1_null_0,NEXUS_5,1.0,en].png index 36edcb8b83..18e8edb58d 100644 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.viewfolder.impl.file_ViewFileView_null_ViewFileView-Day-0_1_null_0,NEXUS_5,1.0,en].png +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.viewfolder.impl.file_ViewFileView_null_ViewFileView-Day-0_1_null_0,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:b8678bfa52be0664119038250fa9b009f5bca7694c13bca346a87f78e1dd00a2 -size 10295 +oid sha256:2e396772e4b3effda7d9238de4f02dbce8c705be334239e4607dd80043764bce +size 10087 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.viewfolder.impl.file_ViewFileView_null_ViewFileView-Day-0_1_null_1,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.viewfolder.impl.file_ViewFileView_null_ViewFileView-Day-0_1_null_1,NEXUS_5,1.0,en].png index f5be6b5490..18e8edb58d 100644 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.viewfolder.impl.file_ViewFileView_null_ViewFileView-Day-0_1_null_1,NEXUS_5,1.0,en].png +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.viewfolder.impl.file_ViewFileView_null_ViewFileView-Day-0_1_null_1,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:52ea44b4be9b858f64a886ded5427f8ef5c2149914e348166a2fbb333ffc41f8 -size 70418 +oid sha256:2e396772e4b3effda7d9238de4f02dbce8c705be334239e4607dd80043764bce +size 10087 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.viewfolder.impl.file_ViewFileView_null_ViewFileView-Day-0_1_null_2,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.viewfolder.impl.file_ViewFileView_null_ViewFileView-Day-0_1_null_2,NEXUS_5,1.0,en].png new file mode 100644 index 0000000000..5ccd73a50a --- /dev/null +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.viewfolder.impl.file_ViewFileView_null_ViewFileView-Day-0_1_null_2,NEXUS_5,1.0,en].png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:3fdcaa9120195f28f41284d2a124df6739f4fb0967df6df24a38eb6cf43b6632 +size 10144 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.viewfolder.impl.file_ViewFileView_null_ViewFileView-Day-0_1_null_3,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.viewfolder.impl.file_ViewFileView_null_ViewFileView-Day-0_1_null_3,NEXUS_5,1.0,en].png new file mode 100644 index 0000000000..36edcb8b83 --- /dev/null +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.viewfolder.impl.file_ViewFileView_null_ViewFileView-Day-0_1_null_3,NEXUS_5,1.0,en].png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:b8678bfa52be0664119038250fa9b009f5bca7694c13bca346a87f78e1dd00a2 +size 10295 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.viewfolder.impl.file_ViewFileView_null_ViewFileView-Day-0_1_null_4,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.viewfolder.impl.file_ViewFileView_null_ViewFileView-Day-0_1_null_4,NEXUS_5,1.0,en].png new file mode 100644 index 0000000000..f5be6b5490 --- /dev/null +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.viewfolder.impl.file_ViewFileView_null_ViewFileView-Day-0_1_null_4,NEXUS_5,1.0,en].png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:52ea44b4be9b858f64a886ded5427f8ef5c2149914e348166a2fbb333ffc41f8 +size 70418 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.viewfolder.impl.file_ViewFileView_null_ViewFileView-Night-0_2_null_0,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.viewfolder.impl.file_ViewFileView_null_ViewFileView-Night-0_2_null_0,NEXUS_5,1.0,en].png index f632e7c8c6..1ded95367d 100644 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.viewfolder.impl.file_ViewFileView_null_ViewFileView-Night-0_2_null_0,NEXUS_5,1.0,en].png +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.viewfolder.impl.file_ViewFileView_null_ViewFileView-Night-0_2_null_0,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:c9b2398f048d9f544a717a7a5f7e6c16f0584403748e76914f4aa2ab69baa13b -size 9799 +oid sha256:3305677d678c28717a83e745b6c1bc71a2636ad65e09c5efc435c09cc1465dfc +size 9577 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.viewfolder.impl.file_ViewFileView_null_ViewFileView-Night-0_2_null_1,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.viewfolder.impl.file_ViewFileView_null_ViewFileView-Night-0_2_null_1,NEXUS_5,1.0,en].png index 339e893381..1ded95367d 100644 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.viewfolder.impl.file_ViewFileView_null_ViewFileView-Night-0_2_null_1,NEXUS_5,1.0,en].png +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.viewfolder.impl.file_ViewFileView_null_ViewFileView-Night-0_2_null_1,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:304c5c94e3b408c744f0b6c86d35ac781f368e6e0d5742d5b2ff36ac1682538a -size 67297 +oid sha256:3305677d678c28717a83e745b6c1bc71a2636ad65e09c5efc435c09cc1465dfc +size 9577 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.viewfolder.impl.file_ViewFileView_null_ViewFileView-Night-0_2_null_2,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.viewfolder.impl.file_ViewFileView_null_ViewFileView-Night-0_2_null_2,NEXUS_5,1.0,en].png new file mode 100644 index 0000000000..cfb85f1f94 --- /dev/null +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.viewfolder.impl.file_ViewFileView_null_ViewFileView-Night-0_2_null_2,NEXUS_5,1.0,en].png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:81e02f3d58a5cea85e9f7f63cab787f3d340fc4ff36ecf4ac5131d4d6d7e9f04 +size 9604 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.viewfolder.impl.file_ViewFileView_null_ViewFileView-Night-0_2_null_3,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.viewfolder.impl.file_ViewFileView_null_ViewFileView-Night-0_2_null_3,NEXUS_5,1.0,en].png new file mode 100644 index 0000000000..f632e7c8c6 --- /dev/null +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.viewfolder.impl.file_ViewFileView_null_ViewFileView-Night-0_2_null_3,NEXUS_5,1.0,en].png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:c9b2398f048d9f544a717a7a5f7e6c16f0584403748e76914f4aa2ab69baa13b +size 9799 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.viewfolder.impl.file_ViewFileView_null_ViewFileView-Night-0_2_null_4,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.viewfolder.impl.file_ViewFileView_null_ViewFileView-Night-0_2_null_4,NEXUS_5,1.0,en].png new file mode 100644 index 0000000000..339e893381 --- /dev/null +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.viewfolder.impl.file_ViewFileView_null_ViewFileView-Night-0_2_null_4,NEXUS_5,1.0,en].png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:304c5c94e3b408c744f0b6c86d35ac781f368e6e0d5742d5b2ff36ac1682538a +size 67297 From 4eb10a24220931dedfa55c6739de9de017d0189e Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Thu, 25 Jan 2024 11:10:01 +0100 Subject: [PATCH 089/127] Fix Compose issues. --- .../android/features/viewfolder/impl/file/ViewFileView.kt | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/features/viewfolder/impl/src/main/kotlin/io/element/android/features/viewfolder/impl/file/ViewFileView.kt b/features/viewfolder/impl/src/main/kotlin/io/element/android/features/viewfolder/impl/file/ViewFileView.kt index f98c13200c..f58f5399d7 100644 --- a/features/viewfolder/impl/src/main/kotlin/io/element/android/features/viewfolder/impl/file/ViewFileView.kt +++ b/features/viewfolder/impl/src/main/kotlin/io/element/android/features/viewfolder/impl/file/ViewFileView.kt @@ -55,6 +55,8 @@ import io.element.android.libraries.designsystem.theme.components.Scaffold import io.element.android.libraries.designsystem.theme.components.Text import io.element.android.libraries.designsystem.theme.components.TopAppBar import io.element.android.libraries.ui.strings.CommonStrings +import kotlinx.collections.immutable.ImmutableList +import kotlinx.collections.immutable.toImmutableList @OptIn(ExperimentalMaterial3Api::class) @Composable @@ -110,8 +112,8 @@ fun ViewFileView( AsyncData.Uninitialized, is AsyncData.Loading -> AsyncLoading() is AsyncData.Success -> FileContent( - modifier = modifier.weight(1f), - lines = state.lines.data, + modifier = Modifier.weight(1f), + lines = state.lines.data.toImmutableList(), ) is AsyncData.Failure -> AsyncFailure(throwable = state.lines.error, onRetry = null) } @@ -122,7 +124,7 @@ fun ViewFileView( @Composable private fun FileContent( - lines: List, + lines: ImmutableList, modifier: Modifier = Modifier, ) { LazyColumn( From 3098d869a807b0fafac746424e253c58ba053063 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Thu, 25 Jan 2024 12:25:42 +0100 Subject: [PATCH 090/127] Log the flavor --- app/src/main/kotlin/io/element/android/x/info/Logs.kt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/app/src/main/kotlin/io/element/android/x/info/Logs.kt b/app/src/main/kotlin/io/element/android/x/info/Logs.kt index 9e96f48e2d..55a1a85b91 100644 --- a/app/src/main/kotlin/io/element/android/x/info/Logs.kt +++ b/app/src/main/kotlin/io/element/android/x/info/Logs.kt @@ -29,6 +29,8 @@ fun logApplicationInfo() { append(BuildConfig.VERSION_CODE) append(") - ") append(BuildConfig.BUILD_TYPE) + append(" / ") + append(BuildConfig.FLAVOR) } // TODO Get SDK version somehow val sdkVersion = "SDK VERSION (TODO)" From cccfdfbcc7fe47aae0d38cacc2be595cc6a65509 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Thu, 25 Jan 2024 14:16:21 +0100 Subject: [PATCH 091/127] Restore branch and git sha, to use it in logs and in rageshakes. Remove quite useless `gitRevisionDate`. --- app/build.gradle.kts | 5 +++ .../io/element/android/x/di/AppModule.kt | 8 +--- .../kotlin/io/element/android/x/info/Logs.kt | 1 + .../impl/reporter/DefaultBugReporter.kt | 2 + .../android/libraries/core/meta/BuildMeta.kt | 1 - .../libraries/matrix/test/core/BuildMeta.kt | 2 - plugins/src/main/kotlin/extension/Utils.kt | 40 +++++++++++++++++++ .../android/samples/minimal/Singleton.kt | 8 +--- 8 files changed, 52 insertions(+), 15 deletions(-) create mode 100644 plugins/src/main/kotlin/extension/Utils.kt diff --git a/app/build.gradle.kts b/app/build.gradle.kts index e977af4c86..aad1c4eff6 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -20,6 +20,8 @@ import com.android.build.api.variant.FilterConfiguration.FilterType.ABI import extension.allFeaturesImpl import extension.allLibrariesImpl import extension.allServicesImpl +import extension.gitBranchName +import extension.gitRevision import extension.koverDependencies import extension.setupKover import org.jetbrains.kotlin.cli.common.toBooleanLenient @@ -54,6 +56,9 @@ android { abiFilters += listOf("armeabi-v7a", "x86", "arm64-v8a", "x86_64") } + buildConfigField("String", "GIT_REVISION", "\"${gitRevision()}\"") + buildConfigField("String", "GIT_BRANCH_NAME", "\"${gitBranchName()}\"") + // Ref: https://developer.android.com/studio/build/configure-apk-splits.html#configure-abi-split splits { // Configures multiple APKs based on ABI. diff --git a/app/src/main/kotlin/io/element/android/x/di/AppModule.kt b/app/src/main/kotlin/io/element/android/x/di/AppModule.kt index bf4880b372..47a2c373ad 100644 --- a/app/src/main/kotlin/io/element/android/x/di/AppModule.kt +++ b/app/src/main/kotlin/io/element/android/x/di/AppModule.kt @@ -85,12 +85,8 @@ object AppModule { lowPrivacyLoggingEnabled = false, versionName = BuildConfig.VERSION_NAME, versionCode = BuildConfig.VERSION_CODE, - // BuildConfig.GIT_REVISION, - gitRevision = "TODO", - // BuildConfig.GIT_REVISION_DATE, - gitRevisionDate = "TODO", - // BuildConfig.GIT_BRANCH_NAME, - gitBranchName = "TODO", + gitRevision = BuildConfig.GIT_REVISION, + gitBranchName = BuildConfig.GIT_BRANCH_NAME, flavorDescription = BuildConfig.FLAVOR_DESCRIPTION, flavorShortDescription = BuildConfig.SHORT_FLAVOR_DESCRIPTION, ) diff --git a/app/src/main/kotlin/io/element/android/x/info/Logs.kt b/app/src/main/kotlin/io/element/android/x/info/Logs.kt index 55a1a85b91..3cabc937a1 100644 --- a/app/src/main/kotlin/io/element/android/x/info/Logs.kt +++ b/app/src/main/kotlin/io/element/android/x/info/Logs.kt @@ -39,6 +39,7 @@ fun logApplicationInfo() { Timber.d("----------------------------------------------------------------") Timber.d("----------------------------------------------------------------") Timber.d(" Application version: $appVersion") + Timber.d(" Git SHA: ${BuildConfig.GIT_REVISION}") Timber.d(" SDK version: $sdkVersion") Timber.d(" Local time: $date") Timber.d("----------------------------------------------------------------") diff --git a/features/rageshake/impl/src/main/kotlin/io/element/android/features/rageshake/impl/reporter/DefaultBugReporter.kt b/features/rageshake/impl/src/main/kotlin/io/element/android/features/rageshake/impl/reporter/DefaultBugReporter.kt index 2123717f8e..e9fa054acf 100755 --- a/features/rageshake/impl/src/main/kotlin/io/element/android/features/rageshake/impl/reporter/DefaultBugReporter.kt +++ b/features/rageshake/impl/src/main/kotlin/io/element/android/features/rageshake/impl/reporter/DefaultBugReporter.kt @@ -200,6 +200,8 @@ class DefaultBugReporter @Inject constructor( // add some github labels builder.addFormDataPart("label", buildMeta.versionName) builder.addFormDataPart("label", buildMeta.flavorDescription) + builder.addFormDataPart("branch_name", buildMeta.gitBranchName) + if (crashCallStack.isNotEmpty() && withCrashLogs) { builder.addFormDataPart("label", "crash") } diff --git a/libraries/core/src/main/kotlin/io/element/android/libraries/core/meta/BuildMeta.kt b/libraries/core/src/main/kotlin/io/element/android/libraries/core/meta/BuildMeta.kt index aaf54cc0f8..cac30e02e4 100644 --- a/libraries/core/src/main/kotlin/io/element/android/libraries/core/meta/BuildMeta.kt +++ b/libraries/core/src/main/kotlin/io/element/android/libraries/core/meta/BuildMeta.kt @@ -25,7 +25,6 @@ data class BuildMeta( val versionName: String, val versionCode: Int, val gitRevision: String, - val gitRevisionDate: String, val gitBranchName: String, val flavorDescription: String, val flavorShortDescription: String, diff --git a/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/core/BuildMeta.kt b/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/core/BuildMeta.kt index d048101f87..f3a704ddc5 100644 --- a/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/core/BuildMeta.kt +++ b/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/core/BuildMeta.kt @@ -28,7 +28,6 @@ fun aBuildMeta( versionName: String = "", versionCode: Int = 0, gitRevision: String = "", - gitRevisionDate: String = "", gitBranchName: String = "", flavorDescription: String = "", flavorShortDescription: String = "", @@ -41,7 +40,6 @@ fun aBuildMeta( versionName, versionCode, gitRevision, - gitRevisionDate, gitBranchName, flavorDescription, flavorShortDescription diff --git a/plugins/src/main/kotlin/extension/Utils.kt b/plugins/src/main/kotlin/extension/Utils.kt new file mode 100644 index 0000000000..31fdd4f952 --- /dev/null +++ b/plugins/src/main/kotlin/extension/Utils.kt @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2022 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 extension + +import org.gradle.api.Project +import java.io.ByteArrayOutputStream +import java.io.IOException + +private fun Project.runCommand(cmd: String): String { + val outputStream = ByteArrayOutputStream() + val errorStream = ByteArrayOutputStream() + project.exec { + commandLine = cmd.split(" ") + standardOutput = outputStream + errorOutput = errorStream + } + if (errorStream.size() > 0) { + println("Error while running command: $cmd") + throw IOException(String(errorStream.toByteArray())) + } + return String(outputStream.toByteArray()).trim() +} + +fun Project.gitRevision() = runCommand("git rev-parse --short=8 HEAD") + +fun Project.gitBranchName() = runCommand("git rev-parse --abbrev-ref HEAD") diff --git a/samples/minimal/src/main/kotlin/io/element/android/samples/minimal/Singleton.kt b/samples/minimal/src/main/kotlin/io/element/android/samples/minimal/Singleton.kt index fc146d1ff3..06e8fb02f4 100644 --- a/samples/minimal/src/main/kotlin/io/element/android/samples/minimal/Singleton.kt +++ b/samples/minimal/src/main/kotlin/io/element/android/samples/minimal/Singleton.kt @@ -37,12 +37,8 @@ object Singleton { lowPrivacyLoggingEnabled = false, versionName = "0.1.0", versionCode = 1, - // BuildConfig.GIT_REVISION, - gitRevision = "TODO", - // BuildConfig.GIT_REVISION_DATE, - gitRevisionDate = "TODO", - // BuildConfig.GIT_BRANCH_NAME, - gitBranchName = "TODO", + gitRevision = "", + gitBranchName = "", flavorDescription = "NA", flavorShortDescription = "NA", ) From 30df153a00f31f29c521ffff1f3df033970f12b1 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Thu, 25 Jan 2024 14:34:19 +0100 Subject: [PATCH 092/127] Add test for `DefaultVersionFormatter` --- features/preferences/impl/build.gradle.kts | 1 + .../preferences/impl/root/VersionFormatter.kt | 8 ++- .../impl/root/VersionFormatterTest.kt | 50 +++++++++++++++++++ 3 files changed, 58 insertions(+), 1 deletion(-) create mode 100644 features/preferences/impl/src/test/kotlin/io/element/android/features/preferences/impl/root/VersionFormatterTest.kt diff --git a/features/preferences/impl/build.gradle.kts b/features/preferences/impl/build.gradle.kts index 406d6a2ff4..e6a605f5e4 100644 --- a/features/preferences/impl/build.gradle.kts +++ b/features/preferences/impl/build.gradle.kts @@ -82,6 +82,7 @@ dependencies { testImplementation(projects.libraries.indicator.impl) testImplementation(projects.features.logout.impl) testImplementation(projects.services.analytics.test) + testImplementation(projects.services.toolbox.test) testImplementation(projects.features.analytics.impl) testImplementation(projects.tests.testutils) } diff --git a/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/root/VersionFormatter.kt b/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/root/VersionFormatter.kt index 7eff670951..8fa62df910 100644 --- a/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/root/VersionFormatter.kt +++ b/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/root/VersionFormatter.kt @@ -33,11 +33,17 @@ class DefaultVersionFormatter @Inject constructor( private val buildMeta: BuildMeta, ) : VersionFormatter { override fun get(): String { - return stringProvider.getString( + val base = stringProvider.getString( CommonStrings.settings_version_number, buildMeta.versionName, buildMeta.versionCode.toString() ) + return if (buildMeta.gitBranchName == "main") { + base + } else { + // In case of a build not from main, we display the branch name and the revision + "$base\n${buildMeta.gitBranchName}\n${buildMeta.gitRevision}" + } } } diff --git a/features/preferences/impl/src/test/kotlin/io/element/android/features/preferences/impl/root/VersionFormatterTest.kt b/features/preferences/impl/src/test/kotlin/io/element/android/features/preferences/impl/root/VersionFormatterTest.kt new file mode 100644 index 0000000000..5d35a105b7 --- /dev/null +++ b/features/preferences/impl/src/test/kotlin/io/element/android/features/preferences/impl/root/VersionFormatterTest.kt @@ -0,0 +1,50 @@ +/* + * 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 io.element.android.features.preferences.impl.root + +import com.google.common.truth.Truth.assertThat +import io.element.android.libraries.matrix.test.core.aBuildMeta +import io.element.android.services.toolbox.test.strings.FakeStringProvider +import kotlinx.coroutines.test.runTest +import org.junit.Test + +class VersionFormatterTest { + @Test + fun `version formatter should return simplified version for other branch`() = runTest { + val sut = DefaultVersionFormatter( + stringProvider = FakeStringProvider(defaultResult = VERSION), + buildMeta = aBuildMeta(gitBranchName = "main") + ) + assertThat(sut.get()).isEqualTo(VERSION) + } + + @Test + fun `version formatter should return simplified version for main branch`() = runTest { + val sut = DefaultVersionFormatter( + stringProvider = FakeStringProvider(defaultResult = VERSION), + buildMeta = aBuildMeta( + gitBranchName = "branch", + gitRevision = "1234567890", + ) + ) + assertThat(sut.get()).isEqualTo("$VERSION\nbranch\n1234567890") + } + + companion object { + const val VERSION = "version" + } +} From 502f35787a6ce3045e5e4e4f408a922e1e1c92a5 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Thu, 25 Jan 2024 14:36:42 +0100 Subject: [PATCH 093/127] Move `FakeVersionFormatter` to the test sourceSet. --- .../preferences/impl/root/VersionFormatter.kt | 5 ---- .../impl/root/FakeVersionFormatter.kt | 23 +++++++++++++++++++ 2 files changed, 23 insertions(+), 5 deletions(-) create mode 100644 features/preferences/impl/src/test/kotlin/io/element/android/features/preferences/impl/root/FakeVersionFormatter.kt diff --git a/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/root/VersionFormatter.kt b/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/root/VersionFormatter.kt index 8fa62df910..949dde2200 100644 --- a/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/root/VersionFormatter.kt +++ b/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/root/VersionFormatter.kt @@ -47,8 +47,3 @@ class DefaultVersionFormatter @Inject constructor( } } -class FakeVersionFormatter : VersionFormatter { - override fun get(): String { - return "A Version" - } -} diff --git a/features/preferences/impl/src/test/kotlin/io/element/android/features/preferences/impl/root/FakeVersionFormatter.kt b/features/preferences/impl/src/test/kotlin/io/element/android/features/preferences/impl/root/FakeVersionFormatter.kt new file mode 100644 index 0000000000..e9321c3dd4 --- /dev/null +++ b/features/preferences/impl/src/test/kotlin/io/element/android/features/preferences/impl/root/FakeVersionFormatter.kt @@ -0,0 +1,23 @@ +/* + * 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 io.element.android.features.preferences.impl.root + +class FakeVersionFormatter : VersionFormatter { + override fun get(): String { + return "A Version" + } +} From 6ea76d9acdb816124959ff8dfdd4088d705aae53 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Thu, 25 Jan 2024 15:00:43 +0100 Subject: [PATCH 094/127] Map `roomInfo.numUnreadNotifications` to `RoomSummaryDetails.numUnreadNotifications` --- .../roomlist/impl/datasource/RoomListRoomSummaryFactory.kt | 2 ++ .../android/features/roomlist/impl/model/RoomListRoomSummary.kt | 1 + .../features/roomlist/impl/model/RoomListRoomSummaryProvider.kt | 2 ++ .../android/libraries/matrix/api/roomlist/RoomSummary.kt | 1 + .../libraries/matrix/impl/roomlist/RoomSummaryDetailsFactory.kt | 1 + .../android/libraries/matrix/test/room/RoomSummaryFixture.kt | 2 ++ .../android/libraries/matrix/ui/components/SelectedRoom.kt | 2 ++ 7 files changed, 11 insertions(+) diff --git a/features/roomlist/impl/src/main/kotlin/io/element/android/features/roomlist/impl/datasource/RoomListRoomSummaryFactory.kt b/features/roomlist/impl/src/main/kotlin/io/element/android/features/roomlist/impl/datasource/RoomListRoomSummaryFactory.kt index e12674658a..9f1416c701 100644 --- a/features/roomlist/impl/src/main/kotlin/io/element/android/features/roomlist/impl/datasource/RoomListRoomSummaryFactory.kt +++ b/features/roomlist/impl/src/main/kotlin/io/element/android/features/roomlist/impl/datasource/RoomListRoomSummaryFactory.kt @@ -43,6 +43,7 @@ class RoomListRoomSummaryFactory @Inject constructor( avatarData = AvatarData(id, "S", size = AvatarSize.RoomListItem), numberOfUnreadMessages = 0, numberOfUnreadMentions = 0, + numberOfUnreadNotifications = 0, userDefinedNotificationMode = null, hasRoomCall = false, isDm = false, @@ -69,6 +70,7 @@ class RoomListRoomSummaryFactory @Inject constructor( name = roomSummary.details.name, numberOfUnreadMessages = roomSummary.details.numUnreadMessages, numberOfUnreadMentions = roomSummary.details.numUnreadMentions, + numberOfUnreadNotifications = roomSummary.details.numUnreadNotifications, timestamp = lastMessageTimestampFormatter.format(roomSummary.details.lastMessageTimestamp), lastMessage = roomSummary.details.lastMessage?.let { message -> roomLastMessageFormatter.format(message.event, roomSummary.details.isDirect) diff --git a/features/roomlist/impl/src/main/kotlin/io/element/android/features/roomlist/impl/model/RoomListRoomSummary.kt b/features/roomlist/impl/src/main/kotlin/io/element/android/features/roomlist/impl/model/RoomListRoomSummary.kt index e35680abc9..f2f0e3932d 100644 --- a/features/roomlist/impl/src/main/kotlin/io/element/android/features/roomlist/impl/model/RoomListRoomSummary.kt +++ b/features/roomlist/impl/src/main/kotlin/io/element/android/features/roomlist/impl/model/RoomListRoomSummary.kt @@ -28,6 +28,7 @@ data class RoomListRoomSummary( val name: String, val numberOfUnreadMessages: Int, val numberOfUnreadMentions: Int, + val numberOfUnreadNotifications: Int, val timestamp: String?, val lastMessage: CharSequence?, val avatarData: AvatarData, diff --git a/features/roomlist/impl/src/main/kotlin/io/element/android/features/roomlist/impl/model/RoomListRoomSummaryProvider.kt b/features/roomlist/impl/src/main/kotlin/io/element/android/features/roomlist/impl/model/RoomListRoomSummaryProvider.kt index f1b0403f5b..e53e1f9072 100644 --- a/features/roomlist/impl/src/main/kotlin/io/element/android/features/roomlist/impl/model/RoomListRoomSummaryProvider.kt +++ b/features/roomlist/impl/src/main/kotlin/io/element/android/features/roomlist/impl/model/RoomListRoomSummaryProvider.kt @@ -88,6 +88,7 @@ internal fun aRoomListRoomSummary( name: String = "Room name", numberOfUnreadMessages: Int = 0, numberOfUnreadMentions: Int = 0, + numberOfUnreadNotifications: Int = 0, lastMessage: String? = "Last message", timestamp: String? = lastMessage?.let { "88:88" }, isPlaceholder: Boolean = false, @@ -101,6 +102,7 @@ internal fun aRoomListRoomSummary( name = name, numberOfUnreadMessages = numberOfUnreadMessages, numberOfUnreadMentions = numberOfUnreadMentions, + numberOfUnreadNotifications = numberOfUnreadNotifications, timestamp = timestamp, lastMessage = lastMessage, avatarData = avatarData, diff --git a/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/roomlist/RoomSummary.kt b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/roomlist/RoomSummary.kt index 09862c7879..cc584f08bb 100644 --- a/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/roomlist/RoomSummary.kt +++ b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/roomlist/RoomSummary.kt @@ -42,6 +42,7 @@ data class RoomSummaryDetails( val lastMessage: RoomMessage?, val numUnreadMessages: Int, val numUnreadMentions: Int, + val numUnreadNotifications: Int, val inviter: RoomMember?, val userDefinedNotificationMode: RoomNotificationMode?, val hasRoomCall: Boolean, diff --git a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/roomlist/RoomSummaryDetailsFactory.kt b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/roomlist/RoomSummaryDetailsFactory.kt index 59be0ba4ce..1b3e900f17 100644 --- a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/roomlist/RoomSummaryDetailsFactory.kt +++ b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/roomlist/RoomSummaryDetailsFactory.kt @@ -37,6 +37,7 @@ class RoomSummaryDetailsFactory(private val roomMessageFactory: RoomMessageFacto avatarUrl = roomInfo.avatarUrl, numUnreadMentions = roomInfo.numUnreadMentions.toInt(), numUnreadMessages = roomInfo.numUnreadMessages.toInt(), + numUnreadNotifications = roomInfo.numUnreadNotifications.toInt(), lastMessage = latestRoomMessage, inviter = roomInfo.inviter?.let(RoomMemberMapper::map), userDefinedNotificationMode = roomInfo.userDefinedNotificationMode?.let(RoomNotificationSettingsMapper::mapMode), diff --git a/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/room/RoomSummaryFixture.kt b/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/room/RoomSummaryFixture.kt index 9e8c438ee3..2bd04894c0 100644 --- a/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/room/RoomSummaryFixture.kt +++ b/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/room/RoomSummaryFixture.kt @@ -61,6 +61,7 @@ fun aRoomSummaryDetails( lastMessage: RoomMessage? = aRoomMessage(), numUnreadMentions: Int = 0, numUnreadMessages: Int = 0, + numUnreadNotifications: Int = 0, notificationMode: RoomNotificationMode? = null, inviter: RoomMember? = null, canonicalAlias: String? = null, @@ -74,6 +75,7 @@ fun aRoomSummaryDetails( lastMessage = lastMessage, numUnreadMentions = numUnreadMentions, numUnreadMessages = numUnreadMessages, + numUnreadNotifications = numUnreadNotifications, userDefinedNotificationMode = notificationMode, inviter = inviter, canonicalAlias = canonicalAlias, diff --git a/libraries/matrixui/src/main/kotlin/io/element/android/libraries/matrix/ui/components/SelectedRoom.kt b/libraries/matrixui/src/main/kotlin/io/element/android/libraries/matrix/ui/components/SelectedRoom.kt index 734f7eef1f..a4d9a479c2 100644 --- a/libraries/matrixui/src/main/kotlin/io/element/android/libraries/matrix/ui/components/SelectedRoom.kt +++ b/libraries/matrixui/src/main/kotlin/io/element/android/libraries/matrix/ui/components/SelectedRoom.kt @@ -115,6 +115,7 @@ fun aRoomSummaryDetails( isDm: Boolean = false, numUnreadMentions: Int = 0, numUnreadMessages: Int = 0, + numUnreadNotifications: Int = 0, ) = RoomSummaryDetails( roomId = roomId, name = name, @@ -128,4 +129,5 @@ fun aRoomSummaryDetails( isDm = isDm, numUnreadMentions = numUnreadMentions, numUnreadMessages = numUnreadMessages, + numUnreadNotifications = numUnreadNotifications, ) From 78bd91de2fe99096970705563835007addaee5aa Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Thu, 25 Jan 2024 15:06:34 +0100 Subject: [PATCH 095/127] Rework: extract sub fun composable. --- .../impl/components/RoomSummaryRow.kt | 41 +++++++++++-------- 1 file changed, 23 insertions(+), 18 deletions(-) diff --git a/features/roomlist/impl/src/main/kotlin/io/element/android/features/roomlist/impl/components/RoomSummaryRow.kt b/features/roomlist/impl/src/main/kotlin/io/element/android/features/roomlist/impl/components/RoomSummaryRow.kt index 65e5490aa6..7944fc69b2 100644 --- a/features/roomlist/impl/src/main/kotlin/io/element/android/features/roomlist/impl/components/RoomSummaryRow.kt +++ b/features/roomlist/impl/src/main/kotlin/io/element/android/features/roomlist/impl/components/RoomSummaryRow.kt @@ -209,12 +209,7 @@ private fun RowScope.NotificationIcons( null, RoomNotificationMode.ALL_MESSAGES -> { if (numberOfUnreadMentions > 0) { - Icon( - modifier = Modifier.size(16.dp), - contentDescription = null, - imageVector = CompoundIcons.Mention, - tint = ElementTheme.colors.unreadIndicator, - ) + MentionIndicatorAtom() UnreadIndicatorAtom() } else if (numberOfUnreadMessages > 0) { UnreadIndicatorAtom() @@ -222,24 +217,14 @@ private fun RowScope.NotificationIcons( } RoomNotificationMode.MENTIONS_AND_KEYWORDS_ONLY -> { if (numberOfUnreadMentions > 0) { - Icon( - modifier = Modifier.size(16.dp), - contentDescription = null, - imageVector = CompoundIcons.Mention, - tint = ElementTheme.colors.unreadIndicator, - ) + MentionIndicatorAtom() UnreadIndicatorAtom() } else if (numberOfUnreadMessages > 0) { UnreadIndicatorAtom(color = ElementTheme.colors.iconQuaternary) } } RoomNotificationMode.MUTE -> { - Icon( - modifier = Modifier.size(16.dp), - contentDescription = null, - imageVector = CompoundIcons.NotificationsSolidOff, - tint = ElementTheme.colors.iconQuaternary, - ) + NotificationOffIndicatorAtom() if (numberOfUnreadMessages > 0 || numberOfUnreadMentions > 0) { UnreadIndicatorAtom(color = ElementTheme.colors.iconQuaternary) } @@ -247,6 +232,26 @@ private fun RowScope.NotificationIcons( } } +@Composable +private fun NotificationOffIndicatorAtom() { + Icon( + modifier = Modifier.size(16.dp), + contentDescription = null, + imageVector = CompoundIcons.NotificationsSolidOff, + tint = ElementTheme.colors.iconQuaternary, + ) +} + +@Composable +private fun MentionIndicatorAtom() { + Icon( + modifier = Modifier.size(16.dp), + contentDescription = null, + imageVector = CompoundIcons.Mention, + tint = ElementTheme.colors.unreadIndicator, + ) +} + @PreviewsDayNight @Composable internal fun RoomSummaryRowPreview(@PreviewParameter(RoomListRoomSummaryProvider::class) data: RoomListRoomSummary) = ElementPreview { From 429effc70666785b9bb9a1b6253ea07f7e832ae1 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Thu, 25 Jan 2024 15:29:11 +0100 Subject: [PATCH 096/127] Rework: improve OnGoingCallIcon API. --- .../impl/components/RoomSummaryRow.kt | 24 ++++++++----------- 1 file changed, 10 insertions(+), 14 deletions(-) diff --git a/features/roomlist/impl/src/main/kotlin/io/element/android/features/roomlist/impl/components/RoomSummaryRow.kt b/features/roomlist/impl/src/main/kotlin/io/element/android/features/roomlist/impl/components/RoomSummaryRow.kt index 7944fc69b2..acc0ab0dba 100644 --- a/features/roomlist/impl/src/main/kotlin/io/element/android/features/roomlist/impl/components/RoomSummaryRow.kt +++ b/features/roomlist/impl/src/main/kotlin/io/element/android/features/roomlist/impl/components/RoomSummaryRow.kt @@ -173,9 +173,9 @@ private fun RowScope.LastMessageAndIndicatorRow(room: RoomListRoomSummary) { verticalAlignment = Alignment.CenterVertically, ) { // Video call - OnGoingCallIcon( - room.hasRoomCall, - ) + if (room.hasRoomCall) { + OnGoingCallIcon() + } // Other indicators NotificationIcons( room.userDefinedNotificationMode, @@ -186,17 +186,13 @@ private fun RowScope.LastMessageAndIndicatorRow(room: RoomListRoomSummary) { } @Composable -private fun OnGoingCallIcon( - hasRoomCall: Boolean, -) { - if (hasRoomCall) { - Icon( - modifier = Modifier.size(16.dp), - imageVector = CompoundIcons.VideoCallSolid, - contentDescription = null, - tint = ElementTheme.colors.unreadIndicator, - ) - } +private fun OnGoingCallIcon() { + Icon( + modifier = Modifier.size(16.dp), + imageVector = CompoundIcons.VideoCallSolid, + contentDescription = null, + tint = ElementTheme.colors.unreadIndicator, + ) } @Composable From c7f29bfe8e0bbeca5d4b6fd004f69a3111111c1f Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Thu, 25 Jan 2024 16:17:27 +0100 Subject: [PATCH 097/127] Ensure the icon stay grey if the global setting is set to mention only. Implement the iOS logic #2282 --- .../impl/components/RoomSummaryRow.kt | 67 ++++++------------- .../impl/model/RoomListRoomSummary.kt | 13 ++-- 2 files changed, 27 insertions(+), 53 deletions(-) diff --git a/features/roomlist/impl/src/main/kotlin/io/element/android/features/roomlist/impl/components/RoomSummaryRow.kt b/features/roomlist/impl/src/main/kotlin/io/element/android/features/roomlist/impl/components/RoomSummaryRow.kt index acc0ab0dba..7002d451ef 100644 --- a/features/roomlist/impl/src/main/kotlin/io/element/android/features/roomlist/impl/components/RoomSummaryRow.kt +++ b/features/roomlist/impl/src/main/kotlin/io/element/android/features/roomlist/impl/components/RoomSummaryRow.kt @@ -35,6 +35,7 @@ import androidx.compose.runtime.Composable import androidx.compose.runtime.remember import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color import androidx.compose.ui.text.AnnotatedString import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.tooling.preview.PreviewParameter @@ -141,7 +142,7 @@ private fun RowScope.NameAndTimestampRow(room: RoomListRoomSummary) { Text( text = room.timestamp ?: "", style = ElementTheme.typography.fontBodySmMedium, - color = if (room.isTimestampHighlighted) { + color = if (room.isHighlighted) { ElementTheme.colors.unreadIndicator } else { MaterialTheme.roomListRoomMessageDate() @@ -165,69 +166,43 @@ private fun RowScope.LastMessageAndIndicatorRow(room: RoomListRoomSummary) { maxLines = 2, overflow = TextOverflow.Ellipsis ) - - // Unread + // Call and unread Row( modifier = Modifier.height(16.dp), horizontalArrangement = Arrangement.spacedBy(8.dp), verticalAlignment = Alignment.CenterVertically, ) { - // Video call + val tint = if (room.isHighlighted) ElementTheme.colors.unreadIndicator else ElementTheme.colors.iconQuaternary if (room.hasRoomCall) { - OnGoingCallIcon() + OnGoingCallIcon( + color = tint, + ) + } + if (room.userDefinedNotificationMode == RoomNotificationMode.MUTE) { + NotificationOffIndicatorAtom() + } else if (room.numberOfUnreadMentions > 0) { + MentionIndicatorAtom() + } + if (room.hasNewContent) { + UnreadIndicatorAtom( + color = tint + ) } - // Other indicators - NotificationIcons( - room.userDefinedNotificationMode, - room.numberOfUnreadMessages, - room.numberOfUnreadMentions, - ) } } @Composable -private fun OnGoingCallIcon() { +private fun OnGoingCallIcon( + color: Color, +) { Icon( modifier = Modifier.size(16.dp), imageVector = CompoundIcons.VideoCallSolid, contentDescription = null, - tint = ElementTheme.colors.unreadIndicator, + tint = color, ) } -@Composable -private fun RowScope.NotificationIcons( - userDefinedNotificationMode: RoomNotificationMode?, - numberOfUnreadMessages: Int, - numberOfUnreadMentions: Int, -) { - when (userDefinedNotificationMode) { - null, - RoomNotificationMode.ALL_MESSAGES -> { - if (numberOfUnreadMentions > 0) { - MentionIndicatorAtom() - UnreadIndicatorAtom() - } else if (numberOfUnreadMessages > 0) { - UnreadIndicatorAtom() - } - } - RoomNotificationMode.MENTIONS_AND_KEYWORDS_ONLY -> { - if (numberOfUnreadMentions > 0) { - MentionIndicatorAtom() - UnreadIndicatorAtom() - } else if (numberOfUnreadMessages > 0) { - UnreadIndicatorAtom(color = ElementTheme.colors.iconQuaternary) - } - } - RoomNotificationMode.MUTE -> { - NotificationOffIndicatorAtom() - if (numberOfUnreadMessages > 0 || numberOfUnreadMentions > 0) { - UnreadIndicatorAtom(color = ElementTheme.colors.iconQuaternary) - } - } - } -} - @Composable private fun NotificationOffIndicatorAtom() { Icon( diff --git a/features/roomlist/impl/src/main/kotlin/io/element/android/features/roomlist/impl/model/RoomListRoomSummary.kt b/features/roomlist/impl/src/main/kotlin/io/element/android/features/roomlist/impl/model/RoomListRoomSummary.kt index f2f0e3932d..26cd9e2d32 100644 --- a/features/roomlist/impl/src/main/kotlin/io/element/android/features/roomlist/impl/model/RoomListRoomSummary.kt +++ b/features/roomlist/impl/src/main/kotlin/io/element/android/features/roomlist/impl/model/RoomListRoomSummary.kt @@ -37,11 +37,10 @@ data class RoomListRoomSummary( val hasRoomCall: Boolean, val isDm: Boolean, ) { - val isTimestampHighlighted = hasRoomCall || - when (userDefinedNotificationMode) { - null, - RoomNotificationMode.ALL_MESSAGES -> numberOfUnreadMessages > 0 || numberOfUnreadMentions > 0 - RoomNotificationMode.MENTIONS_AND_KEYWORDS_ONLY -> numberOfUnreadMentions > 0 - RoomNotificationMode.MUTE -> false - } + val isHighlighted = userDefinedNotificationMode != RoomNotificationMode.MUTE && + (numberOfUnreadNotifications > 0 || numberOfUnreadMentions > 0) + + val hasNewContent = numberOfUnreadMessages > 0 || + numberOfUnreadMentions > 0 || + numberOfUnreadNotifications > 0 } From 1653c8ae80f29a6081d5ffc55c3b89fda11ddbc4 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Thu, 25 Jan 2024 16:20:06 +0100 Subject: [PATCH 098/127] Changelog --- changelog.d/2282.bugfix | 1 + 1 file changed, 1 insertion(+) create mode 100644 changelog.d/2282.bugfix diff --git a/changelog.d/2282.bugfix b/changelog.d/2282.bugfix new file mode 100644 index 0000000000..959bc42189 --- /dev/null +++ b/changelog.d/2282.bugfix @@ -0,0 +1 @@ +Room list Ensure the indicators stay grey if the global setting is set to mention only and a regular message is received. From ccbe2eb1f783f811082ebad79f3d5afcc57e1d64 Mon Sep 17 00:00:00 2001 From: ElementBot Date: Thu, 25 Jan 2024 15:27:56 +0000 Subject: [PATCH 099/127] Update screenshots --- ...w_null_RoomSummaryRow-Day-9_10_null_16,NEXUS_5,1.0,en].png | 4 ++-- ...w_null_RoomSummaryRow-Day-9_10_null_17,NEXUS_5,1.0,en].png | 4 ++-- ...w_null_RoomSummaryRow-Day-9_10_null_20,NEXUS_5,1.0,en].png | 4 ++-- ...w_null_RoomSummaryRow-Day-9_10_null_21,NEXUS_5,1.0,en].png | 4 ++-- ...w_null_RoomSummaryRow-Day-9_10_null_24,NEXUS_5,1.0,en].png | 4 ++-- ...w_null_RoomSummaryRow-Day-9_10_null_25,NEXUS_5,1.0,en].png | 4 ++-- ...w_null_RoomSummaryRow-Day-9_10_null_26,NEXUS_5,1.0,en].png | 4 ++-- ...w_null_RoomSummaryRow-Day-9_10_null_27,NEXUS_5,1.0,en].png | 4 ++-- ...ow_null_RoomSummaryRow-Day-9_10_null_3,NEXUS_5,1.0,en].png | 4 ++-- ...ow_null_RoomSummaryRow-Day-9_10_null_5,NEXUS_5,1.0,en].png | 4 ++-- ...null_RoomSummaryRow-Night-9_11_null_16,NEXUS_5,1.0,en].png | 4 ++-- ...null_RoomSummaryRow-Night-9_11_null_17,NEXUS_5,1.0,en].png | 4 ++-- ...null_RoomSummaryRow-Night-9_11_null_20,NEXUS_5,1.0,en].png | 4 ++-- ...null_RoomSummaryRow-Night-9_11_null_21,NEXUS_5,1.0,en].png | 4 ++-- ...null_RoomSummaryRow-Night-9_11_null_24,NEXUS_5,1.0,en].png | 4 ++-- ...null_RoomSummaryRow-Night-9_11_null_25,NEXUS_5,1.0,en].png | 4 ++-- ...null_RoomSummaryRow-Night-9_11_null_26,NEXUS_5,1.0,en].png | 4 ++-- ...null_RoomSummaryRow-Night-9_11_null_27,NEXUS_5,1.0,en].png | 4 ++-- ..._null_RoomSummaryRow-Night-9_11_null_3,NEXUS_5,1.0,en].png | 4 ++-- ..._null_RoomSummaryRow-Night-9_11_null_5,NEXUS_5,1.0,en].png | 4 ++-- ...ListSearchResultContent-Day-10_11_null,NEXUS_5,1.0,en].png | 4 ++-- ...stSearchResultContent-Night-10_12_null,NEXUS_5,1.0,en].png | 4 ++-- ...tView_null_RoomListView-Day-3_4_null_0,NEXUS_5,1.0,en].png | 4 ++-- ...tView_null_RoomListView-Day-3_4_null_1,NEXUS_5,1.0,en].png | 4 ++-- ...tView_null_RoomListView-Day-3_4_null_2,NEXUS_5,1.0,en].png | 4 ++-- ...tView_null_RoomListView-Day-3_4_null_3,NEXUS_5,1.0,en].png | 4 ++-- ...tView_null_RoomListView-Day-3_4_null_4,NEXUS_5,1.0,en].png | 4 ++-- ...tView_null_RoomListView-Day-3_4_null_5,NEXUS_5,1.0,en].png | 4 ++-- ...tView_null_RoomListView-Day-3_4_null_7,NEXUS_5,1.0,en].png | 4 ++-- ...tView_null_RoomListView-Day-3_4_null_9,NEXUS_5,1.0,en].png | 4 ++-- ...iew_null_RoomListView-Night-3_5_null_0,NEXUS_5,1.0,en].png | 4 ++-- ...iew_null_RoomListView-Night-3_5_null_1,NEXUS_5,1.0,en].png | 4 ++-- ...iew_null_RoomListView-Night-3_5_null_2,NEXUS_5,1.0,en].png | 4 ++-- ...iew_null_RoomListView-Night-3_5_null_3,NEXUS_5,1.0,en].png | 4 ++-- ...iew_null_RoomListView-Night-3_5_null_4,NEXUS_5,1.0,en].png | 4 ++-- ...iew_null_RoomListView-Night-3_5_null_5,NEXUS_5,1.0,en].png | 4 ++-- ...iew_null_RoomListView-Night-3_5_null_7,NEXUS_5,1.0,en].png | 4 ++-- ...iew_null_RoomListView-Night-3_5_null_9,NEXUS_5,1.0,en].png | 4 ++-- 38 files changed, 76 insertions(+), 76 deletions(-) diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Day-9_10_null_16,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Day-9_10_null_16,NEXUS_5,1.0,en].png index ac8f73cb15..dd462b020f 100644 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Day-9_10_null_16,NEXUS_5,1.0,en].png +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Day-9_10_null_16,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:aed38a22a1d3a481d07c6955cc14f2a81ed27d754fb0701113d5ec5b6bb85015 -size 14461 +oid sha256:a02ead0e9c689ac14337dbfb1d238a4082321aa5e9ce5447135df71358dd36b4 +size 14338 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Day-9_10_null_17,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Day-9_10_null_17,NEXUS_5,1.0,en].png index cc9c93bf90..375e03b6c0 100644 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Day-9_10_null_17,NEXUS_5,1.0,en].png +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Day-9_10_null_17,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:b8194ccafe6f78cb90bbe1d1291a8b04463e57e9fe0a891adb3d1a95cb7b91a9 -size 15652 +oid sha256:a4b88a625372bd794e8f18fb572cfc642d5738e36916e5639a8aac3fdddf70f8 +size 15474 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Day-9_10_null_20,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Day-9_10_null_20,NEXUS_5,1.0,en].png index 585b47b72a..7345bee430 100644 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Day-9_10_null_20,NEXUS_5,1.0,en].png +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Day-9_10_null_20,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:f9b6e33a825b4fb6379827a9ec28f586e64d05aaf013d8120eccdafa178f6816 -size 16714 +oid sha256:215750e3ed728fe17ac8b2a12e3867ef3dbaa1b486276fc73b7a1fd334ee831c +size 16573 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Day-9_10_null_21,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Day-9_10_null_21,NEXUS_5,1.0,en].png index 62735b485b..f8cb49e06c 100644 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Day-9_10_null_21,NEXUS_5,1.0,en].png +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Day-9_10_null_21,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:229fbadc49f0ef62434e9f26e7f31f1f94037a358dfc218b552046978ca3a182 -size 17874 +oid sha256:b8140db57575dc4f447b12bb1369ad0f1cff549679b707dd3e82e1224470a1d4 +size 17707 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Day-9_10_null_24,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Day-9_10_null_24,NEXUS_5,1.0,en].png index e6bb8b58c1..fe69a074ac 100644 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Day-9_10_null_24,NEXUS_5,1.0,en].png +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Day-9_10_null_24,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:3951f02f9f2cc0ba1907363ba7fdf1150260b5add22be95d7bea94ec0c52f31e -size 12841 +oid sha256:44087f904de812d58363dd64ed95d3007c13d8c97c93b05afd53da7fb4a6b3a7 +size 12703 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Day-9_10_null_25,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Day-9_10_null_25,NEXUS_5,1.0,en].png index 89f803773a..9c3662f93a 100644 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Day-9_10_null_25,NEXUS_5,1.0,en].png +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Day-9_10_null_25,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:324024fbe1bf52291a0352859742d630f688becaed00c3c1eeab4ef96f436d63 -size 13943 +oid sha256:f2f6c42ffcef69b58758a29b037b06a4844e047e06c2bdd7187fa64c6208ad41 +size 13781 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Day-9_10_null_26,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Day-9_10_null_26,NEXUS_5,1.0,en].png index a6e71a4e57..5844e343c5 100644 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Day-9_10_null_26,NEXUS_5,1.0,en].png +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Day-9_10_null_26,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:1b6cc4f49d6440ea9ae146ff816ea7ac649a6880924a7be82b2823b1064ce285 -size 15454 +oid sha256:e3d3386f399049e3903413d93b711f430285f19f1a845a5791b4c1fdfd8566ff +size 15296 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Day-9_10_null_27,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Day-9_10_null_27,NEXUS_5,1.0,en].png index 2253b1ae8a..407c728a58 100644 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Day-9_10_null_27,NEXUS_5,1.0,en].png +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Day-9_10_null_27,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:2b3e39f3c7e6606d340bf4462d18f9b4e5329b1e845beb6a4a3d0c1a1dabe5b2 -size 13521 +oid sha256:8b911a96afcfef14ccfcee87bae860105e4d34c6b06bb5db74334a1494ba0f05 +size 13367 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Day-9_10_null_3,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Day-9_10_null_3,NEXUS_5,1.0,en].png index ae1e098362..feeeb4879c 100644 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Day-9_10_null_3,NEXUS_5,1.0,en].png +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Day-9_10_null_3,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:a1dfe518ad4ee77539f017a39c684e0ce7bfb733a33161639fdf606a188b13d0 -size 22406 +oid sha256:eeddf38808c98548f550956dd9338a897f51913944bd1e9adac06117bbd002d9 +size 22262 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Day-9_10_null_5,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Day-9_10_null_5,NEXUS_5,1.0,en].png index 004868ed67..e630578fca 100644 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Day-9_10_null_5,NEXUS_5,1.0,en].png +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Day-9_10_null_5,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:176f15fb96c05d5932708c9eb26a98261540f07fa4204a416b67baa2388993e5 -size 14775 +oid sha256:f6bbad58b0e446703ab76117af2916fbee40196faf8424e36eceac10f625d50c +size 14642 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Night-9_11_null_16,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Night-9_11_null_16,NEXUS_5,1.0,en].png index df70b73967..0b4bff7f98 100644 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Night-9_11_null_16,NEXUS_5,1.0,en].png +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Night-9_11_null_16,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:0f59a1489dc39a6b9fdb3c90a17eb2d604d3f9a422827fe30b6e3251a6a5e54f -size 14131 +oid sha256:a47196a390720a7321121c934e44fb524f37e4e5f45feaec6a334d0d8faf893a +size 14151 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Night-9_11_null_17,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Night-9_11_null_17,NEXUS_5,1.0,en].png index 695a5a0908..03d159b408 100644 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Night-9_11_null_17,NEXUS_5,1.0,en].png +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Night-9_11_null_17,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:f5d8aa34aaebac1defbc0a78aef1f45635e68b58390639d9e8ddaff1e8c95647 -size 15261 +oid sha256:619163e820ad38561e31c2c231e8df63ef43b6bb39f324eab9cda1d5d7d0212c +size 15242 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Night-9_11_null_20,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Night-9_11_null_20,NEXUS_5,1.0,en].png index d34599fe58..1e25af7752 100644 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Night-9_11_null_20,NEXUS_5,1.0,en].png +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Night-9_11_null_20,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:4aae70caf5fda4fce4f014d1526456e33da65b8221fa81998d69ba675f1a478d -size 16163 +oid sha256:f53362e755ef01ec7eb6d5b5b70d0c55e661d3d0f425f58e396fee9c8df10023 +size 16152 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Night-9_11_null_21,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Night-9_11_null_21,NEXUS_5,1.0,en].png index bec68b016d..c00f359add 100644 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Night-9_11_null_21,NEXUS_5,1.0,en].png +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Night-9_11_null_21,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:17419657995b619a72322d54fb148f9ddf689016f2fb0fc385aeaa9d6114d81c -size 17233 +oid sha256:bc020ed69f860405af38a99d9710495fe84bad6e11f89ca174ee352b62615deb +size 17225 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Night-9_11_null_24,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Night-9_11_null_24,NEXUS_5,1.0,en].png index 5389529e8a..4e4e9b55b3 100644 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Night-9_11_null_24,NEXUS_5,1.0,en].png +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Night-9_11_null_24,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:288c85268c3383d5daaa6d45ee8060ca74330e284b5ef807a1cca7706284daf9 -size 12686 +oid sha256:f5c7efc5dda976509dea1e8259dbe417f655a036cfdbffeaaba5405bc94d52e1 +size 12702 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Night-9_11_null_25,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Night-9_11_null_25,NEXUS_5,1.0,en].png index 7562af3e65..5cd847939c 100644 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Night-9_11_null_25,NEXUS_5,1.0,en].png +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Night-9_11_null_25,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:63d8fe9ff875a9e7223af0c0acfbdc025600580c5a43144bcc650bfc6bc0b696 -size 13797 +oid sha256:54536f0eaa19b20629a0ebebeeed9ff892a54a8009ac6d06d63a742f4e2791e0 +size 13772 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Night-9_11_null_26,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Night-9_11_null_26,NEXUS_5,1.0,en].png index d9eb1328ad..d89d4d6537 100644 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Night-9_11_null_26,NEXUS_5,1.0,en].png +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Night-9_11_null_26,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:5dda78f4088b9201f0600a06a35d44ca6d407551aeea538392c8a38e9e6fb16e -size 15234 +oid sha256:91437deeb71a9a1e7b8d4f0e343275712d320d3c2f44a3f5cda6efa28a49bdff +size 15197 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Night-9_11_null_27,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Night-9_11_null_27,NEXUS_5,1.0,en].png index 57931f091f..85105ff9f3 100644 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Night-9_11_null_27,NEXUS_5,1.0,en].png +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Night-9_11_null_27,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:b6414b6557672508d6bdabe2b40d547b25ef9a73566241e98bc12500b4cf7234 -size 13370 +oid sha256:dbc09a6ae1619e8a870371bf110654ebd288b686001d892116f6c27cdb3c1919 +size 13339 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Night-9_11_null_3,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Night-9_11_null_3,NEXUS_5,1.0,en].png index 0f0d5353fb..af81e76f00 100644 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Night-9_11_null_3,NEXUS_5,1.0,en].png +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Night-9_11_null_3,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:b5f274b1ad4ca31aaf585d34ce48c2898fbb9ada8294b211fe1440a097da21f6 -size 21626 +oid sha256:4d40489903e1fa61d91ae44bda36fa2f59f81357edb441a198b27f6f928f6c70 +size 21654 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Night-9_11_null_5,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Night-9_11_null_5,NEXUS_5,1.0,en].png index 3af269b8f6..4332acdbc2 100644 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Night-9_11_null_5,NEXUS_5,1.0,en].png +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Night-9_11_null_5,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:9e13796d33e2ae08bdf7e1b9cc3ae4216e4a4d86054b8172d7054f8758232f03 -size 14406 +oid sha256:75db8e2faba1070c628a79e193679b67438a8ae0d484f72e52e32d8411605baa +size 14412 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.search_RoomListSearchResultContent_null_RoomListSearchResultContent-Day-10_11_null,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.search_RoomListSearchResultContent_null_RoomListSearchResultContent-Day-10_11_null,NEXUS_5,1.0,en].png index 95f61ecfa8..03e79996e4 100644 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.search_RoomListSearchResultContent_null_RoomListSearchResultContent-Day-10_11_null,NEXUS_5,1.0,en].png +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.search_RoomListSearchResultContent_null_RoomListSearchResultContent-Day-10_11_null,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:95659c6503ff1def5f3ec59bf96e9b47ea8f539ba90016c06aee3c1ead4d4387 -size 30047 +oid sha256:ac45ae9f8aefc681d6f73d46ecd7683ea9f84c646e4b92f9282924aec0d73bcb +size 29980 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.search_RoomListSearchResultContent_null_RoomListSearchResultContent-Night-10_12_null,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.search_RoomListSearchResultContent_null_RoomListSearchResultContent-Night-10_12_null,NEXUS_5,1.0,en].png index 32e13103bc..a9b938365e 100644 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.search_RoomListSearchResultContent_null_RoomListSearchResultContent-Night-10_12_null,NEXUS_5,1.0,en].png +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.search_RoomListSearchResultContent_null_RoomListSearchResultContent-Night-10_12_null,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:56c5abd33920c390237f2889fceb20f18283c10fd075612ff7abc85bf6e5da52 -size 29887 +oid sha256:3010426862d9e56245b96d9a0ad9d4468996bfd1a7436254e984b6cad46ccac4 +size 29874 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl_RoomListView_null_RoomListView-Day-3_4_null_0,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl_RoomListView_null_RoomListView-Day-3_4_null_0,NEXUS_5,1.0,en].png index 3c9834d32d..558a7f6e18 100644 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl_RoomListView_null_RoomListView-Day-3_4_null_0,NEXUS_5,1.0,en].png +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl_RoomListView_null_RoomListView-Day-3_4_null_0,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:f6415c4b16fca9f9c33fa26c320eba7db63414f9e7f80e4be8c06aadf0d761ef -size 64895 +oid sha256:21835cc7375230c585465e400338a92230ac164ba5fbb3c08a81935295798739 +size 64818 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl_RoomListView_null_RoomListView-Day-3_4_null_1,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl_RoomListView_null_RoomListView-Day-3_4_null_1,NEXUS_5,1.0,en].png index f0cdb4dc98..4893ac0e06 100644 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl_RoomListView_null_RoomListView-Day-3_4_null_1,NEXUS_5,1.0,en].png +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl_RoomListView_null_RoomListView-Day-3_4_null_1,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:eb5cd4ad10a617fdc031c417402c20b8c83c9224ee4e4c40a0803d7399d1d338 -size 86439 +oid sha256:a477aef8b2a641362996cf27c5630ebb0da670c0fc180e2b2b45eb9b0afab3d4 +size 86360 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl_RoomListView_null_RoomListView-Day-3_4_null_2,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl_RoomListView_null_RoomListView-Day-3_4_null_2,NEXUS_5,1.0,en].png index 3c9834d32d..558a7f6e18 100644 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl_RoomListView_null_RoomListView-Day-3_4_null_2,NEXUS_5,1.0,en].png +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl_RoomListView_null_RoomListView-Day-3_4_null_2,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:f6415c4b16fca9f9c33fa26c320eba7db63414f9e7f80e4be8c06aadf0d761ef -size 64895 +oid sha256:21835cc7375230c585465e400338a92230ac164ba5fbb3c08a81935295798739 +size 64818 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl_RoomListView_null_RoomListView-Day-3_4_null_3,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl_RoomListView_null_RoomListView-Day-3_4_null_3,NEXUS_5,1.0,en].png index b9944b4d34..0df8527c75 100644 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl_RoomListView_null_RoomListView-Day-3_4_null_3,NEXUS_5,1.0,en].png +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl_RoomListView_null_RoomListView-Day-3_4_null_3,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:9482d5bdce23a63c4b682fc7ef6c48d3b29c42ae88eb22c0c79876591816ca1c -size 64880 +oid sha256:880db00d69af2c419ea11ec199196b2bd4811c7829ced249a899948e6825b2a2 +size 64785 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl_RoomListView_null_RoomListView-Day-3_4_null_4,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl_RoomListView_null_RoomListView-Day-3_4_null_4,NEXUS_5,1.0,en].png index 9b6f977aa0..22ff27b03e 100644 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl_RoomListView_null_RoomListView-Day-3_4_null_4,NEXUS_5,1.0,en].png +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl_RoomListView_null_RoomListView-Day-3_4_null_4,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:7164dd963d88f12cd5b784d2184e9832b21f4465e42b1b8e687cdfde87e0c853 -size 65990 +oid sha256:b49b631bb839eb12df9beca2dd48554f128da5decbb1381c9da384020b243f94 +size 65875 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl_RoomListView_null_RoomListView-Day-3_4_null_5,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl_RoomListView_null_RoomListView-Day-3_4_null_5,NEXUS_5,1.0,en].png index 97a6d22a8d..3feda9a846 100644 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl_RoomListView_null_RoomListView-Day-3_4_null_5,NEXUS_5,1.0,en].png +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl_RoomListView_null_RoomListView-Day-3_4_null_5,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:01a3240614334fcacc98cdfe4fcba8d91629f000f6224cda2d2218c8d9fdb7aa -size 66366 +oid sha256:33b483b3ef695f55c8a153d8e50b81e244f5125235cc3db559efa861756e6b68 +size 66253 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl_RoomListView_null_RoomListView-Day-3_4_null_7,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl_RoomListView_null_RoomListView-Day-3_4_null_7,NEXUS_5,1.0,en].png index 95f61ecfa8..03e79996e4 100644 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl_RoomListView_null_RoomListView-Day-3_4_null_7,NEXUS_5,1.0,en].png +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl_RoomListView_null_RoomListView-Day-3_4_null_7,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:95659c6503ff1def5f3ec59bf96e9b47ea8f539ba90016c06aee3c1ead4d4387 -size 30047 +oid sha256:ac45ae9f8aefc681d6f73d46ecd7683ea9f84c646e4b92f9282924aec0d73bcb +size 29980 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl_RoomListView_null_RoomListView-Day-3_4_null_9,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl_RoomListView_null_RoomListView-Day-3_4_null_9,NEXUS_5,1.0,en].png index 25388c3a96..25e01b3339 100644 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl_RoomListView_null_RoomListView-Day-3_4_null_9,NEXUS_5,1.0,en].png +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl_RoomListView_null_RoomListView-Day-3_4_null_9,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:ff9327bbe5d92c91bfbe23811fa4776b4fc3c73ab26563a303e27cba4056e5e1 -size 89621 +oid sha256:cc15def26261d505147ee309d90666a7f9325128332fe6b3d246978044a99f78 +size 89554 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl_RoomListView_null_RoomListView-Night-3_5_null_0,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl_RoomListView_null_RoomListView-Night-3_5_null_0,NEXUS_5,1.0,en].png index 95e4c489a9..361db77c69 100644 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl_RoomListView_null_RoomListView-Night-3_5_null_0,NEXUS_5,1.0,en].png +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl_RoomListView_null_RoomListView-Night-3_5_null_0,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:47fce43a17dc5db55f901d43fe2ce6436ad18373129f0ca82ea3aecc07707442 -size 67127 +oid sha256:71b8af217423a992e17414a084d4b336cfa6d0701a0029ed93bb227596024e85 +size 67112 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl_RoomListView_null_RoomListView-Night-3_5_null_1,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl_RoomListView_null_RoomListView-Night-3_5_null_1,NEXUS_5,1.0,en].png index 194ad7e5cf..d2705148e2 100644 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl_RoomListView_null_RoomListView-Night-3_5_null_1,NEXUS_5,1.0,en].png +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl_RoomListView_null_RoomListView-Night-3_5_null_1,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:2d3228cbd10bee0e42b4d6ac09261b6b3d9eb6822f4d6fb8097fbe7ba06b2d8a -size 88321 +oid sha256:d9293afdc38af47fe988d78df044178f845e1e9b5dbf78bfd840711d73bb48b0 +size 88305 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl_RoomListView_null_RoomListView-Night-3_5_null_2,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl_RoomListView_null_RoomListView-Night-3_5_null_2,NEXUS_5,1.0,en].png index 95e4c489a9..361db77c69 100644 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl_RoomListView_null_RoomListView-Night-3_5_null_2,NEXUS_5,1.0,en].png +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl_RoomListView_null_RoomListView-Night-3_5_null_2,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:47fce43a17dc5db55f901d43fe2ce6436ad18373129f0ca82ea3aecc07707442 -size 67127 +oid sha256:71b8af217423a992e17414a084d4b336cfa6d0701a0029ed93bb227596024e85 +size 67112 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl_RoomListView_null_RoomListView-Night-3_5_null_3,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl_RoomListView_null_RoomListView-Night-3_5_null_3,NEXUS_5,1.0,en].png index d4a3208718..01a9907758 100644 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl_RoomListView_null_RoomListView-Night-3_5_null_3,NEXUS_5,1.0,en].png +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl_RoomListView_null_RoomListView-Night-3_5_null_3,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:5871901c9988ce8954758e4b6487f8448b11e9f24984bae8bc4a05336fce99e6 -size 66896 +oid sha256:829115185aa5d0c3c2b91107dfad58dff09357223e5f1df82223fb044a19ec5c +size 66864 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl_RoomListView_null_RoomListView-Night-3_5_null_4,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl_RoomListView_null_RoomListView-Night-3_5_null_4,NEXUS_5,1.0,en].png index b7d2192eb8..8fc682c6a2 100644 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl_RoomListView_null_RoomListView-Night-3_5_null_4,NEXUS_5,1.0,en].png +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl_RoomListView_null_RoomListView-Night-3_5_null_4,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:1bea5791ddb9180750462f17e65733a91bb246c6095f3b87477d3f0406d5a800 -size 68716 +oid sha256:bc15f30e62f68dd8ea3d1a17073328eba61e97e24cd63e5ae9a997287b24145c +size 68682 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl_RoomListView_null_RoomListView-Night-3_5_null_5,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl_RoomListView_null_RoomListView-Night-3_5_null_5,NEXUS_5,1.0,en].png index a44c83e6b1..f9dc69fa6c 100644 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl_RoomListView_null_RoomListView-Night-3_5_null_5,NEXUS_5,1.0,en].png +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl_RoomListView_null_RoomListView-Night-3_5_null_5,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:45fdc87068b3eec07720f4d81ed31c7914e3b6ba781dd5bf699a889a859218b1 -size 69069 +oid sha256:b58177f669fb5aeb03c7b72697feda03492a3df5ec37ebb3a7588fef7e8130f2 +size 69041 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl_RoomListView_null_RoomListView-Night-3_5_null_7,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl_RoomListView_null_RoomListView-Night-3_5_null_7,NEXUS_5,1.0,en].png index 32e13103bc..a9b938365e 100644 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl_RoomListView_null_RoomListView-Night-3_5_null_7,NEXUS_5,1.0,en].png +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl_RoomListView_null_RoomListView-Night-3_5_null_7,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:56c5abd33920c390237f2889fceb20f18283c10fd075612ff7abc85bf6e5da52 -size 29887 +oid sha256:3010426862d9e56245b96d9a0ad9d4468996bfd1a7436254e984b6cad46ccac4 +size 29874 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl_RoomListView_null_RoomListView-Night-3_5_null_9,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl_RoomListView_null_RoomListView-Night-3_5_null_9,NEXUS_5,1.0,en].png index bc6be07737..39d32fc508 100644 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl_RoomListView_null_RoomListView-Night-3_5_null_9,NEXUS_5,1.0,en].png +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl_RoomListView_null_RoomListView-Night-3_5_null_9,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:c59880d152c30171ef28b06035067bb8209028eaf66ff77dc0492112a00979e0 -size 91200 +oid sha256:4908718c873903f2566fd953bd947ad012c822ba3289a8dec96793d3ef879e2b +size 91185 From c9392818a69c4169daaa8994a345514246f2839c Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Thu, 25 Jan 2024 16:46:24 +0100 Subject: [PATCH 100/127] Remove extra new line. --- .../android/features/preferences/impl/root/VersionFormatter.kt | 1 - 1 file changed, 1 deletion(-) diff --git a/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/root/VersionFormatter.kt b/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/root/VersionFormatter.kt index 949dde2200..801f569d81 100644 --- a/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/root/VersionFormatter.kt +++ b/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/root/VersionFormatter.kt @@ -46,4 +46,3 @@ class DefaultVersionFormatter @Inject constructor( } } } - From 6933eb51df4100849285289a83b728e6eab3e1f4 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Thu, 25 Jan 2024 16:46:44 +0100 Subject: [PATCH 101/127] Fix test, there is a new data sent. --- .../rageshake/impl/reporter/DefaultBugReporterTest.kt | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/features/rageshake/impl/src/test/kotlin/io/element/android/features/rageshake/impl/reporter/DefaultBugReporterTest.kt b/features/rageshake/impl/src/test/kotlin/io/element/android/features/rageshake/impl/reporter/DefaultBugReporterTest.kt index c5317e5e48..91b5c016da 100755 --- a/features/rageshake/impl/src/test/kotlin/io/element/android/features/rageshake/impl/reporter/DefaultBugReporterTest.kt +++ b/features/rageshake/impl/src/test/kotlin/io/element/android/features/rageshake/impl/reporter/DefaultBugReporterTest.kt @@ -80,7 +80,7 @@ class DefaultBugReporterTest { server.shutdown() assertThat(onUploadCancelledCalled).isFalse() assertThat(onUploadFailedCalled).isFalse() - assertThat(progressValues.size).isEqualTo(11) + assertThat(progressValues.size).isEqualTo(EXPECTED_NUMBER_OF_PROGRESS_VALUE) assertThat(onUploadSucceedCalled).isTrue() } @@ -131,7 +131,7 @@ class DefaultBugReporterTest { assertThat(onUploadCancelledCalled).isFalse() assertThat(onUploadFailedCalled).isTrue() assertThat(onUploadFailedReason).isEqualTo("An error body") - assertThat(progressValues.size).isEqualTo(11) + assertThat(progressValues.size).isEqualTo(EXPECTED_NUMBER_OF_PROGRESS_VALUE) assertThat(onUploadSucceedCalled).isFalse() } @@ -153,4 +153,8 @@ class DefaultBugReporterTest { bugReporterUrlProvider = { server.url("/") } ) } + + companion object { + private const val EXPECTED_NUMBER_OF_PROGRESS_VALUE = 12 + } } From c5fc45e7fb6529c53238f3967ca1f39365daef2b Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Thu, 25 Jan 2024 17:22:10 +0100 Subject: [PATCH 102/127] Fix test compilation issue. --- .../android/features/roomlist/impl/RoomListPresenterTests.kt | 1 + 1 file changed, 1 insertion(+) diff --git a/features/roomlist/impl/src/test/kotlin/io/element/android/features/roomlist/impl/RoomListPresenterTests.kt b/features/roomlist/impl/src/test/kotlin/io/element/android/features/roomlist/impl/RoomListPresenterTests.kt index 27d8fca783..839fa04cf7 100644 --- a/features/roomlist/impl/src/test/kotlin/io/element/android/features/roomlist/impl/RoomListPresenterTests.kt +++ b/features/roomlist/impl/src/test/kotlin/io/element/android/features/roomlist/impl/RoomListPresenterTests.kt @@ -442,6 +442,7 @@ private val aRoomListRoomSummary = RoomListRoomSummary( name = A_ROOM_NAME, numberOfUnreadMentions = 1, numberOfUnreadMessages = 2, + numberOfUnreadNotifications = 0, timestamp = A_FORMATTED_DATE, lastMessage = "", avatarData = AvatarData(id = A_ROOM_ID.value, name = A_ROOM_NAME, size = AvatarSize.RoomListItem), From 732ec3f26316582018ea2febc6eeec939513e7f4 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Thu, 25 Jan 2024 18:00:09 +0100 Subject: [PATCH 103/127] Ensure login and password exclude `\n`. #2263 --- changelog.d/2263.bugfix | 1 + .../loginpassword/LoginPasswordView.kt | 28 +++++++++++++------ 2 files changed, 20 insertions(+), 9 deletions(-) create mode 100644 changelog.d/2263.bugfix diff --git a/changelog.d/2263.bugfix b/changelog.d/2263.bugfix new file mode 100644 index 0000000000..016555ac44 --- /dev/null +++ b/changelog.d/2263.bugfix @@ -0,0 +1 @@ +Ensure login and password exclude `\n` diff --git a/features/login/impl/src/main/kotlin/io/element/android/features/login/impl/screens/loginpassword/LoginPasswordView.kt b/features/login/impl/src/main/kotlin/io/element/android/features/login/impl/screens/loginpassword/LoginPasswordView.kt index 2a6a752154..1c97836b02 100644 --- a/features/login/impl/src/main/kotlin/io/element/android/features/login/impl/screens/loginpassword/LoginPasswordView.kt +++ b/features/login/impl/src/main/kotlin/io/element/android/features/login/impl/screens/loginpassword/LoginPasswordView.kt @@ -194,15 +194,17 @@ private fun LoginForm( .onTabOrEnterKeyFocusNext(focusManager) .testTag(TestTags.loginEmailUsername) .autofill(autofillTypes = listOf(AutofillType.Username), onFill = { - loginFieldState = it - eventSink(LoginPasswordEvents.SetLogin(it)) + val sanitized = it.sanitize() + loginFieldState = sanitized + eventSink(LoginPasswordEvents.SetLogin(sanitized)) }), placeholder = { Text(text = stringResource(CommonStrings.common_username)) }, onValueChange = { - loginFieldState = it - eventSink(LoginPasswordEvents.SetLogin(it)) + val sanitized = it.sanitize() + loginFieldState = sanitized + eventSink(LoginPasswordEvents.SetLogin(sanitized)) }, keyboardOptions = KeyboardOptions( keyboardType = KeyboardType.Email, @@ -224,7 +226,6 @@ private fun LoginForm( null }, ) - var passwordVisible by remember { mutableStateOf(false) } if (state.loginAction is AsyncData.Loading) { // Ensure password is hidden when user submits the form @@ -239,12 +240,14 @@ private fun LoginForm( .onTabOrEnterKeyFocusNext(focusManager) .testTag(TestTags.loginPassword) .autofill(autofillTypes = listOf(AutofillType.Password), onFill = { - passwordFieldState = it - eventSink(LoginPasswordEvents.SetPassword(it)) + val sanitized = it.sanitize() + passwordFieldState = sanitized + eventSink(LoginPasswordEvents.SetPassword(sanitized)) }), onValueChange = { - passwordFieldState = it - eventSink(LoginPasswordEvents.SetPassword(it)) + val sanitized = it.sanitize() + passwordFieldState = sanitized + eventSink(LoginPasswordEvents.SetPassword(sanitized)) }, placeholder = { Text(text = stringResource(CommonStrings.common_password)) @@ -272,6 +275,13 @@ private fun LoginForm( } } +/** + * Ensure that the string does not contain any new line characters, which can happen when pasting values. + */ +private fun String.sanitize(): String { + return replace("\n", "") +} + @Composable private fun LoginErrorDialog(error: Throwable, onDismiss: () -> Unit) { ErrorDialog( From 0d35e60dacc7f0c884b9c7668b04a77a2f604e92 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Thu, 25 Jan 2024 18:33:48 +0100 Subject: [PATCH 104/127] Disambiguate display name in notifications #2224 --- libraries/matrix/api/build.gradle.kts | 1 + .../api/notification/NotificationData.kt | 15 +++- .../api/notification/NotificationDataTest.kt | 73 +++++++++++++++++++ .../impl/notification/NotificationMapper.kt | 1 + .../notifications/NotifiableEventResolver.kt | 7 +- .../NotifiableEventResolverTest.kt | 1 + 6 files changed, 93 insertions(+), 5 deletions(-) create mode 100644 libraries/matrix/api/src/test/kotlin/io/element/android/libraries/matrix/api/notification/NotificationDataTest.kt diff --git a/libraries/matrix/api/build.gradle.kts b/libraries/matrix/api/build.gradle.kts index f8a600df1e..b9467af169 100644 --- a/libraries/matrix/api/build.gradle.kts +++ b/libraries/matrix/api/build.gradle.kts @@ -46,4 +46,5 @@ dependencies { testImplementation(libs.test.truth) testImplementation(libs.test.robolectric) testImplementation(projects.tests.testutils) + testImplementation(projects.libraries.matrix.test) } diff --git a/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/notification/NotificationData.kt b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/notification/NotificationData.kt index 8275b8ee5f..3fff2dd468 100644 --- a/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/notification/NotificationData.kt +++ b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/notification/NotificationData.kt @@ -27,7 +27,9 @@ data class NotificationData( val roomId: RoomId, // mxc url val senderAvatarUrl: String?, - val senderDisplayName: String?, + // private, must use `getSenderName` + private val senderDisplayName: String?, + private val senderIsNameAmbiguous: Boolean, val roomAvatarUrl: String?, val roomDisplayName: String?, val isDirect: Boolean, @@ -36,7 +38,13 @@ data class NotificationData( val timestamp: Long, val content: NotificationContent, val hasMention: Boolean, -) +) { + fun getSenderName(userId: UserId): String = when { + senderDisplayName.isNullOrBlank() -> userId.value + senderIsNameAmbiguous -> "$senderDisplayName ($userId)" + else -> senderDisplayName + } +} sealed interface NotificationContent { sealed interface MessageLike : NotificationContent { @@ -54,11 +62,13 @@ sealed interface NotificationContent { data class ReactionContent( val relatedEventId: String ) : MessageLike + data object RoomEncrypted : MessageLike data class RoomMessage( val senderId: UserId, val messageType: MessageType ) : MessageLike + data object RoomRedaction : MessageLike data object Sticker : MessageLike data class Poll( @@ -83,6 +93,7 @@ sealed interface NotificationContent { val userId: String, val membershipState: RoomMembershipState ) : StateEvent + data object RoomName : StateEvent data object RoomPinnedEvents : StateEvent data object RoomPowerLevels : StateEvent diff --git a/libraries/matrix/api/src/test/kotlin/io/element/android/libraries/matrix/api/notification/NotificationDataTest.kt b/libraries/matrix/api/src/test/kotlin/io/element/android/libraries/matrix/api/notification/NotificationDataTest.kt new file mode 100644 index 0000000000..77a4188a68 --- /dev/null +++ b/libraries/matrix/api/src/test/kotlin/io/element/android/libraries/matrix/api/notification/NotificationDataTest.kt @@ -0,0 +1,73 @@ +/* + * Copyright (c) 2023 New Vector Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.element.android.libraries.matrix.api.notification + +import com.google.common.truth.Truth.assertThat +import io.element.android.libraries.matrix.test.AN_EVENT_ID +import io.element.android.libraries.matrix.test.A_ROOM_ID +import io.element.android.libraries.matrix.test.A_USER_ID +import org.junit.Test + +class NotificationDataTest { + @Test + fun `getSenderName should return user id if there is no sender name`() { + val sut = aNotificationData( + senderDisplayName = null, + senderIsNameAmbiguous = false, + ) + assertThat(sut.getSenderName(A_USER_ID)).isEqualTo("@alice:server.org") + } + + @Test + fun `getSenderName should return sender name if defined`() { + val sut = aNotificationData( + senderDisplayName = "Alice", + senderIsNameAmbiguous = false, + ) + assertThat(sut.getSenderName(A_USER_ID)).isEqualTo("Alice") + } + + @Test + fun `getSenderName should return sender name and user id in case of ambiguous display name`() { + val sut = aNotificationData( + senderDisplayName = "Alice", + senderIsNameAmbiguous = true, + ) + assertThat(sut.getSenderName(A_USER_ID)).isEqualTo("Alice (@alice:server.org)") + } + + private fun aNotificationData( + senderDisplayName: String?, + senderIsNameAmbiguous: Boolean, + ): NotificationData { + return NotificationData( + eventId = AN_EVENT_ID, + roomId = A_ROOM_ID, + senderAvatarUrl = null, + senderDisplayName = senderDisplayName, + senderIsNameAmbiguous = senderIsNameAmbiguous, + roomAvatarUrl = null, + roomDisplayName = null, + isDirect = false, + isEncrypted = false, + isNoisy = false, + timestamp = 0L, + content = NotificationContent.MessageLike.RoomEncrypted, + hasMention = false, + ) + } +} diff --git a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/notification/NotificationMapper.kt b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/notification/NotificationMapper.kt index 6285ba393f..4b7c08f9b4 100644 --- a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/notification/NotificationMapper.kt +++ b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/notification/NotificationMapper.kt @@ -45,6 +45,7 @@ class NotificationMapper( roomId = roomId, senderAvatarUrl = item.senderInfo.avatarUrl, senderDisplayName = item.senderInfo.displayName, + senderIsNameAmbiguous = item.senderInfo.isNameAmbiguous, roomAvatarUrl = item.roomInfo.avatarUrl ?: item.senderInfo.avatarUrl.takeIf { item.roomInfo.isDirect }, roomDisplayName = item.roomInfo.displayName, isDirect = item.roomInfo.isDirect, diff --git a/libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/notifications/NotifiableEventResolver.kt b/libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/notifications/NotifiableEventResolver.kt index ebf8ac6a89..31e71dc6c9 100644 --- a/libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/notifications/NotifiableEventResolver.kt +++ b/libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/notifications/NotifiableEventResolver.kt @@ -91,7 +91,8 @@ class NotifiableEventResolver @Inject constructor( ): NotifiableEvent? { return when (val content = this.content) { is NotificationContent.MessageLike.RoomMessage -> { - val messageBody = descriptionFromMessageContent(content, senderDisplayName ?: content.senderId.value) + val senderName = getSenderName(content.senderId) + val messageBody = descriptionFromMessageContent(content, senderName) val notificationBody = if (hasMention) { stringProvider.getString(R.string.notification_mentioned_you_body, messageBody) } else { @@ -104,7 +105,7 @@ class NotifiableEventResolver @Inject constructor( eventId = eventId, noisy = isNoisy, timestamp = this.timestamp, - senderName = senderDisplayName, + senderName = senderName, body = notificationBody, imageUriString = fetchImageIfPresent(client)?.toString(), roomName = roomDisplayName, @@ -161,7 +162,7 @@ class NotifiableEventResolver @Inject constructor( eventId = eventId, noisy = isNoisy, timestamp = this.timestamp, - senderName = senderDisplayName, + senderName = getSenderName(content.senderId), body = stringProvider.getString(CommonStrings.common_poll_summary, content.question), imageUriString = null, roomName = roomDisplayName, diff --git a/libraries/push/impl/src/test/kotlin/io/element/android/libraries/push/impl/notifications/NotifiableEventResolverTest.kt b/libraries/push/impl/src/test/kotlin/io/element/android/libraries/push/impl/notifications/NotifiableEventResolverTest.kt index d824a193d2..7b31afc01e 100644 --- a/libraries/push/impl/src/test/kotlin/io/element/android/libraries/push/impl/notifications/NotifiableEventResolverTest.kt +++ b/libraries/push/impl/src/test/kotlin/io/element/android/libraries/push/impl/notifications/NotifiableEventResolverTest.kt @@ -527,6 +527,7 @@ class NotifiableEventResolverTest { roomId = A_ROOM_ID, senderAvatarUrl = null, senderDisplayName = "Bob", + senderIsNameAmbiguous = false, roomAvatarUrl = null, roomDisplayName = null, isDirect = isDirect, From a11bb6a70c13fa29b6b3bda1043d39098237b393 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 26 Jan 2024 07:35:28 +0000 Subject: [PATCH 105/127] Update dependency org.matrix.rustcomponents:sdk-android to v0.1.94 --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index be695b4d5b..7d8040d34b 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -153,7 +153,7 @@ jsoup = "org.jsoup:jsoup:1.17.2" appyx_core = { module = "com.bumble.appyx:core", version.ref = "appyx" } molecule-runtime = "app.cash.molecule:molecule-runtime:1.3.2" timber = "com.jakewharton.timber:timber:5.0.1" -matrix_sdk = "org.matrix.rustcomponents:sdk-android:0.1.92" +matrix_sdk = "org.matrix.rustcomponents:sdk-android:0.1.94" matrix_richtexteditor = { module = "io.element.android:wysiwyg", version.ref = "wysiwyg" } matrix_richtexteditor_compose = { module = "io.element.android:wysiwyg-compose", version.ref = "wysiwyg" } sqldelight-driver-android = { module = "app.cash.sqldelight:android-driver", version.ref = "sqldelight" } From 1154efd77a102e31a1d5d80b88534591f2d09a6a Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Fri, 26 Jan 2024 08:48:31 +0100 Subject: [PATCH 106/127] Changelog. --- changelog.d/2224.misc | 1 + 1 file changed, 1 insertion(+) create mode 100644 changelog.d/2224.misc diff --git a/changelog.d/2224.misc b/changelog.d/2224.misc new file mode 100644 index 0000000000..6ec471f392 --- /dev/null +++ b/changelog.d/2224.misc @@ -0,0 +1 @@ +Disambiguate display name in notifications From b7945675c9b321bb032fb77f338f2095b1e4541f Mon Sep 17 00:00:00 2001 From: Jorge Martin Espinosa Date: Fri, 26 Jan 2024 10:05:30 +0100 Subject: [PATCH 107/127] Add a special tracing configuration for nightlies (#2297) It also enables logging `MATRIX_SDK_BASE_READ_RECEIPTS` at a `TRACE` level for both debug and nightly versions. --- .../android/x/initializer/TracingInitializer.kt | 7 ++++++- ...-special-tracing-configuration-for-nightlies.misc | 1 + .../matrix/api/tracing/TracingFilterConfiguration.kt | 12 ++++++++++-- 3 files changed, 17 insertions(+), 3 deletions(-) create mode 100644 changelog.d/+add-special-tracing-configuration-for-nightlies.misc diff --git a/app/src/main/kotlin/io/element/android/x/initializer/TracingInitializer.kt b/app/src/main/kotlin/io/element/android/x/initializer/TracingInitializer.kt index 5a7bf0fb82..7afcc49e6d 100644 --- a/app/src/main/kotlin/io/element/android/x/initializer/TracingInitializer.kt +++ b/app/src/main/kotlin/io/element/android/x/initializer/TracingInitializer.kt @@ -46,8 +46,13 @@ class TracingInitializer : Initializer { writesToFilesConfiguration = WriteToFilesConfiguration.Disabled ) } else { + val config = if (BuildConfig.BUILD_TYPE == "nightly") { + TracingFilterConfigurations.nightly + } else { + TracingFilterConfigurations.release + } TracingConfiguration( - filterConfiguration = TracingFilterConfigurations.release, + filterConfiguration = config, writesToLogcat = false, writesToFilesConfiguration = WriteToFilesConfiguration.Enabled( directory = bugReporter.logDirectory().absolutePath, diff --git a/changelog.d/+add-special-tracing-configuration-for-nightlies.misc b/changelog.d/+add-special-tracing-configuration-for-nightlies.misc new file mode 100644 index 0000000000..89f72f4332 --- /dev/null +++ b/changelog.d/+add-special-tracing-configuration-for-nightlies.misc @@ -0,0 +1 @@ +Add a special logging configuration for nightlies so we can get more detailed info for existing issues. diff --git a/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/tracing/TracingFilterConfiguration.kt b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/tracing/TracingFilterConfiguration.kt index 5cd6750552..114c7df0cb 100644 --- a/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/tracing/TracingFilterConfiguration.kt +++ b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/tracing/TracingFilterConfiguration.kt @@ -29,6 +29,7 @@ data class TracingFilterConfiguration( Target.MATRIX_SDK_SLIDING_SYNC to LogLevel.TRACE, Target.MATRIX_SDK_BASE_SLIDING_SYNC to LogLevel.TRACE, Target.MATRIX_SDK_UI_TIMELINE to LogLevel.TRACE, + Target.MATRIX_SDK_BASE_READ_RECEIPTS to LogLevel.TRACE, ) fun getLogLevel(target: Target): LogLevel { @@ -37,7 +38,7 @@ data class TracingFilterConfiguration( val filter: String get() { - val fullMap = Target.values().associateWith { + val fullMap = Target.entries.associateWith { overrides[it] ?: targetsToLogLevel[it] ?: defaultLogLevel } return fullMap.map { @@ -64,6 +65,7 @@ enum class Target(open val filter: String) { MATRIX_SDK_SLIDING_SYNC("matrix_sdk::sliding_sync"), MATRIX_SDK_BASE_SLIDING_SYNC("matrix_sdk_base::sliding_sync"), MATRIX_SDK_UI_TIMELINE("matrix_sdk_ui::timeline"), + MATRIX_SDK_BASE_READ_RECEIPTS("matrix_sdk_base::read_receipts"), } enum class LogLevel(open val filter: String) { @@ -80,6 +82,12 @@ object TracingFilterConfigurations { Target.ELEMENT to LogLevel.DEBUG ), ) + val nightly = TracingFilterConfiguration( + overrides = mapOf( + Target.ELEMENT to LogLevel.TRACE, + Target.MATRIX_SDK_BASE_READ_RECEIPTS to LogLevel.TRACE, + ), + ) val debug = TracingFilterConfiguration( overrides = mapOf( Target.ELEMENT to LogLevel.TRACE @@ -89,7 +97,7 @@ object TracingFilterConfigurations { /** * Use this method to create a custom configuration where all targets will have the same log level. */ - fun custom(logLevel: LogLevel) = TracingFilterConfiguration(overrides = Target.values().associateWith { logLevel }) + fun custom(logLevel: LogLevel) = TracingFilterConfiguration(overrides = Target.entries.associateWith { logLevel }) /** * Use this method to override the log level of specific targets. From 7e58f719fee4f31022a122e25a2792d0717e17a5 Mon Sep 17 00:00:00 2001 From: Jorge Martin Espinosa Date: Fri, 26 Jan 2024 10:06:26 +0100 Subject: [PATCH 108/127] Add 'send private read receipts' option in advanced settings (#2290) * Add 'send private read receipts' option in advanced settings * Create `SessionPreferencesStore` that stores the settings for the current use separate from those of the app. * Rename `PreferencesStore` to `AppPreferencesStore` to split the preferences. --------- Co-authored-by: ElementBot --- .../io/element/android/x/di/AppBindings.kt | 4 +- changelog.d/2204.feature | 1 + .../features/call/ui/ElementCallActivity.kt | 6 +- .../call/utils/DefaultCallWidgetProvider.kt | 6 +- .../utils/DefaultCallWidgetProviderTest.kt | 12 ++-- .../messages/impl/MessagesPresenter.kt | 6 +- .../impl/actionlist/ActionListPresenter.kt | 6 +- .../impl/timeline/TimelinePresenter.kt | 10 ++- .../messages/impl/MessagesPresenterTest.kt | 11 ++-- .../actionlist/ActionListPresenterTest.kt | 6 +- .../impl/timeline/TimelinePresenterTest.kt | 44 +++++++++++-- .../impl/advanced/AdvancedSettingsEvents.kt | 1 + .../advanced/AdvancedSettingsPresenter.kt | 25 +++++--- .../impl/advanced/AdvancedSettingsState.kt | 1 + .../advanced/AdvancedSettingsStateProvider.kt | 3 + .../impl/advanced/AdvancedSettingsView.kt | 12 ++++ .../developer/DeveloperSettingsPresenter.kt | 8 +-- .../impl/src/main/res/values/localazy.xml | 2 + .../advanced/AdvancedSettingsPresenterTest.kt | 39 +++++++++--- .../DeveloperSettingsPresenterTest.kt | 8 +-- .../test/timeline/FakeMatrixTimeline.kt | 4 +- ...erencesStore.kt => AppPreferencesStore.kt} | 2 +- .../api/store/SessionPreferencesStore.kt | 26 ++++++++ libraries/preferences/impl/build.gradle.kts | 2 + ...Store.kt => DefaultAppPreferencesStore.kt} | 6 +- .../store/DefaultSessionPreferencesStore.kt | 63 +++++++++++++++++++ ...tore.kt => InMemoryAppPreferencesStore.kt} | 6 +- .../test/InMemorySessionPreferencesStore.kt | 41 ++++++++++++ ...ngsView-Day-1_2_null_0,NEXUS_5,1.0,en].png | 4 +- ...ngsView-Day-1_2_null_1,NEXUS_5,1.0,en].png | 4 +- ...ngsView-Day-1_2_null_2,NEXUS_5,1.0,en].png | 4 +- ...ngsView-Day-1_2_null_3,NEXUS_5,1.0,en].png | 4 +- ...ngsView-Day-1_2_null_4,NEXUS_5,1.0,en].png | 3 + ...sView-Night-1_3_null_0,NEXUS_5,1.0,en].png | 4 +- ...sView-Night-1_3_null_1,NEXUS_5,1.0,en].png | 4 +- ...sView-Night-1_3_null_2,NEXUS_5,1.0,en].png | 4 +- ...sView-Night-1_3_null_3,NEXUS_5,1.0,en].png | 4 +- ...sView-Night-1_3_null_4,NEXUS_5,1.0,en].png | 3 + 38 files changed, 314 insertions(+), 85 deletions(-) create mode 100644 changelog.d/2204.feature rename libraries/preferences/api/src/main/kotlin/io/element/android/features/preferences/api/store/{PreferencesStore.kt => AppPreferencesStore.kt} (97%) create mode 100644 libraries/preferences/api/src/main/kotlin/io/element/android/features/preferences/api/store/SessionPreferencesStore.kt rename libraries/preferences/impl/src/main/kotlin/io/element/android/libraries/preferences/impl/store/{DefaultPreferencesStore.kt => DefaultAppPreferencesStore.kt} (95%) create mode 100644 libraries/preferences/impl/src/main/kotlin/io/element/android/libraries/preferences/impl/store/DefaultSessionPreferencesStore.kt rename libraries/preferences/test/src/main/kotlin/io/element/android/libraries/featureflag/test/{InMemoryPreferencesStore.kt => InMemoryAppPreferencesStore.kt} (93%) create mode 100644 libraries/preferences/test/src/main/kotlin/io/element/android/libraries/featureflag/test/InMemorySessionPreferencesStore.kt create mode 100644 tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.advanced_AdvancedSettingsView_null_AdvancedSettingsView-Day-1_2_null_4,NEXUS_5,1.0,en].png create mode 100644 tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.advanced_AdvancedSettingsView_null_AdvancedSettingsView-Night-1_3_null_4,NEXUS_5,1.0,en].png diff --git a/app/src/main/kotlin/io/element/android/x/di/AppBindings.kt b/app/src/main/kotlin/io/element/android/x/di/AppBindings.kt index a6ce26c237..0934771501 100644 --- a/app/src/main/kotlin/io/element/android/x/di/AppBindings.kt +++ b/app/src/main/kotlin/io/element/android/x/di/AppBindings.kt @@ -18,7 +18,7 @@ package io.element.android.x.di import com.squareup.anvil.annotations.ContributesTo import io.element.android.features.lockscreen.api.LockScreenService -import io.element.android.features.preferences.api.store.PreferencesStore +import io.element.android.features.preferences.api.store.AppPreferencesStore import io.element.android.features.rageshake.api.reporter.BugReporter import io.element.android.libraries.designsystem.utils.snackbar.SnackbarDispatcher import io.element.android.libraries.di.AppScope @@ -34,5 +34,5 @@ interface AppBindings { fun lockScreenService(): LockScreenService - fun preferencesStore(): PreferencesStore + fun preferencesStore(): AppPreferencesStore } diff --git a/changelog.d/2204.feature b/changelog.d/2204.feature new file mode 100644 index 0000000000..0a26acc5de --- /dev/null +++ b/changelog.d/2204.feature @@ -0,0 +1 @@ +Add 'send private read receipts' option in advanced settings diff --git a/features/call/src/main/kotlin/io/element/android/features/call/ui/ElementCallActivity.kt b/features/call/src/main/kotlin/io/element/android/features/call/ui/ElementCallActivity.kt index 2729d71a7e..8eea4c814f 100644 --- a/features/call/src/main/kotlin/io/element/android/features/call/ui/ElementCallActivity.kt +++ b/features/call/src/main/kotlin/io/element/android/features/call/ui/ElementCallActivity.kt @@ -45,7 +45,7 @@ import io.element.android.features.call.CallForegroundService import io.element.android.features.call.CallType import io.element.android.features.call.di.CallBindings import io.element.android.features.call.utils.CallIntentDataParser -import io.element.android.features.preferences.api.store.PreferencesStore +import io.element.android.features.preferences.api.store.AppPreferencesStore import io.element.android.libraries.architecture.bindings import javax.inject.Inject @@ -67,7 +67,7 @@ class ElementCallActivity : NodeComponentActivity(), CallScreenNavigator { @Inject lateinit var callIntentDataParser: CallIntentDataParser @Inject lateinit var presenterFactory: CallScreenPresenter.Factory - @Inject lateinit var preferencesStore: PreferencesStore + @Inject lateinit var appPreferencesStore: AppPreferencesStore private lateinit var presenter: CallScreenPresenter @@ -101,7 +101,7 @@ class ElementCallActivity : NodeComponentActivity(), CallScreenNavigator { setContent { val theme by remember { - preferencesStore.getThemeFlow().mapToTheme() + appPreferencesStore.getThemeFlow().mapToTheme() } .collectAsState(initial = Theme.System) val state = presenter.present() diff --git a/features/call/src/main/kotlin/io/element/android/features/call/utils/DefaultCallWidgetProvider.kt b/features/call/src/main/kotlin/io/element/android/features/call/utils/DefaultCallWidgetProvider.kt index f3cb9cbcd5..cc6e2a299f 100644 --- a/features/call/src/main/kotlin/io/element/android/features/call/utils/DefaultCallWidgetProvider.kt +++ b/features/call/src/main/kotlin/io/element/android/features/call/utils/DefaultCallWidgetProvider.kt @@ -18,7 +18,7 @@ package io.element.android.features.call.utils import com.squareup.anvil.annotations.ContributesBinding import io.element.android.appconfig.ElementCallConfig -import io.element.android.features.preferences.api.store.PreferencesStore +import io.element.android.features.preferences.api.store.AppPreferencesStore import io.element.android.libraries.di.AppScope import io.element.android.libraries.matrix.api.MatrixClientProvider import io.element.android.libraries.matrix.api.core.RoomId @@ -31,7 +31,7 @@ import javax.inject.Inject @ContributesBinding(AppScope::class) class DefaultCallWidgetProvider @Inject constructor( private val matrixClientsProvider: MatrixClientProvider, - private val preferencesStore: PreferencesStore, + private val appPreferencesStore: AppPreferencesStore, private val callWidgetSettingsProvider: CallWidgetSettingsProvider, ) : CallWidgetProvider { override suspend fun getWidget( @@ -42,7 +42,7 @@ class DefaultCallWidgetProvider @Inject constructor( theme: String?, ): Result> = runCatching { val room = matrixClientsProvider.getOrRestore(sessionId).getOrThrow().getRoom(roomId) ?: error("Room not found") - val baseUrl = preferencesStore.getCustomElementCallBaseUrlFlow().firstOrNull() ?: ElementCallConfig.DEFAULT_BASE_URL + val baseUrl = appPreferencesStore.getCustomElementCallBaseUrlFlow().firstOrNull() ?: ElementCallConfig.DEFAULT_BASE_URL val widgetSettings = callWidgetSettingsProvider.provide(baseUrl) val callUrl = room.generateWidgetWebViewUrl(widgetSettings, clientId, languageTag, theme).getOrThrow() room.getWidgetDriver(widgetSettings).getOrThrow() to callUrl diff --git a/features/call/src/test/kotlin/io/element/android/features/call/utils/DefaultCallWidgetProviderTest.kt b/features/call/src/test/kotlin/io/element/android/features/call/utils/DefaultCallWidgetProviderTest.kt index 50d8c54998..31f6327d2f 100644 --- a/features/call/src/test/kotlin/io/element/android/features/call/utils/DefaultCallWidgetProviderTest.kt +++ b/features/call/src/test/kotlin/io/element/android/features/call/utils/DefaultCallWidgetProviderTest.kt @@ -17,8 +17,8 @@ package io.element.android.features.call.utils import com.google.common.truth.Truth.assertThat -import io.element.android.features.preferences.api.store.PreferencesStore -import io.element.android.libraries.featureflag.test.InMemoryPreferencesStore +import io.element.android.features.preferences.api.store.AppPreferencesStore +import io.element.android.libraries.featureflag.test.InMemoryAppPreferencesStore import io.element.android.libraries.matrix.api.MatrixClientProvider import io.element.android.libraries.matrix.api.widget.CallWidgetSettingsProvider import io.element.android.libraries.matrix.test.A_ROOM_ID @@ -94,14 +94,14 @@ class DefaultCallWidgetProviderTest { val client = FakeMatrixClient().apply { givenGetRoomResult(A_ROOM_ID, room) } - val preferencesStore = InMemoryPreferencesStore().apply { + val preferencesStore = InMemoryAppPreferencesStore().apply { setCustomElementCallBaseUrl("https://custom.element.io") } val settingsProvider = FakeCallWidgetSettingsProvider() val provider = createProvider( matrixClientProvider = FakeMatrixClientProvider { Result.success(client) }, callWidgetSettingsProvider = settingsProvider, - preferencesStore = preferencesStore, + appPreferencesStore = preferencesStore, ) provider.getWidget(A_SESSION_ID, A_ROOM_ID, "clientId", "languageTag", "theme") @@ -110,11 +110,11 @@ class DefaultCallWidgetProviderTest { private fun createProvider( matrixClientProvider: MatrixClientProvider = FakeMatrixClientProvider(), - preferencesStore: PreferencesStore = InMemoryPreferencesStore(), + appPreferencesStore: AppPreferencesStore = InMemoryAppPreferencesStore(), callWidgetSettingsProvider: CallWidgetSettingsProvider = FakeCallWidgetSettingsProvider() ) = DefaultCallWidgetProvider( matrixClientProvider, - preferencesStore, + appPreferencesStore, callWidgetSettingsProvider, ) } diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/MessagesPresenter.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/MessagesPresenter.kt index 07eeda2efa..262f6cc6b2 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/MessagesPresenter.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/MessagesPresenter.kt @@ -63,7 +63,7 @@ import io.element.android.features.messages.impl.utils.messagesummary.MessageSum import io.element.android.features.messages.impl.voicemessages.composer.VoiceMessageComposerPresenter import io.element.android.features.networkmonitor.api.NetworkMonitor import io.element.android.features.networkmonitor.api.NetworkStatus -import io.element.android.features.preferences.api.store.PreferencesStore +import io.element.android.features.preferences.api.store.AppPreferencesStore import io.element.android.libraries.androidutils.clipboard.ClipboardHelper import io.element.android.libraries.architecture.AsyncData import io.element.android.libraries.architecture.Presenter @@ -108,7 +108,7 @@ class MessagesPresenter @AssistedInject constructor( private val messageSummaryFormatter: MessageSummaryFormatter, private val dispatchers: CoroutineDispatchers, private val clipboardHelper: ClipboardHelper, - private val preferencesStore: PreferencesStore, + private val appPreferencesStore: AppPreferencesStore, private val featureFlagsService: FeatureFlagService, private val htmlConverterProvider: HtmlConverterProvider, @Assisted private val navigator: MessagesNavigator, @@ -178,7 +178,7 @@ class MessagesPresenter @AssistedInject constructor( timelineState.eventSink(TimelineEvents.SetHighlightedEvent(composerState.mode.relatedEventId)) } - val enableTextFormatting by preferencesStore.isRichTextEditorEnabledFlow().collectAsState(initial = true) + val enableTextFormatting by appPreferencesStore.isRichTextEditorEnabledFlow().collectAsState(initial = true) var enableVoiceMessages by remember { mutableStateOf(false) } LaunchedEffect(featureFlagsService) { diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/actionlist/ActionListPresenter.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/actionlist/ActionListPresenter.kt index f753266062..c5d449b288 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/actionlist/ActionListPresenter.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/actionlist/ActionListPresenter.kt @@ -31,7 +31,7 @@ import io.element.android.features.messages.impl.timeline.model.event.TimelineIt import io.element.android.features.messages.impl.timeline.model.event.TimelineItemVoiceContent import io.element.android.features.messages.impl.timeline.model.event.canBeCopied import io.element.android.features.messages.impl.timeline.model.event.canReact -import io.element.android.features.preferences.api.store.PreferencesStore +import io.element.android.features.preferences.api.store.AppPreferencesStore import io.element.android.libraries.architecture.Presenter import kotlinx.collections.immutable.toImmutableList import kotlinx.coroutines.CoroutineScope @@ -39,7 +39,7 @@ import kotlinx.coroutines.launch import javax.inject.Inject class ActionListPresenter @Inject constructor( - private val preferencesStore: PreferencesStore, + private val appPreferencesStore: AppPreferencesStore, ) : Presenter { @Composable override fun present(): ActionListState { @@ -49,7 +49,7 @@ class ActionListPresenter @Inject constructor( mutableStateOf(ActionListState.Target.None) } - val isDeveloperModeEnabled by preferencesStore.isDeveloperModeEnabledFlow().collectAsState(initial = false) + val isDeveloperModeEnabled by appPreferencesStore.isDeveloperModeEnabledFlow().collectAsState(initial = false) fun handleEvents(event: ActionListEvents) { when (event) { diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/TimelinePresenter.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/TimelinePresenter.kt index f1f934c4ba..a0d7ebf771 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/TimelinePresenter.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/TimelinePresenter.kt @@ -38,6 +38,7 @@ import io.element.android.features.messages.impl.timeline.session.SessionState import io.element.android.features.messages.impl.voicemessages.timeline.RedactedVoiceMessageManager import io.element.android.features.poll.api.actions.EndPollAction import io.element.android.features.poll.api.actions.SendPollResponseAction +import io.element.android.features.preferences.api.store.SessionPreferencesStore import io.element.android.libraries.architecture.Presenter import io.element.android.libraries.core.coroutine.CoroutineDispatchers import io.element.android.libraries.matrix.api.core.EventId @@ -73,6 +74,7 @@ class TimelinePresenter @AssistedInject constructor( private val redactedVoiceMessageManager: RedactedVoiceMessageManager, private val sendPollResponseAction: SendPollResponseAction, private val endPollAction: EndPollAction, + private val sessionPreferencesStore: SessionPreferencesStore, ) : Presenter { @AssistedFactory interface Factory { @@ -103,6 +105,8 @@ class TimelinePresenter @AssistedInject constructor( val sessionVerifiedStatus by verificationService.sessionVerifiedStatus.collectAsState() val keyBackupState by encryptionService.backupStateStateFlow.collectAsState() + val isSendPublicReadReceiptsEnabled by sessionPreferencesStore.isSendPublicReadReceiptsEnabled().collectAsState(initial = true) + val sessionState by remember { derivedStateOf { SessionState( @@ -124,7 +128,8 @@ class TimelinePresenter @AssistedInject constructor( firstVisibleIndex = event.firstIndex, timelineItems = timelineItems, lastReadReceiptIndex = lastReadReceiptIndex, - lastReadReceiptId = lastReadReceiptId + lastReadReceiptId = lastReadReceiptId, + readReceiptType = if (isSendPublicReadReceiptsEnabled) ReceiptType.READ else ReceiptType.READ_PRIVATE, ) } is TimelineEvents.PollAnswerSelected -> appScope.launch { @@ -223,13 +228,14 @@ class TimelinePresenter @AssistedInject constructor( timelineItems: ImmutableList, lastReadReceiptIndex: MutableState, lastReadReceiptId: MutableState, + readReceiptType: ReceiptType, ) = launch(dispatchers.computation) { // Get last valid EventId seen by the user, as the first index might refer to a Virtual item val eventId = getLastEventIdBeforeOrAt(firstVisibleIndex, timelineItems) if (eventId != null && firstVisibleIndex <= lastReadReceiptIndex.value && eventId != lastReadReceiptId.value) { lastReadReceiptIndex.value = firstVisibleIndex lastReadReceiptId.value = eventId - timeline.sendReadReceipt(eventId = eventId, receiptType = ReceiptType.READ) + timeline.sendReadReceipt(eventId = eventId, receiptType = readReceiptType) } } diff --git a/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/MessagesPresenterTest.kt b/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/MessagesPresenterTest.kt index 67bbb98e73..08eaf15f7b 100644 --- a/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/MessagesPresenterTest.kt +++ b/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/MessagesPresenterTest.kt @@ -59,7 +59,8 @@ import io.element.android.libraries.designsystem.components.avatar.AvatarSize import io.element.android.libraries.designsystem.utils.snackbar.SnackbarDispatcher import io.element.android.libraries.featureflag.api.FeatureFlags import io.element.android.libraries.featureflag.test.FakeFeatureFlagService -import io.element.android.libraries.featureflag.test.InMemoryPreferencesStore +import io.element.android.libraries.featureflag.test.InMemoryAppPreferencesStore +import io.element.android.libraries.featureflag.test.InMemorySessionPreferencesStore import io.element.android.libraries.matrix.api.media.MediaSource import io.element.android.libraries.matrix.api.room.MatrixRoom import io.element.android.libraries.matrix.api.room.MatrixRoomMembersState @@ -668,6 +669,8 @@ class MessagesPresenterTest { ): MessagesPresenter { val mediaSender = MediaSender(FakeMediaPreProcessor(), matrixRoom) val permissionsPresenterFactory = FakePermissionsPresenterFactory(permissionsPresenter) + val appPreferencesStore = InMemoryAppPreferencesStore(isRichTextEditorEnabled = true) + val sessionPreferencesStore = InMemorySessionPreferencesStore() val messageComposerPresenter = MessageComposerPresenter( appCoroutineScope = this, room = matrixRoom, @@ -702,14 +705,14 @@ class MessagesPresenterTest { redactedVoiceMessageManager = FakeRedactedVoiceMessageManager(), endPollAction = FakeEndPollAction(), sendPollResponseAction = FakeSendPollResponseAction(), + sessionPreferencesStore = sessionPreferencesStore, ) val timelinePresenterFactory = object : TimelinePresenter.Factory { override fun create(navigator: MessagesNavigator): TimelinePresenter { return timelinePresenter } } - val preferencesStore = InMemoryPreferencesStore(isRichTextEditorEnabled = true) - val actionListPresenter = ActionListPresenter(preferencesStore = preferencesStore) + val actionListPresenter = ActionListPresenter(appPreferencesStore = appPreferencesStore) val readReceiptBottomSheetPresenter = ReadReceiptBottomSheetPresenter() val customReactionPresenter = CustomReactionPresenter(emojibaseProvider = FakeEmojibaseProvider()) val reactionSummaryPresenter = ReactionSummaryPresenter(room = matrixRoom) @@ -729,7 +732,7 @@ class MessagesPresenterTest { messageSummaryFormatter = FakeMessageSummaryFormatter(), navigator = navigator, clipboardHelper = clipboardHelper, - preferencesStore = preferencesStore, + appPreferencesStore = appPreferencesStore, featureFlagsService = FakeFeatureFlagService(), buildMeta = aBuildMeta(), dispatchers = coroutineDispatchers, diff --git a/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/actionlist/ActionListPresenterTest.kt b/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/actionlist/ActionListPresenterTest.kt index 0132b449df..981e8fc8ac 100644 --- a/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/actionlist/ActionListPresenterTest.kt +++ b/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/actionlist/ActionListPresenterTest.kt @@ -30,7 +30,7 @@ import io.element.android.features.messages.impl.timeline.model.event.aTimelineI import io.element.android.features.messages.impl.timeline.model.event.aTimelineItemStateEventContent import io.element.android.features.messages.impl.timeline.model.event.aTimelineItemVoiceContent import io.element.android.features.poll.api.pollcontent.aPollAnswerItemList -import io.element.android.libraries.featureflag.test.InMemoryPreferencesStore +import io.element.android.libraries.featureflag.test.InMemoryAppPreferencesStore import io.element.android.libraries.matrix.test.A_MESSAGE import io.element.android.tests.testutils.WarmUpRule import kotlinx.collections.immutable.persistentListOf @@ -747,6 +747,6 @@ class ActionListPresenterTest { } private fun createActionListPresenter(isDeveloperModeEnabled: Boolean): ActionListPresenter { - val preferencesStore = InMemoryPreferencesStore(isDeveloperModeEnabled = isDeveloperModeEnabled) - return ActionListPresenter(preferencesStore = preferencesStore) + val preferencesStore = InMemoryAppPreferencesStore(isDeveloperModeEnabled = isDeveloperModeEnabled) + return ActionListPresenter(appPreferencesStore = preferencesStore) } diff --git a/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/timeline/TimelinePresenterTest.kt b/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/timeline/TimelinePresenterTest.kt index be06965fa6..c01135fb5f 100644 --- a/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/timeline/TimelinePresenterTest.kt +++ b/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/timeline/TimelinePresenterTest.kt @@ -35,9 +35,11 @@ import io.element.android.features.poll.api.actions.SendPollResponseAction import io.element.android.features.poll.test.actions.FakeEndPollAction import io.element.android.features.poll.test.actions.FakeSendPollResponseAction import io.element.android.libraries.featureflag.api.FeatureFlags +import io.element.android.libraries.featureflag.test.InMemorySessionPreferencesStore import io.element.android.libraries.matrix.api.room.MatrixRoomMembersState import io.element.android.libraries.matrix.api.timeline.MatrixTimeline import io.element.android.libraries.matrix.api.timeline.MatrixTimelineItem +import io.element.android.libraries.matrix.api.timeline.ReceiptType import io.element.android.libraries.matrix.api.timeline.item.event.EventReaction import io.element.android.libraries.matrix.api.timeline.item.event.ReactionSender import io.element.android.libraries.matrix.api.timeline.item.event.Receipt @@ -134,13 +136,41 @@ class TimelinePresenterTest { moleculeFlow(RecompositionMode.Immediate) { presenter.present() }.test { - assertThat(timeline.sendReadReceiptCount).isEqualTo(0) + assertThat(timeline.sentReadReceipts).isEmpty() val initialState = awaitFirstItem() awaitWithLatch { latch -> timeline.sendReadReceiptLatch = latch initialState.eventSink.invoke(TimelineEvents.OnScrollFinished(0)) } - assertThat(timeline.sendReadReceiptCount).isEqualTo(1) + assertThat(timeline.sentReadReceipts).isNotEmpty() + assertThat(timeline.sentReadReceipts.first().second).isEqualTo(ReceiptType.READ) + cancelAndIgnoreRemainingEvents() + } + } + + @Test + fun `present - on scroll finished send a private read receipt if an event is before the index and public read receipts are disabled`() = runTest { + val timeline = FakeMatrixTimeline( + initialTimelineItems = listOf( + MatrixTimelineItem.Event(FAKE_UNIQUE_ID, anEventTimelineItem()) + ) + ) + val sessionPreferencesStore = InMemorySessionPreferencesStore(isSendPublicReadReceiptsEnabled = false) + val presenter = createTimelinePresenter( + timeline = timeline, + sessionPreferencesStore = sessionPreferencesStore, + ) + moleculeFlow(RecompositionMode.Immediate) { + presenter.present() + }.test { + assertThat(timeline.sentReadReceipts).isEmpty() + val initialState = awaitFirstItem() + awaitWithLatch { latch -> + timeline.sendReadReceiptLatch = latch + initialState.eventSink.invoke(TimelineEvents.OnScrollFinished(0)) + } + assertThat(timeline.sentReadReceipts).isNotEmpty() + assertThat(timeline.sentReadReceipts.first().second).isEqualTo(ReceiptType.READ_PRIVATE) cancelAndIgnoreRemainingEvents() } } @@ -156,13 +186,13 @@ class TimelinePresenterTest { moleculeFlow(RecompositionMode.Immediate) { presenter.present() }.test { - assertThat(timeline.sendReadReceiptCount).isEqualTo(0) + assertThat(timeline.sentReadReceipts).isEmpty() val initialState = awaitFirstItem() awaitWithLatch { latch -> timeline.sendReadReceiptLatch = latch initialState.eventSink.invoke(TimelineEvents.OnScrollFinished(1)) } - assertThat(timeline.sendReadReceiptCount).isEqualTo(0) + assertThat(timeline.sentReadReceipts).isEmpty() cancelAndIgnoreRemainingEvents() } } @@ -178,13 +208,13 @@ class TimelinePresenterTest { moleculeFlow(RecompositionMode.Immediate) { presenter.present() }.test { - assertThat(timeline.sendReadReceiptCount).isEqualTo(0) + assertThat(timeline.sentReadReceipts).isEmpty() val initialState = awaitFirstItem() awaitWithLatch { latch -> timeline.sendReadReceiptLatch = latch initialState.eventSink.invoke(TimelineEvents.OnScrollFinished(0)) } - assertThat(timeline.sendReadReceiptCount).isEqualTo(0) + assertThat(timeline.sentReadReceipts).isEmpty() cancelAndIgnoreRemainingEvents() } } @@ -418,6 +448,7 @@ class TimelinePresenterTest { messagesNavigator: FakeMessagesNavigator = FakeMessagesNavigator(), endPollAction: EndPollAction = FakeEndPollAction(), sendPollResponseAction: SendPollResponseAction = FakeSendPollResponseAction(), + sessionPreferencesStore: InMemorySessionPreferencesStore = InMemorySessionPreferencesStore(), ): TimelinePresenter { return TimelinePresenter( timelineItemsFactory = timelineItemsFactory, @@ -430,6 +461,7 @@ class TimelinePresenterTest { redactedVoiceMessageManager = redactedVoiceMessageManager, endPollAction = endPollAction, sendPollResponseAction = sendPollResponseAction, + sessionPreferencesStore = sessionPreferencesStore, ) } } diff --git a/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/advanced/AdvancedSettingsEvents.kt b/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/advanced/AdvancedSettingsEvents.kt index f22a653f6d..d67a594dd2 100644 --- a/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/advanced/AdvancedSettingsEvents.kt +++ b/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/advanced/AdvancedSettingsEvents.kt @@ -21,6 +21,7 @@ import io.element.android.compound.theme.Theme sealed interface AdvancedSettingsEvents { data class SetRichTextEditorEnabled(val enabled: Boolean) : AdvancedSettingsEvents data class SetDeveloperModeEnabled(val enabled: Boolean) : AdvancedSettingsEvents + data class SetSendPublicReadReceiptsEnabled(val enabled: Boolean) : AdvancedSettingsEvents data object ChangeTheme : AdvancedSettingsEvents data object CancelChangeTheme : AdvancedSettingsEvents data class SetTheme(val theme: Theme) : AdvancedSettingsEvents diff --git a/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/advanced/AdvancedSettingsPresenter.kt b/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/advanced/AdvancedSettingsPresenter.kt index ce5de0b8e8..2ac5b664b5 100644 --- a/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/advanced/AdvancedSettingsPresenter.kt +++ b/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/advanced/AdvancedSettingsPresenter.kt @@ -25,40 +25,48 @@ import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.runtime.setValue import io.element.android.compound.theme.Theme import io.element.android.compound.theme.mapToTheme -import io.element.android.features.preferences.api.store.PreferencesStore +import io.element.android.features.preferences.api.store.AppPreferencesStore +import io.element.android.features.preferences.api.store.SessionPreferencesStore import io.element.android.libraries.architecture.Presenter import kotlinx.coroutines.launch import javax.inject.Inject class AdvancedSettingsPresenter @Inject constructor( - private val preferencesStore: PreferencesStore, + private val appPreferencesStore: AppPreferencesStore, + private val sessionPreferencesStore: SessionPreferencesStore, ) : Presenter { @Composable override fun present(): AdvancedSettingsState { val localCoroutineScope = rememberCoroutineScope() - val isRichTextEditorEnabled by preferencesStore + val isRichTextEditorEnabled by appPreferencesStore .isRichTextEditorEnabledFlow() .collectAsState(initial = false) - val isDeveloperModeEnabled by preferencesStore + val isDeveloperModeEnabled by appPreferencesStore .isDeveloperModeEnabledFlow() .collectAsState(initial = false) + val isSendPublicReadReceiptsEnabled by sessionPreferencesStore + .isSendPublicReadReceiptsEnabled() + .collectAsState(initial = true) val theme by remember { - preferencesStore.getThemeFlow().mapToTheme() + appPreferencesStore.getThemeFlow().mapToTheme() } .collectAsState(initial = Theme.System) var showChangeThemeDialog by remember { mutableStateOf(false) } fun handleEvents(event: AdvancedSettingsEvents) { when (event) { is AdvancedSettingsEvents.SetRichTextEditorEnabled -> localCoroutineScope.launch { - preferencesStore.setRichTextEditorEnabled(event.enabled) + appPreferencesStore.setRichTextEditorEnabled(event.enabled) } is AdvancedSettingsEvents.SetDeveloperModeEnabled -> localCoroutineScope.launch { - preferencesStore.setDeveloperModeEnabled(event.enabled) + appPreferencesStore.setDeveloperModeEnabled(event.enabled) + } + is AdvancedSettingsEvents.SetSendPublicReadReceiptsEnabled -> localCoroutineScope.launch { + sessionPreferencesStore.setSendPublicReadReceipts(event.enabled) } AdvancedSettingsEvents.CancelChangeTheme -> showChangeThemeDialog = false AdvancedSettingsEvents.ChangeTheme -> showChangeThemeDialog = true is AdvancedSettingsEvents.SetTheme -> localCoroutineScope.launch { - preferencesStore.setTheme(event.theme.name) + appPreferencesStore.setTheme(event.theme.name) showChangeThemeDialog = false } } @@ -67,6 +75,7 @@ class AdvancedSettingsPresenter @Inject constructor( return AdvancedSettingsState( isRichTextEditorEnabled = isRichTextEditorEnabled, isDeveloperModeEnabled = isDeveloperModeEnabled, + isSendPublicReadReceiptsEnabled = isSendPublicReadReceiptsEnabled, theme = theme, showChangeThemeDialog = showChangeThemeDialog, eventSink = { handleEvents(it) } diff --git a/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/advanced/AdvancedSettingsState.kt b/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/advanced/AdvancedSettingsState.kt index 01d702224f..0ea04185f7 100644 --- a/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/advanced/AdvancedSettingsState.kt +++ b/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/advanced/AdvancedSettingsState.kt @@ -21,6 +21,7 @@ import io.element.android.compound.theme.Theme data class AdvancedSettingsState( val isRichTextEditorEnabled: Boolean, val isDeveloperModeEnabled: Boolean, + val isSendPublicReadReceiptsEnabled: Boolean, val theme: Theme, val showChangeThemeDialog: Boolean, val eventSink: (AdvancedSettingsEvents) -> Unit diff --git a/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/advanced/AdvancedSettingsStateProvider.kt b/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/advanced/AdvancedSettingsStateProvider.kt index aadf27dd20..acfd9bb026 100644 --- a/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/advanced/AdvancedSettingsStateProvider.kt +++ b/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/advanced/AdvancedSettingsStateProvider.kt @@ -26,16 +26,19 @@ open class AdvancedSettingsStateProvider : PreviewParameterProvider { @Composable override fun present(): DeveloperSettingsState { @@ -69,7 +69,7 @@ class DeveloperSettingsPresenter @Inject constructor( val clearCacheAction = remember { mutableStateOf>(AsyncData.Uninitialized) } - val customElementCallBaseUrl by preferencesStore + val customElementCallBaseUrl by appPreferencesStore .getCustomElementCallBaseUrlFlow() .collectAsState(initial = null) @@ -100,7 +100,7 @@ class DeveloperSettingsPresenter @Inject constructor( is DeveloperSettingsEvents.SetCustomElementCallBaseUrl -> coroutineScope.launch { // If the URL is either empty or the default one, we want to save 'null' to remove the custom URL val urlToSave = event.baseUrl.takeIf { !it.isNullOrEmpty() && it != ElementCallConfig.DEFAULT_BASE_URL } - preferencesStore.setCustomElementCallBaseUrl(urlToSave) + appPreferencesStore.setCustomElementCallBaseUrl(urlToSave) } DeveloperSettingsEvents.ClearCache -> coroutineScope.clearCache(clearCacheAction) } diff --git a/features/preferences/impl/src/main/res/values/localazy.xml b/features/preferences/impl/src/main/res/values/localazy.xml index 55c43f05f4..607329332f 100644 --- a/features/preferences/impl/src/main/res/values/localazy.xml +++ b/features/preferences/impl/src/main/res/values/localazy.xml @@ -6,6 +6,8 @@ "Developer mode" "Enable to have access to features and functionality for developers." "Disable the rich text editor to type Markdown manually." + "Read receipts" + "If turned off, your read receipts won\'t be sent to anyone. You will still receive read receipts from other users." "Enable option to view message source in the timeline." "Display name" "Your display name" diff --git a/features/preferences/impl/src/test/kotlin/io/element/android/features/preferences/impl/advanced/AdvancedSettingsPresenterTest.kt b/features/preferences/impl/src/test/kotlin/io/element/android/features/preferences/impl/advanced/AdvancedSettingsPresenterTest.kt index 6d7877de32..a042d792b8 100644 --- a/features/preferences/impl/src/test/kotlin/io/element/android/features/preferences/impl/advanced/AdvancedSettingsPresenterTest.kt +++ b/features/preferences/impl/src/test/kotlin/io/element/android/features/preferences/impl/advanced/AdvancedSettingsPresenterTest.kt @@ -21,7 +21,8 @@ import app.cash.molecule.moleculeFlow import app.cash.turbine.test import com.google.common.truth.Truth.assertThat import io.element.android.compound.theme.Theme -import io.element.android.libraries.featureflag.test.InMemoryPreferencesStore +import io.element.android.libraries.featureflag.test.InMemoryAppPreferencesStore +import io.element.android.libraries.featureflag.test.InMemorySessionPreferencesStore import io.element.android.tests.testutils.WarmUpRule import io.element.android.tests.testutils.awaitLastSequentialItem import kotlinx.coroutines.test.runTest @@ -34,8 +35,7 @@ class AdvancedSettingsPresenterTest { @Test fun `present - initial state`() = runTest { - val store = InMemoryPreferencesStore() - val presenter = AdvancedSettingsPresenter(store) + val presenter = createAdvancedSettingsPresenter() moleculeFlow(RecompositionMode.Immediate) { presenter.present() }.test { @@ -43,14 +43,14 @@ class AdvancedSettingsPresenterTest { assertThat(initialState.isDeveloperModeEnabled).isFalse() assertThat(initialState.isRichTextEditorEnabled).isFalse() assertThat(initialState.showChangeThemeDialog).isFalse() + assertThat(initialState.isSendPublicReadReceiptsEnabled).isTrue() assertThat(initialState.theme).isEqualTo(Theme.System) } } @Test fun `present - developer mode on off`() = runTest { - val store = InMemoryPreferencesStore() - val presenter = AdvancedSettingsPresenter(store) + val presenter = createAdvancedSettingsPresenter() moleculeFlow(RecompositionMode.Immediate) { presenter.present() }.test { @@ -65,8 +65,7 @@ class AdvancedSettingsPresenterTest { @Test fun `present - rich text editor on off`() = runTest { - val store = InMemoryPreferencesStore() - val presenter = AdvancedSettingsPresenter(store) + val presenter = createAdvancedSettingsPresenter() moleculeFlow(RecompositionMode.Immediate) { presenter.present() }.test { @@ -79,10 +78,24 @@ class AdvancedSettingsPresenterTest { } } + @Test + fun `present - send public read receipts off on`() = runTest { + val presenter = createAdvancedSettingsPresenter() + moleculeFlow(RecompositionMode.Immediate) { + presenter.present() + }.test { + val initialState = awaitLastSequentialItem() + assertThat(initialState.isSendPublicReadReceiptsEnabled).isTrue() + initialState.eventSink.invoke(AdvancedSettingsEvents.SetSendPublicReadReceiptsEnabled(false)) + assertThat(awaitItem().isSendPublicReadReceiptsEnabled).isFalse() + initialState.eventSink.invoke(AdvancedSettingsEvents.SetSendPublicReadReceiptsEnabled(true)) + assertThat(awaitItem().isSendPublicReadReceiptsEnabled).isTrue() + } + } + @Test fun `present - change theme`() = runTest { - val store = InMemoryPreferencesStore() - val presenter = AdvancedSettingsPresenter(store) + val presenter = createAdvancedSettingsPresenter() moleculeFlow(RecompositionMode.Immediate) { presenter.present() }.test { @@ -102,4 +115,12 @@ class AdvancedSettingsPresenterTest { assertThat(withNewTheme.theme).isEqualTo(Theme.Light) } } + + private fun createAdvancedSettingsPresenter( + appPreferencesStore: InMemoryAppPreferencesStore = InMemoryAppPreferencesStore(), + sessionPreferencesStore: InMemorySessionPreferencesStore = InMemorySessionPreferencesStore(), + ) = AdvancedSettingsPresenter( + appPreferencesStore = appPreferencesStore, + sessionPreferencesStore = sessionPreferencesStore, + ) } diff --git a/features/preferences/impl/src/test/kotlin/io/element/android/features/preferences/impl/developer/DeveloperSettingsPresenterTest.kt b/features/preferences/impl/src/test/kotlin/io/element/android/features/preferences/impl/developer/DeveloperSettingsPresenterTest.kt index 50bf1ab426..19b1614500 100644 --- a/features/preferences/impl/src/test/kotlin/io/element/android/features/preferences/impl/developer/DeveloperSettingsPresenterTest.kt +++ b/features/preferences/impl/src/test/kotlin/io/element/android/features/preferences/impl/developer/DeveloperSettingsPresenterTest.kt @@ -29,7 +29,7 @@ import io.element.android.features.rageshake.test.rageshake.FakeRageshakeDataSto import io.element.android.libraries.architecture.AsyncData import io.element.android.libraries.featureflag.api.FeatureFlags import io.element.android.libraries.featureflag.test.FakeFeatureFlagService -import io.element.android.libraries.featureflag.test.InMemoryPreferencesStore +import io.element.android.libraries.featureflag.test.InMemoryAppPreferencesStore import io.element.android.tests.testutils.WarmUpRule import io.element.android.tests.testutils.awaitLastSequentialItem import kotlinx.coroutines.test.runTest @@ -114,7 +114,7 @@ class DeveloperSettingsPresenterTest { @Test fun `present - custom element call base url`() = runTest { - val preferencesStore = InMemoryPreferencesStore() + val preferencesStore = InMemoryAppPreferencesStore() val presenter = createDeveloperSettingsPresenter(preferencesStore = preferencesStore) moleculeFlow(RecompositionMode.Immediate) { presenter.present() @@ -149,14 +149,14 @@ class DeveloperSettingsPresenterTest { cacheSizeUseCase: FakeComputeCacheSizeUseCase = FakeComputeCacheSizeUseCase(), clearCacheUseCase: FakeClearCacheUseCase = FakeClearCacheUseCase(), rageshakePresenter: DefaultRageshakePreferencesPresenter = DefaultRageshakePreferencesPresenter(FakeRageShake(), FakeRageshakeDataStore()), - preferencesStore: InMemoryPreferencesStore = InMemoryPreferencesStore(), + preferencesStore: InMemoryAppPreferencesStore = InMemoryAppPreferencesStore(), ): DeveloperSettingsPresenter { return DeveloperSettingsPresenter( featureFlagService = featureFlagService, computeCacheSizeUseCase = cacheSizeUseCase, clearCacheUseCase = clearCacheUseCase, rageshakePresenter = rageshakePresenter, - preferencesStore = preferencesStore, + appPreferencesStore = preferencesStore, ) } } diff --git a/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/timeline/FakeMatrixTimeline.kt b/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/timeline/FakeMatrixTimeline.kt index 5530bb8d13..83ea98df6d 100644 --- a/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/timeline/FakeMatrixTimeline.kt +++ b/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/timeline/FakeMatrixTimeline.kt @@ -39,7 +39,7 @@ class FakeMatrixTimeline( private val _paginationState: MutableStateFlow = MutableStateFlow(initialPaginationState) private val _timelineItems: MutableStateFlow> = MutableStateFlow(initialTimelineItems) - var sendReadReceiptCount = 0 + var sentReadReceipts = mutableListOf>() private set var sendReadReceiptLatch: CompletableDeferred? = null @@ -81,7 +81,7 @@ class FakeMatrixTimeline( eventId: EventId, receiptType: ReceiptType, ): Result = simulateLongTask { - sendReadReceiptCount++ + sentReadReceipts.add(eventId to receiptType) sendReadReceiptLatch?.complete(Unit) Result.success(Unit) } diff --git a/libraries/preferences/api/src/main/kotlin/io/element/android/features/preferences/api/store/PreferencesStore.kt b/libraries/preferences/api/src/main/kotlin/io/element/android/features/preferences/api/store/AppPreferencesStore.kt similarity index 97% rename from libraries/preferences/api/src/main/kotlin/io/element/android/features/preferences/api/store/PreferencesStore.kt rename to libraries/preferences/api/src/main/kotlin/io/element/android/features/preferences/api/store/AppPreferencesStore.kt index 2bd1fc6064..4e78978873 100644 --- a/libraries/preferences/api/src/main/kotlin/io/element/android/features/preferences/api/store/PreferencesStore.kt +++ b/libraries/preferences/api/src/main/kotlin/io/element/android/features/preferences/api/store/AppPreferencesStore.kt @@ -18,7 +18,7 @@ package io.element.android.features.preferences.api.store import kotlinx.coroutines.flow.Flow -interface PreferencesStore { +interface AppPreferencesStore { suspend fun setRichTextEditorEnabled(enabled: Boolean) fun isRichTextEditorEnabledFlow(): Flow diff --git a/libraries/preferences/api/src/main/kotlin/io/element/android/features/preferences/api/store/SessionPreferencesStore.kt b/libraries/preferences/api/src/main/kotlin/io/element/android/features/preferences/api/store/SessionPreferencesStore.kt new file mode 100644 index 0000000000..0174d8d1eb --- /dev/null +++ b/libraries/preferences/api/src/main/kotlin/io/element/android/features/preferences/api/store/SessionPreferencesStore.kt @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2024 New Vector Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.element.android.features.preferences.api.store + +import kotlinx.coroutines.flow.Flow + +interface SessionPreferencesStore { + suspend fun setSendPublicReadReceipts(enabled: Boolean) + fun isSendPublicReadReceiptsEnabled(): Flow + + suspend fun clear() +} diff --git a/libraries/preferences/impl/build.gradle.kts b/libraries/preferences/impl/build.gradle.kts index 9c31d83481..3fa6324699 100644 --- a/libraries/preferences/impl/build.gradle.kts +++ b/libraries/preferences/impl/build.gradle.kts @@ -31,6 +31,8 @@ dependencies { api(projects.libraries.preferences.api) implementation(libs.dagger) implementation(libs.androidx.datastore.preferences) + implementation(projects.libraries.androidutils) implementation(projects.libraries.di) implementation(projects.libraries.core) + implementation(projects.libraries.matrix.api) } diff --git a/libraries/preferences/impl/src/main/kotlin/io/element/android/libraries/preferences/impl/store/DefaultPreferencesStore.kt b/libraries/preferences/impl/src/main/kotlin/io/element/android/libraries/preferences/impl/store/DefaultAppPreferencesStore.kt similarity index 95% rename from libraries/preferences/impl/src/main/kotlin/io/element/android/libraries/preferences/impl/store/DefaultPreferencesStore.kt rename to libraries/preferences/impl/src/main/kotlin/io/element/android/libraries/preferences/impl/store/DefaultAppPreferencesStore.kt index d00b7505d7..fdbd7dde8c 100644 --- a/libraries/preferences/impl/src/main/kotlin/io/element/android/libraries/preferences/impl/store/DefaultPreferencesStore.kt +++ b/libraries/preferences/impl/src/main/kotlin/io/element/android/libraries/preferences/impl/store/DefaultAppPreferencesStore.kt @@ -24,7 +24,7 @@ import androidx.datastore.preferences.core.edit import androidx.datastore.preferences.core.stringPreferencesKey import androidx.datastore.preferences.preferencesDataStore import com.squareup.anvil.annotations.ContributesBinding -import io.element.android.features.preferences.api.store.PreferencesStore +import io.element.android.features.preferences.api.store.AppPreferencesStore import io.element.android.libraries.core.bool.orTrue import io.element.android.libraries.core.meta.BuildMeta import io.element.android.libraries.core.meta.BuildType @@ -42,10 +42,10 @@ private val customElementCallBaseUrlKey = stringPreferencesKey("elementCallBaseU private val themeKey = stringPreferencesKey("theme") @ContributesBinding(AppScope::class) -class DefaultPreferencesStore @Inject constructor( +class DefaultAppPreferencesStore @Inject constructor( @ApplicationContext context: Context, private val buildMeta: BuildMeta, -) : PreferencesStore { +) : AppPreferencesStore { private val store = context.dataStore override suspend fun setRichTextEditorEnabled(enabled: Boolean) { diff --git a/libraries/preferences/impl/src/main/kotlin/io/element/android/libraries/preferences/impl/store/DefaultSessionPreferencesStore.kt b/libraries/preferences/impl/src/main/kotlin/io/element/android/libraries/preferences/impl/store/DefaultSessionPreferencesStore.kt new file mode 100644 index 0000000000..0d10d02b62 --- /dev/null +++ b/libraries/preferences/impl/src/main/kotlin/io/element/android/libraries/preferences/impl/store/DefaultSessionPreferencesStore.kt @@ -0,0 +1,63 @@ +/* + * 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 io.element.android.libraries.preferences.impl.store + +import android.content.Context +import androidx.datastore.preferences.core.PreferenceDataStoreFactory +import androidx.datastore.preferences.core.Preferences +import androidx.datastore.preferences.core.booleanPreferencesKey +import androidx.datastore.preferences.core.edit +import androidx.datastore.preferences.preferencesDataStoreFile +import com.squareup.anvil.annotations.ContributesBinding +import io.element.android.features.preferences.api.store.SessionPreferencesStore +import io.element.android.libraries.androidutils.file.safeDelete +import io.element.android.libraries.androidutils.hash.hash +import io.element.android.libraries.di.ApplicationContext +import io.element.android.libraries.di.SessionScope +import io.element.android.libraries.di.SingleIn +import io.element.android.libraries.matrix.api.user.CurrentSessionIdHolder +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.map +import javax.inject.Inject + +@ContributesBinding(SessionScope::class) +@SingleIn(SessionScope::class) +class DefaultSessionPreferencesStore @Inject constructor( + @ApplicationContext context: Context, + currentSessionIdHolder: CurrentSessionIdHolder, +) : SessionPreferencesStore { + private val sendPublicReadReceiptsKey = booleanPreferencesKey("sendPublicReadReceipts") + private val hashedUserId = currentSessionIdHolder.current.value.hash().take(16) + + private val dataStoreFile = context.preferencesDataStoreFile("session_${hashedUserId}_preferences") + private val store = PreferenceDataStoreFactory.create { dataStoreFile } + + override suspend fun setSendPublicReadReceipts(enabled: Boolean) = update(sendPublicReadReceiptsKey, enabled) + override fun isSendPublicReadReceiptsEnabled(): Flow = get(sendPublicReadReceiptsKey, true) + + override suspend fun clear() { + dataStoreFile.safeDelete() + } + + private suspend fun update(key: Preferences.Key, value: T) { + store.edit { prefs -> prefs[key] = value } + } + + private fun get(key: Preferences.Key, default: T): Flow { + return store.data.map { prefs -> prefs[key] ?: default } + } +} diff --git a/libraries/preferences/test/src/main/kotlin/io/element/android/libraries/featureflag/test/InMemoryPreferencesStore.kt b/libraries/preferences/test/src/main/kotlin/io/element/android/libraries/featureflag/test/InMemoryAppPreferencesStore.kt similarity index 93% rename from libraries/preferences/test/src/main/kotlin/io/element/android/libraries/featureflag/test/InMemoryPreferencesStore.kt rename to libraries/preferences/test/src/main/kotlin/io/element/android/libraries/featureflag/test/InMemoryAppPreferencesStore.kt index c143b3ff6c..c065622f3f 100644 --- a/libraries/preferences/test/src/main/kotlin/io/element/android/libraries/featureflag/test/InMemoryPreferencesStore.kt +++ b/libraries/preferences/test/src/main/kotlin/io/element/android/libraries/featureflag/test/InMemoryAppPreferencesStore.kt @@ -16,16 +16,16 @@ package io.element.android.libraries.featureflag.test -import io.element.android.features.preferences.api.store.PreferencesStore +import io.element.android.features.preferences.api.store.AppPreferencesStore import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.MutableStateFlow -class InMemoryPreferencesStore( +class InMemoryAppPreferencesStore( isRichTextEditorEnabled: Boolean = false, isDeveloperModeEnabled: Boolean = false, customElementCallBaseUrl: String? = null, theme: String? = null, -) : PreferencesStore { +) : AppPreferencesStore { private val isRichTextEditorEnabled = MutableStateFlow(isRichTextEditorEnabled) private val isDeveloperModeEnabled = MutableStateFlow(isDeveloperModeEnabled) private val customElementCallBaseUrl = MutableStateFlow(customElementCallBaseUrl) diff --git a/libraries/preferences/test/src/main/kotlin/io/element/android/libraries/featureflag/test/InMemorySessionPreferencesStore.kt b/libraries/preferences/test/src/main/kotlin/io/element/android/libraries/featureflag/test/InMemorySessionPreferencesStore.kt new file mode 100644 index 0000000000..1f6f7a6724 --- /dev/null +++ b/libraries/preferences/test/src/main/kotlin/io/element/android/libraries/featureflag/test/InMemorySessionPreferencesStore.kt @@ -0,0 +1,41 @@ +/* + * 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 io.element.android.libraries.featureflag.test + +import io.element.android.features.preferences.api.store.SessionPreferencesStore +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.MutableStateFlow + +class InMemorySessionPreferencesStore( + isSendPublicReadReceiptsEnabled: Boolean = true, +) : SessionPreferencesStore { + private val isSendPublicReadReceiptsEnabled = MutableStateFlow(isSendPublicReadReceiptsEnabled) + var clearCallCount = 0 + private set + + override suspend fun setSendPublicReadReceipts(enabled: Boolean) { + isSendPublicReadReceiptsEnabled.tryEmit(enabled) + } + override fun isSendPublicReadReceiptsEnabled(): Flow { + return isSendPublicReadReceiptsEnabled + } + + override suspend fun clear() { + clearCallCount++ + isSendPublicReadReceiptsEnabled.tryEmit(true) + } +} diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.advanced_AdvancedSettingsView_null_AdvancedSettingsView-Day-1_2_null_0,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.advanced_AdvancedSettingsView_null_AdvancedSettingsView-Day-1_2_null_0,NEXUS_5,1.0,en].png index a5e5ee3ebe..da1d8ddbfd 100644 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.advanced_AdvancedSettingsView_null_AdvancedSettingsView-Day-1_2_null_0,NEXUS_5,1.0,en].png +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.advanced_AdvancedSettingsView_null_AdvancedSettingsView-Day-1_2_null_0,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:b9792c65780ccbabc55476cd15f0ef1a00e43d4b49ded546350271f52bc50ac5 -size 39898 +oid sha256:da3f8614862ddacfd9b54afcd3bf091bec335e1489d7cbffc826059a89ae5478 +size 58453 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.advanced_AdvancedSettingsView_null_AdvancedSettingsView-Day-1_2_null_1,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.advanced_AdvancedSettingsView_null_AdvancedSettingsView-Day-1_2_null_1,NEXUS_5,1.0,en].png index 4e99b875cb..c99349ac0c 100644 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.advanced_AdvancedSettingsView_null_AdvancedSettingsView-Day-1_2_null_1,NEXUS_5,1.0,en].png +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.advanced_AdvancedSettingsView_null_AdvancedSettingsView-Day-1_2_null_1,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:33121ba1e716f4a22ba66a2648a1c66acbab8ffe721be2d52e556dd341818696 -size 39392 +oid sha256:1fd599f2e93432d5d5555f086b60059e84452a0da3c2a69d932042b7ee4d3bac +size 57922 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.advanced_AdvancedSettingsView_null_AdvancedSettingsView-Day-1_2_null_2,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.advanced_AdvancedSettingsView_null_AdvancedSettingsView-Day-1_2_null_2,NEXUS_5,1.0,en].png index cca7799a9b..b228d561bd 100644 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.advanced_AdvancedSettingsView_null_AdvancedSettingsView-Day-1_2_null_2,NEXUS_5,1.0,en].png +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.advanced_AdvancedSettingsView_null_AdvancedSettingsView-Day-1_2_null_2,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:2081e18691471601c80bed114bc795c6fe4491186282db4a81f0fb186d286d30 -size 39402 +oid sha256:9e9641228e0482c8e5500bb999b180e79cbfcb6a13e121f3be68aae5c58a6839 +size 57953 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.advanced_AdvancedSettingsView_null_AdvancedSettingsView-Day-1_2_null_3,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.advanced_AdvancedSettingsView_null_AdvancedSettingsView-Day-1_2_null_3,NEXUS_5,1.0,en].png index 336d6c8b81..3df61a1ef4 100644 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.advanced_AdvancedSettingsView_null_AdvancedSettingsView-Day-1_2_null_3,NEXUS_5,1.0,en].png +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.advanced_AdvancedSettingsView_null_AdvancedSettingsView-Day-1_2_null_3,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:61201245ab79d39b505f27d9fd4d1a5842111bac1e067c2bd450f633c9e92ec4 -size 35497 +oid sha256:1c1c5b00098e5860d4c69ef9a652483ea1192d9fa10f5449fb817769ab054183 +size 36128 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.advanced_AdvancedSettingsView_null_AdvancedSettingsView-Day-1_2_null_4,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.advanced_AdvancedSettingsView_null_AdvancedSettingsView-Day-1_2_null_4,NEXUS_5,1.0,en].png new file mode 100644 index 0000000000..50da3b5d6c --- /dev/null +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.advanced_AdvancedSettingsView_null_AdvancedSettingsView-Day-1_2_null_4,NEXUS_5,1.0,en].png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:4fe6625641cf06c45a817e9d10bc0d7296aa59160fc5a3e9dc28304e5b794125 +size 57943 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.advanced_AdvancedSettingsView_null_AdvancedSettingsView-Night-1_3_null_0,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.advanced_AdvancedSettingsView_null_AdvancedSettingsView-Night-1_3_null_0,NEXUS_5,1.0,en].png index 01afa74c7f..47fbdb6c0f 100644 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.advanced_AdvancedSettingsView_null_AdvancedSettingsView-Night-1_3_null_0,NEXUS_5,1.0,en].png +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.advanced_AdvancedSettingsView_null_AdvancedSettingsView-Night-1_3_null_0,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:5a24874553e4228ba8c254487c1bdd4d1a5556ecc2d4dfe26ace20548f5f9d38 -size 37203 +oid sha256:e85b252d0d6c166f987974ebcf9a6b58b924316733b868ad0ed5a61413bda381 +size 54577 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.advanced_AdvancedSettingsView_null_AdvancedSettingsView-Night-1_3_null_1,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.advanced_AdvancedSettingsView_null_AdvancedSettingsView-Night-1_3_null_1,NEXUS_5,1.0,en].png index 43cfc64ba6..10d7a6c5e1 100644 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.advanced_AdvancedSettingsView_null_AdvancedSettingsView-Night-1_3_null_1,NEXUS_5,1.0,en].png +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.advanced_AdvancedSettingsView_null_AdvancedSettingsView-Night-1_3_null_1,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:08d8714914bef5a1e5f353c43d5b7dbec7ff5c549402c723a0e875e1a8de2181 -size 36807 +oid sha256:4f246ce9f60b25d9739d73e2aed98132dfb3a0a694acbf320ff796f35f805fdc +size 54273 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.advanced_AdvancedSettingsView_null_AdvancedSettingsView-Night-1_3_null_2,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.advanced_AdvancedSettingsView_null_AdvancedSettingsView-Night-1_3_null_2,NEXUS_5,1.0,en].png index 7dafa3459b..4b03ace56b 100644 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.advanced_AdvancedSettingsView_null_AdvancedSettingsView-Night-1_3_null_2,NEXUS_5,1.0,en].png +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.advanced_AdvancedSettingsView_null_AdvancedSettingsView-Night-1_3_null_2,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:3eb3cbf3f0eeced3753b4b574cfcf1e8a5d86e7789e970f0a07089656cd16a18 -size 36818 +oid sha256:d0403a4bb8da3d36922cb5362977af9b3052624525def05e5236f4f922384c31 +size 54297 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.advanced_AdvancedSettingsView_null_AdvancedSettingsView-Night-1_3_null_3,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.advanced_AdvancedSettingsView_null_AdvancedSettingsView-Night-1_3_null_3,NEXUS_5,1.0,en].png index 83b3fee634..01e0e907a6 100644 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.advanced_AdvancedSettingsView_null_AdvancedSettingsView-Night-1_3_null_3,NEXUS_5,1.0,en].png +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.advanced_AdvancedSettingsView_null_AdvancedSettingsView-Night-1_3_null_3,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:0a74667729b5980edce4103b5ce38bd97dbb4df0e50642489a1822128b4dcd75 -size 31280 +oid sha256:824774a1e19974090de4cb32e06a7f984b5db238c3dc8d04a35d3457e647ac84 +size 31999 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.advanced_AdvancedSettingsView_null_AdvancedSettingsView-Night-1_3_null_4,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.advanced_AdvancedSettingsView_null_AdvancedSettingsView-Night-1_3_null_4,NEXUS_5,1.0,en].png new file mode 100644 index 0000000000..449fb69524 --- /dev/null +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.advanced_AdvancedSettingsView_null_AdvancedSettingsView-Night-1_3_null_4,NEXUS_5,1.0,en].png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:c0820b462a0dc103b66aef78528ae5ce13a55e2614a7a197e06713366c422893 +size 54313 From 12f4fa4b79e0f9dd3f5fc7087a8b37450449dcd8 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 26 Jan 2024 10:06:45 +0100 Subject: [PATCH 109/127] Update dependency androidx.webkit:webkit to v1.10.0 (#2286) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 7d8040d34b..d7e702d956 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -90,7 +90,7 @@ androidx_activity_activity = { module = "androidx.activity:activity", version.re androidx_activity_compose = { module = "androidx.activity:activity-compose", version.ref = "activity" } androidx_startup = "androidx.startup:startup-runtime:1.1.1" androidx_preference = "androidx.preference:preference:1.2.1" -androidx_webkit = "androidx.webkit:webkit:1.9.0" +androidx_webkit = "androidx.webkit:webkit:1.10.0" androidx_compose_bom = { module = "androidx.compose:compose-bom", version.ref = "compose_bom" } # When Material3 updates its transitive Compose dependencies, take a look at the constraints in `DependencyHandleScope.kt`. We may be able to remove the workaround there. From 80d49543ef8893471a19643d497aa931c4972a0e Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Fri, 26 Jan 2024 11:42:21 +0100 Subject: [PATCH 110/127] FileViewer: fix coloration issue for logs files. --- .../viewfolder/impl/file/ViewFilePresenter.kt | 10 +++++ .../viewfolder/impl/file/ViewFileState.kt | 7 ++++ .../impl/file/ViewFileStateProvider.kt | 1 + .../viewfolder/impl/file/ViewFileView.kt | 42 ++++++++++++++----- .../test/file/ViewFilePresenterTest.kt | 26 ++++++++++++ 5 files changed, 75 insertions(+), 11 deletions(-) diff --git a/features/viewfolder/impl/src/main/kotlin/io/element/android/features/viewfolder/impl/file/ViewFilePresenter.kt b/features/viewfolder/impl/src/main/kotlin/io/element/android/features/viewfolder/impl/file/ViewFilePresenter.kt index 91cc59ec05..0337d9044a 100644 --- a/features/viewfolder/impl/src/main/kotlin/io/element/android/features/viewfolder/impl/file/ViewFilePresenter.kt +++ b/features/viewfolder/impl/src/main/kotlin/io/element/android/features/viewfolder/impl/file/ViewFilePresenter.kt @@ -49,6 +49,7 @@ class ViewFilePresenter @AssistedInject constructor( @Composable override fun present(): ViewFileState { val coroutineScope = rememberCoroutineScope() + val colorationMode = remember { name.toColorationMode() } fun handleEvent(event: ViewFileEvents) { when (event) { @@ -67,6 +68,7 @@ class ViewFilePresenter @AssistedInject constructor( return ViewFileState( name = name, lines = lines, + colorationMode = colorationMode, eventSink = ::handleEvent, ) } @@ -79,3 +81,11 @@ class ViewFilePresenter @AssistedInject constructor( fileSave.save(path) } } + +private fun String.toColorationMode(): ColorationMode { + return when { + equals("logcat.log") -> ColorationMode.Logcat + startsWith("logs.") -> ColorationMode.Logs + else -> ColorationMode.None + } +} diff --git a/features/viewfolder/impl/src/main/kotlin/io/element/android/features/viewfolder/impl/file/ViewFileState.kt b/features/viewfolder/impl/src/main/kotlin/io/element/android/features/viewfolder/impl/file/ViewFileState.kt index 9fb531c478..8529655139 100644 --- a/features/viewfolder/impl/src/main/kotlin/io/element/android/features/viewfolder/impl/file/ViewFileState.kt +++ b/features/viewfolder/impl/src/main/kotlin/io/element/android/features/viewfolder/impl/file/ViewFileState.kt @@ -21,5 +21,12 @@ import io.element.android.libraries.architecture.AsyncData data class ViewFileState( val name: String, val lines: AsyncData>, + val colorationMode: ColorationMode, val eventSink: (ViewFileEvents) -> Unit, ) + +enum class ColorationMode { + Logcat, + Logs, + None, +} diff --git a/features/viewfolder/impl/src/main/kotlin/io/element/android/features/viewfolder/impl/file/ViewFileStateProvider.kt b/features/viewfolder/impl/src/main/kotlin/io/element/android/features/viewfolder/impl/file/ViewFileStateProvider.kt index f0612c0714..9859528511 100644 --- a/features/viewfolder/impl/src/main/kotlin/io/element/android/features/viewfolder/impl/file/ViewFileStateProvider.kt +++ b/features/viewfolder/impl/src/main/kotlin/io/element/android/features/viewfolder/impl/file/ViewFileStateProvider.kt @@ -51,5 +51,6 @@ fun aViewFileState( ) = ViewFileState( name = name, lines = lines, + colorationMode = ColorationMode.Logcat, eventSink = {}, ) diff --git a/features/viewfolder/impl/src/main/kotlin/io/element/android/features/viewfolder/impl/file/ViewFileView.kt b/features/viewfolder/impl/src/main/kotlin/io/element/android/features/viewfolder/impl/file/ViewFileView.kt index f58f5399d7..eea8f64b6e 100644 --- a/features/viewfolder/impl/src/main/kotlin/io/element/android/features/viewfolder/impl/file/ViewFileView.kt +++ b/features/viewfolder/impl/src/main/kotlin/io/element/android/features/viewfolder/impl/file/ViewFileView.kt @@ -114,6 +114,7 @@ fun ViewFileView( is AsyncData.Success -> FileContent( modifier = Modifier.weight(1f), lines = state.lines.data.toImmutableList(), + colorationMode = state.colorationMode, ) is AsyncData.Failure -> AsyncFailure(throwable = state.lines.error, onRetry = null) } @@ -125,6 +126,7 @@ fun ViewFileView( @Composable private fun FileContent( lines: ImmutableList, + colorationMode: ColorationMode, modifier: Modifier = Modifier, ) { LazyColumn( @@ -147,6 +149,7 @@ private fun FileContent( LineRow( lineNumber = index + 1, line = line, + colorationMode = colorationMode, ) } } @@ -157,6 +160,7 @@ private fun FileContent( private fun LineRow( lineNumber: Int, line: String, + colorationMode: ColorationMode, ) { val context = LocalContext.current Row( @@ -195,25 +199,41 @@ private fun LineRow( } .padding(horizontal = 4.dp), text = line, - color = line.toColor(), + color = line.toColor(colorationMode), style = ElementTheme.typography.fontBodyMdRegular ) } } /** - * Convert a logcat line to a color. - * Ex: `01-23 13:14:50.740 25818 25818 D org.matrix.rust.sdk: elementx: SyncIndicator = Hide | RustRoomListService.kt:81` + * Convert a line to a color. + * Ex for logcat: + * `01-23 13:14:50.740 25818 25818 D org.matrix.rust.sdk: elementx: SyncIndicator = Hide | RustRoomListService.kt:81` + * ^ use this char to determine the color + * Ex for logs: + * `2024-01-26T10:22:26.947416Z WARN elementx: Restore with non-empty map | MatrixClientsHolder.kt:68` + * ^ use this char to determine the color, see [LogLevel] */ @Composable -private fun String.toColor(): Color { - return when (getOrNull(31)) { - 'D' -> Color(0xFF299999) - 'I' -> Color(0xFFABC023) - 'W' -> Color(0xFFBBB529) - 'E' -> Color(0xFFFF6B68) - 'A' -> Color(0xFFFF6B68) - else -> ElementTheme.colors.textPrimary +private fun String.toColor(colorationMode: ColorationMode): Color { + return when (colorationMode) { + ColorationMode.Logcat -> when (getOrNull(31)) { + 'D' -> Color(0xFF299999) + 'I' -> Color(0xFFABC023) + 'W' -> Color(0xFFBBB529) + 'E' -> Color(0xFFFF6B68) + 'A' -> Color(0xFFFF6B68) + else -> ElementTheme.colors.textPrimary + } + ColorationMode.Logs -> when (getOrNull(32)) { + 'E' -> ElementTheme.colors.textPrimary + 'G' -> Color(0xFF299999) + '0' -> Color(0xFFABC023) + 'N' -> Color(0xFFBBB529) + 'R' -> Color(0xFFFF6B68) + else -> ElementTheme.colors.textPrimary + } + ColorationMode.None -> ElementTheme.colors.textPrimary } } diff --git a/features/viewfolder/impl/src/test/kotlin/io/element/android/features/viewfolder/test/file/ViewFilePresenterTest.kt b/features/viewfolder/impl/src/test/kotlin/io/element/android/features/viewfolder/test/file/ViewFilePresenterTest.kt index 3b593410b2..bfff21a71f 100644 --- a/features/viewfolder/impl/src/test/kotlin/io/element/android/features/viewfolder/test/file/ViewFilePresenterTest.kt +++ b/features/viewfolder/impl/src/test/kotlin/io/element/android/features/viewfolder/test/file/ViewFilePresenterTest.kt @@ -20,6 +20,7 @@ import app.cash.molecule.RecompositionMode import app.cash.molecule.moleculeFlow import app.cash.turbine.test import com.google.common.truth.Truth.assertThat +import io.element.android.features.viewfolder.impl.file.ColorationMode import io.element.android.features.viewfolder.impl.file.FileContentReader import io.element.android.features.viewfolder.impl.file.FileSave import io.element.android.features.viewfolder.impl.file.FileShare @@ -48,6 +49,7 @@ class ViewFilePresenterTest { val initialState = awaitItem() assertThat(initialState.name).isEqualTo("aName") assertThat(initialState.lines).isInstanceOf(AsyncData.Loading::class.java) + assertThat(initialState.colorationMode).isEqualTo(ColorationMode.None) val loadedState = awaitItem() val lines = (loadedState.lines as AsyncData.Success).data assertThat(lines.size).isEqualTo(1) @@ -55,6 +57,30 @@ class ViewFilePresenterTest { } } + @Test + fun `present - coloration mode for logcat`() = runTest { + val presenter = createPresenter(name = "logcat.log") + moleculeFlow(RecompositionMode.Immediate) { + presenter.present() + }.test { + val initialState = awaitItem() + assertThat(initialState.colorationMode).isEqualTo(ColorationMode.Logcat) + cancelAndConsumeRemainingEvents() + } + } + + @Test + fun `present - coloration mode for logs`() = runTest { + val presenter = createPresenter(name = "logs.date") + moleculeFlow(RecompositionMode.Immediate) { + presenter.present() + }.test { + val initialState = awaitItem() + assertThat(initialState.colorationMode).isEqualTo(ColorationMode.Logs) + cancelAndConsumeRemainingEvents() + } + } + @Test fun `present - share should not have any side effect`() = runTest { val fileContentReader = FakeFileContentReader().apply { From f55cfd116046ae625a1a22a4f6bee6642ca21fed Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Fri, 26 Jan 2024 14:46:51 +0100 Subject: [PATCH 111/127] Rename `ColorationMode.Logs` to `ColorationMode.RustLogs`. --- .../features/viewfolder/impl/file/ViewFilePresenter.kt | 2 +- .../android/features/viewfolder/impl/file/ViewFileState.kt | 2 +- .../android/features/viewfolder/impl/file/ViewFileView.kt | 4 ++-- .../features/viewfolder/test/file/ViewFilePresenterTest.kt | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/features/viewfolder/impl/src/main/kotlin/io/element/android/features/viewfolder/impl/file/ViewFilePresenter.kt b/features/viewfolder/impl/src/main/kotlin/io/element/android/features/viewfolder/impl/file/ViewFilePresenter.kt index 0337d9044a..4af90a83ed 100644 --- a/features/viewfolder/impl/src/main/kotlin/io/element/android/features/viewfolder/impl/file/ViewFilePresenter.kt +++ b/features/viewfolder/impl/src/main/kotlin/io/element/android/features/viewfolder/impl/file/ViewFilePresenter.kt @@ -85,7 +85,7 @@ class ViewFilePresenter @AssistedInject constructor( private fun String.toColorationMode(): ColorationMode { return when { equals("logcat.log") -> ColorationMode.Logcat - startsWith("logs.") -> ColorationMode.Logs + startsWith("logs.") -> ColorationMode.RustLogs else -> ColorationMode.None } } diff --git a/features/viewfolder/impl/src/main/kotlin/io/element/android/features/viewfolder/impl/file/ViewFileState.kt b/features/viewfolder/impl/src/main/kotlin/io/element/android/features/viewfolder/impl/file/ViewFileState.kt index 8529655139..35ed0991ad 100644 --- a/features/viewfolder/impl/src/main/kotlin/io/element/android/features/viewfolder/impl/file/ViewFileState.kt +++ b/features/viewfolder/impl/src/main/kotlin/io/element/android/features/viewfolder/impl/file/ViewFileState.kt @@ -27,6 +27,6 @@ data class ViewFileState( enum class ColorationMode { Logcat, - Logs, + RustLogs, None, } diff --git a/features/viewfolder/impl/src/main/kotlin/io/element/android/features/viewfolder/impl/file/ViewFileView.kt b/features/viewfolder/impl/src/main/kotlin/io/element/android/features/viewfolder/impl/file/ViewFileView.kt index eea8f64b6e..5127d41828 100644 --- a/features/viewfolder/impl/src/main/kotlin/io/element/android/features/viewfolder/impl/file/ViewFileView.kt +++ b/features/viewfolder/impl/src/main/kotlin/io/element/android/features/viewfolder/impl/file/ViewFileView.kt @@ -210,7 +210,7 @@ private fun LineRow( * Ex for logcat: * `01-23 13:14:50.740 25818 25818 D org.matrix.rust.sdk: elementx: SyncIndicator = Hide | RustRoomListService.kt:81` * ^ use this char to determine the color - * Ex for logs: + * Ex for Rust logs: * `2024-01-26T10:22:26.947416Z WARN elementx: Restore with non-empty map | MatrixClientsHolder.kt:68` * ^ use this char to determine the color, see [LogLevel] */ @@ -225,7 +225,7 @@ private fun String.toColor(colorationMode: ColorationMode): Color { 'A' -> Color(0xFFFF6B68) else -> ElementTheme.colors.textPrimary } - ColorationMode.Logs -> when (getOrNull(32)) { + ColorationMode.RustLogs -> when (getOrNull(32)) { 'E' -> ElementTheme.colors.textPrimary 'G' -> Color(0xFF299999) '0' -> Color(0xFFABC023) diff --git a/features/viewfolder/impl/src/test/kotlin/io/element/android/features/viewfolder/test/file/ViewFilePresenterTest.kt b/features/viewfolder/impl/src/test/kotlin/io/element/android/features/viewfolder/test/file/ViewFilePresenterTest.kt index bfff21a71f..6cef49a72d 100644 --- a/features/viewfolder/impl/src/test/kotlin/io/element/android/features/viewfolder/test/file/ViewFilePresenterTest.kt +++ b/features/viewfolder/impl/src/test/kotlin/io/element/android/features/viewfolder/test/file/ViewFilePresenterTest.kt @@ -76,7 +76,7 @@ class ViewFilePresenterTest { presenter.present() }.test { val initialState = awaitItem() - assertThat(initialState.colorationMode).isEqualTo(ColorationMode.Logs) + assertThat(initialState.colorationMode).isEqualTo(ColorationMode.RustLogs) cancelAndConsumeRemainingEvents() } } From d6ed2a40f504fda5f6e66cc4db80ab8139a4bd17 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Fri, 26 Jan 2024 14:49:45 +0100 Subject: [PATCH 112/127] Extract colors to avoid duplication and for more clarity. --- .../viewfolder/impl/file/ViewFileView.kt | 23 +++++++++++-------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/features/viewfolder/impl/src/main/kotlin/io/element/android/features/viewfolder/impl/file/ViewFileView.kt b/features/viewfolder/impl/src/main/kotlin/io/element/android/features/viewfolder/impl/file/ViewFileView.kt index 5127d41828..39f14ef88f 100644 --- a/features/viewfolder/impl/src/main/kotlin/io/element/android/features/viewfolder/impl/file/ViewFileView.kt +++ b/features/viewfolder/impl/src/main/kotlin/io/element/android/features/viewfolder/impl/file/ViewFileView.kt @@ -218,25 +218,30 @@ private fun LineRow( private fun String.toColor(colorationMode: ColorationMode): Color { return when (colorationMode) { ColorationMode.Logcat -> when (getOrNull(31)) { - 'D' -> Color(0xFF299999) - 'I' -> Color(0xFFABC023) - 'W' -> Color(0xFFBBB529) - 'E' -> Color(0xFFFF6B68) - 'A' -> Color(0xFFFF6B68) + 'D' -> colorDebug + 'I' -> colorInfo + 'W' -> colorWarning + 'E' -> colorError + 'A' -> colorError else -> ElementTheme.colors.textPrimary } ColorationMode.RustLogs -> when (getOrNull(32)) { 'E' -> ElementTheme.colors.textPrimary - 'G' -> Color(0xFF299999) - '0' -> Color(0xFFABC023) - 'N' -> Color(0xFFBBB529) - 'R' -> Color(0xFFFF6B68) + 'G' -> colorDebug + '0' -> colorInfo + 'N' -> colorWarning + 'R' -> colorError else -> ElementTheme.colors.textPrimary } ColorationMode.None -> ElementTheme.colors.textPrimary } } +private val colorDebug = Color(0xFF299999) +private val colorInfo = Color(0xFFABC023) +private val colorWarning = Color(0xFFBBB529) +private val colorError = Color(0xFFFF6B68) + @PreviewsDayNight @Composable internal fun ViewFileViewPreview(@PreviewParameter(ViewFileStateProvider::class) state: ViewFileState) = ElementPreview { From 7efbee8f86b2f552c704bfbdc5930e78d222e626 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Fri, 26 Jan 2024 14:55:53 +0100 Subject: [PATCH 113/127] Add preview for Rust logs (and fix a bug!) --- .../impl/file/ViewFileStateProvider.kt | 24 +++++++++++++++++-- .../viewfolder/impl/file/ViewFileView.kt | 2 +- 2 files changed, 23 insertions(+), 3 deletions(-) diff --git a/features/viewfolder/impl/src/main/kotlin/io/element/android/features/viewfolder/impl/file/ViewFileStateProvider.kt b/features/viewfolder/impl/src/main/kotlin/io/element/android/features/viewfolder/impl/file/ViewFileStateProvider.kt index 9859528511..3213036d4d 100644 --- a/features/viewfolder/impl/src/main/kotlin/io/element/android/features/viewfolder/impl/file/ViewFileStateProvider.kt +++ b/features/viewfolder/impl/src/main/kotlin/io/element/android/features/viewfolder/impl/file/ViewFileStateProvider.kt @@ -27,6 +27,7 @@ open class ViewFileStateProvider : PreviewParameterProvider { aViewFileState(lines = AsyncData.Failure(Exception("A failure"))), aViewFileState(lines = AsyncData.Success(emptyList())), aViewFileState( + name = "logcat.log", lines = AsyncData.Success( listOf( "Line 1", @@ -40,7 +41,25 @@ open class ViewFileStateProvider : PreviewParameterProvider { "01-23 13:14:50.740 25818 25818 E error", "01-23 13:14:50.740 25818 25818 A assertion", ) - ) + ), + colorationMode = ColorationMode.Logcat, + ), + aViewFileState( + name = "logs.2024-01-26", + lines = AsyncData.Success( + listOf( + "Line 1", + "Line 2", + "Line 3 lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor" + + " incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam,", + "2024-01-26T10:22:26.947416Z TRACE trace", + "2024-01-26T10:22:26.947416Z DEBUG debug", + "2024-01-26T10:22:26.947416Z INFO info", + "2024-01-26T10:22:26.947416Z WARN warn", + "2024-01-26T10:22:26.947416Z ERROR error", + ) + ), + colorationMode = ColorationMode.RustLogs, ) ) } @@ -48,9 +67,10 @@ open class ViewFileStateProvider : PreviewParameterProvider { fun aViewFileState( name: String = "aName", lines: AsyncData> = AsyncData.Uninitialized, + colorationMode: ColorationMode = ColorationMode.None, ) = ViewFileState( name = name, lines = lines, - colorationMode = ColorationMode.Logcat, + colorationMode = colorationMode, eventSink = {}, ) diff --git a/features/viewfolder/impl/src/main/kotlin/io/element/android/features/viewfolder/impl/file/ViewFileView.kt b/features/viewfolder/impl/src/main/kotlin/io/element/android/features/viewfolder/impl/file/ViewFileView.kt index 39f14ef88f..d5b3818227 100644 --- a/features/viewfolder/impl/src/main/kotlin/io/element/android/features/viewfolder/impl/file/ViewFileView.kt +++ b/features/viewfolder/impl/src/main/kotlin/io/element/android/features/viewfolder/impl/file/ViewFileView.kt @@ -228,7 +228,7 @@ private fun String.toColor(colorationMode: ColorationMode): Color { ColorationMode.RustLogs -> when (getOrNull(32)) { 'E' -> ElementTheme.colors.textPrimary 'G' -> colorDebug - '0' -> colorInfo + 'O' -> colorInfo 'N' -> colorWarning 'R' -> colorError else -> ElementTheme.colors.textPrimary From 6194f2c59fb458c60ee5c9b02f5f406c8995d2a6 Mon Sep 17 00:00:00 2001 From: ElementBot Date: Fri, 26 Jan 2024 14:04:10 +0000 Subject: [PATCH 114/127] Update screenshots --- ...eView_null_ViewFileView-Day-0_1_null_4,NEXUS_5,1.0,en].png | 4 ++-- ...eView_null_ViewFileView-Day-0_1_null_5,NEXUS_5,1.0,en].png | 3 +++ ...iew_null_ViewFileView-Night-0_2_null_4,NEXUS_5,1.0,en].png | 4 ++-- ...iew_null_ViewFileView-Night-0_2_null_5,NEXUS_5,1.0,en].png | 3 +++ 4 files changed, 10 insertions(+), 4 deletions(-) create mode 100644 tests/uitests/src/test/snapshots/images/ui_S_t[f.viewfolder.impl.file_ViewFileView_null_ViewFileView-Day-0_1_null_5,NEXUS_5,1.0,en].png create mode 100644 tests/uitests/src/test/snapshots/images/ui_S_t[f.viewfolder.impl.file_ViewFileView_null_ViewFileView-Night-0_2_null_5,NEXUS_5,1.0,en].png diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.viewfolder.impl.file_ViewFileView_null_ViewFileView-Day-0_1_null_4,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.viewfolder.impl.file_ViewFileView_null_ViewFileView-Day-0_1_null_4,NEXUS_5,1.0,en].png index f5be6b5490..862b48dfc9 100644 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.viewfolder.impl.file_ViewFileView_null_ViewFileView-Day-0_1_null_4,NEXUS_5,1.0,en].png +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.viewfolder.impl.file_ViewFileView_null_ViewFileView-Day-0_1_null_4,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:52ea44b4be9b858f64a886ded5427f8ef5c2149914e348166a2fbb333ffc41f8 -size 70418 +oid sha256:726f55e0bd89f429e351b070bda57be081c01a42240ba53e8d87bdfdcf84a1c6 +size 71385 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.viewfolder.impl.file_ViewFileView_null_ViewFileView-Day-0_1_null_5,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.viewfolder.impl.file_ViewFileView_null_ViewFileView-Day-0_1_null_5,NEXUS_5,1.0,en].png new file mode 100644 index 0000000000..1a3a882cc9 --- /dev/null +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.viewfolder.impl.file_ViewFileView_null_ViewFileView-Day-0_1_null_5,NEXUS_5,1.0,en].png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:839bdc36f80481351c63b66e358a0f68537a8cc1cdf75ee9dcaed35338573e92 +size 66140 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.viewfolder.impl.file_ViewFileView_null_ViewFileView-Night-0_2_null_4,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.viewfolder.impl.file_ViewFileView_null_ViewFileView-Night-0_2_null_4,NEXUS_5,1.0,en].png index 339e893381..8bd6eb3b3b 100644 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.viewfolder.impl.file_ViewFileView_null_ViewFileView-Night-0_2_null_4,NEXUS_5,1.0,en].png +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.viewfolder.impl.file_ViewFileView_null_ViewFileView-Night-0_2_null_4,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:304c5c94e3b408c744f0b6c86d35ac781f368e6e0d5742d5b2ff36ac1682538a -size 67297 +oid sha256:684fec6dc2c15767195b79d6c4c5996ab9cdb03386b5fcfc3400622ad4e03008 +size 68115 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.viewfolder.impl.file_ViewFileView_null_ViewFileView-Night-0_2_null_5,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.viewfolder.impl.file_ViewFileView_null_ViewFileView-Night-0_2_null_5,NEXUS_5,1.0,en].png new file mode 100644 index 0000000000..c6eca13a72 --- /dev/null +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.viewfolder.impl.file_ViewFileView_null_ViewFileView-Night-0_2_null_5,NEXUS_5,1.0,en].png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:1813c8906a75315d691faf5fe7ede66ab7e56e52e779408a2a4fcd6829c113b1 +size 61642 From 0b3ad63164b4b387bdd29b56351cffc5ba15e746 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 26 Jan 2024 14:37:43 +0000 Subject: [PATCH 115/127] Update dependency io.nlopez.compose.rules:detekt to v0.3.11 --- build.gradle.kts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle.kts b/build.gradle.kts index 26b7a4efe5..698757f737 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -60,7 +60,7 @@ allprojects { config.from(files("$rootDir/tools/detekt/detekt.yml")) } dependencies { - detektPlugins("io.nlopez.compose.rules:detekt:0.3.10") + detektPlugins("io.nlopez.compose.rules:detekt:0.3.11") } // KtLint From 0ec2632f448083ad616fa40482a84fe2ed3c30e1 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 26 Jan 2024 14:37:48 +0000 Subject: [PATCH 116/127] Update dependency org.matrix.rustcomponents:sdk-android to v0.1.95 --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index d7e702d956..ade161ca38 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -153,7 +153,7 @@ jsoup = "org.jsoup:jsoup:1.17.2" appyx_core = { module = "com.bumble.appyx:core", version.ref = "appyx" } molecule-runtime = "app.cash.molecule:molecule-runtime:1.3.2" timber = "com.jakewharton.timber:timber:5.0.1" -matrix_sdk = "org.matrix.rustcomponents:sdk-android:0.1.94" +matrix_sdk = "org.matrix.rustcomponents:sdk-android:0.1.95" matrix_richtexteditor = { module = "io.element.android:wysiwyg", version.ref = "wysiwyg" } matrix_richtexteditor_compose = { module = "io.element.android:wysiwyg-compose", version.ref = "wysiwyg" } sqldelight-driver-android = { module = "app.cash.sqldelight:android-driver", version.ref = "sqldelight" } From bfb6b327409cfdd973bf82718d6ce6e2f3f5766c Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Fri, 26 Jan 2024 16:08:13 +0100 Subject: [PATCH 117/127] Send typing notification #2240 --- changelog.d/2240.feature | 1 + .../impl/messagecomposer/MessageComposerEvents.kt | 1 + .../messagecomposer/MessageComposerPresenter.kt | 15 +++++++++++++++ .../impl/messagecomposer/MessageComposerView.kt | 5 +++++ .../textcomposer/MessageComposerPresenterTest.kt | 15 +++++++++++++++ .../libraries/matrix/api/room/MatrixRoom.kt | 6 ++++++ .../libraries/matrix/impl/room/RustMatrixRoom.kt | 4 ++++ .../libraries/matrix/test/room/FakeMatrixRoom.kt | 8 ++++++++ .../libraries/textcomposer/TextComposer.kt | 9 +++++++-- 9 files changed, 62 insertions(+), 2 deletions(-) create mode 100644 changelog.d/2240.feature diff --git a/changelog.d/2240.feature b/changelog.d/2240.feature new file mode 100644 index 0000000000..99d98058c8 --- /dev/null +++ b/changelog.d/2240.feature @@ -0,0 +1 @@ +Send typing notification diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/messagecomposer/MessageComposerEvents.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/messagecomposer/MessageComposerEvents.kt index 4f5c2aba10..9ddf1f7aae 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/messagecomposer/MessageComposerEvents.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/messagecomposer/MessageComposerEvents.kt @@ -43,6 +43,7 @@ sealed interface MessageComposerEvents { data class ToggleTextFormatting(val enabled: Boolean) : MessageComposerEvents data object CancelSendAttachment : MessageComposerEvents data class Error(val error: Throwable) : MessageComposerEvents + data class TypingNotice(val isTyping: Boolean) : MessageComposerEvents data class SuggestionReceived(val suggestion: Suggestion?) : MessageComposerEvents data class InsertMention(val mention: MentionSuggestion) : MessageComposerEvents } diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/messagecomposer/MessageComposerPresenter.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/messagecomposer/MessageComposerPresenter.kt index 6044b1abe7..4fea2ee046 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/messagecomposer/MessageComposerPresenter.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/messagecomposer/MessageComposerPresenter.kt @@ -20,6 +20,7 @@ import android.Manifest import android.annotation.SuppressLint import android.net.Uri import androidx.compose.runtime.Composable +import androidx.compose.runtime.DisposableEffect import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.MutableState import androidx.compose.runtime.getValue @@ -207,6 +208,15 @@ class MessageComposerPresenter @Inject constructor( .collect() } + DisposableEffect(Unit) { + // Declare that the user is not typing anymore when the composer is disposed + onDispose { + appCoroutineScope.launch { + room.typingNotice(false) + } + } + } + fun handleEvents(event: MessageComposerEvents) { when (event) { MessageComposerEvents.ToggleFullScreenState -> isFullScreen.value = !isFullScreen.value @@ -299,6 +309,11 @@ class MessageComposerPresenter @Inject constructor( is MessageComposerEvents.Error -> { analyticsService.trackError(event.error) } + is MessageComposerEvents.TypingNotice -> { + localCoroutineScope.launch { + room.typingNotice(event.isTyping) + } + } is MessageComposerEvents.SuggestionReceived -> { suggestionSearchTrigger.value = event.suggestion } diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/messagecomposer/MessageComposerView.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/messagecomposer/MessageComposerView.kt index 47b5adea5e..6cb2900a20 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/messagecomposer/MessageComposerView.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/messagecomposer/MessageComposerView.kt @@ -78,6 +78,10 @@ internal fun MessageComposerView( state.eventSink(MessageComposerEvents.Error(error)) } + fun onTyping(typing: Boolean) { + state.eventSink(MessageComposerEvents.TypingNotice(typing)) + } + val coroutineScope = rememberCoroutineScope() fun onRequestFocus() { coroutineScope.launch { @@ -121,6 +125,7 @@ internal fun MessageComposerView( onDeleteVoiceMessage = onDeleteVoiceMessage, onSuggestionReceived = ::onSuggestionReceived, onError = ::onError, + onTyping = ::onTyping, currentUserId = state.currentUserId, onRichContentSelected = ::sendUri, ) diff --git a/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/textcomposer/MessageComposerPresenterTest.kt b/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/textcomposer/MessageComposerPresenterTest.kt index 8f9842e309..d4b3c33cb1 100644 --- a/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/textcomposer/MessageComposerPresenterTest.kt +++ b/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/textcomposer/MessageComposerPresenterTest.kt @@ -873,6 +873,21 @@ class MessageComposerPresenterTest { } } + @Test + fun `present - handle typing notice event`() = runTest { + val room = FakeMatrixRoom() + val presenter = createPresenter(room = room, coroutineScope = this) + moleculeFlow(RecompositionMode.Immediate) { + presenter.present() + }.test { + val initialState = awaitFirstItem() + assertThat(room.typingRecord).isEmpty() + initialState.eventSink.invoke(MessageComposerEvents.TypingNotice(true)) + initialState.eventSink.invoke(MessageComposerEvents.TypingNotice(false)) + assertThat(room.typingRecord).isEqualTo(listOf(true, false)) + } + } + private suspend fun ReceiveTurbine.backToNormalMode(state: MessageComposerState, skipCount: Int = 0): MessageComposerState { state.eventSink.invoke(MessageComposerEvents.CloseSpecialMode) skipItems(skipCount) diff --git a/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/room/MatrixRoom.kt b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/room/MatrixRoom.kt index 41043d8ba5..6d5a552c83 100644 --- a/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/room/MatrixRoom.kt +++ b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/room/MatrixRoom.kt @@ -224,6 +224,12 @@ interface MatrixRoom : Closeable { progressCallback: ProgressCallback? ): Result + /** + * Send a typing notification. + * @param isTyping True if the user is typing, false otherwise. + */ + suspend fun typingNotice(isTyping: Boolean): Result + /** * Generates a Widget url to display in a [android.webkit.WebView] given the provided parameters. * @param widgetSettings The widget settings to use. diff --git a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/room/RustMatrixRoom.kt b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/room/RustMatrixRoom.kt index 647586431a..86bfd2dc12 100644 --- a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/room/RustMatrixRoom.kt +++ b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/room/RustMatrixRoom.kt @@ -520,6 +520,10 @@ class RustMatrixRoom( ) } + override suspend fun typingNotice(isTyping: Boolean) = runCatching { + innerRoom.typingNotice(isTyping) + } + override suspend fun generateWidgetWebViewUrl( widgetSettings: MatrixWidgetSettings, clientId: String, diff --git a/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/room/FakeMatrixRoom.kt b/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/room/FakeMatrixRoom.kt index 19b5132016..1b37f689a4 100644 --- a/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/room/FakeMatrixRoom.kt +++ b/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/room/FakeMatrixRoom.kt @@ -115,6 +115,9 @@ class FakeMatrixRoom( private var canUserJoinCallResult: Result = Result.success(true) var sendMessageMentions = emptyList() val editMessageCalls = mutableListOf>() + private val _typingRecord = mutableListOf() + val typingRecord: List + get() = _typingRecord var sendMediaCount = 0 private set @@ -426,6 +429,11 @@ class FakeMatrixRoom( progressCallback: ProgressCallback? ): Result = fakeSendMedia(progressCallback) + override suspend fun typingNotice(isTyping: Boolean): Result { + _typingRecord += isTyping + return Result.success(Unit) + } + override suspend fun generateWidgetWebViewUrl( widgetSettings: MatrixWidgetSettings, clientId: String, diff --git a/libraries/textcomposer/impl/src/main/kotlin/io/element/android/libraries/textcomposer/TextComposer.kt b/libraries/textcomposer/impl/src/main/kotlin/io/element/android/libraries/textcomposer/TextComposer.kt index 252e35d652..13359c1c0c 100644 --- a/libraries/textcomposer/impl/src/main/kotlin/io/element/android/libraries/textcomposer/TextComposer.kt +++ b/libraries/textcomposer/impl/src/main/kotlin/io/element/android/libraries/textcomposer/TextComposer.kt @@ -112,6 +112,7 @@ fun TextComposer( onSendVoiceMessage: () -> Unit, onDeleteVoiceMessage: () -> Unit, onError: (Throwable) -> Unit, + onTyping: (Boolean) -> Unit, onSuggestionReceived: (Suggestion?) -> Unit, onRichContentSelected: ((Uri) -> Unit)?, modifier: Modifier = Modifier, @@ -165,6 +166,7 @@ fun TextComposer( resolveMentionDisplay = { text, url -> TextDisplay.Custom(mentionSpanProvider.getMentionSpanFor(text, url)) }, resolveRoomMentionDisplay = { TextDisplay.Custom(mentionSpanProvider.getMentionSpanFor("@room", "#")) }, onError = onError, + onTyping = onTyping, onRichContentSelected = onRichContentSelected, ) } @@ -400,9 +402,10 @@ private fun TextInput( onResetComposerMode: () -> Unit, resolveRoomMentionDisplay: () -> TextDisplay, resolveMentionDisplay: (text: String, url: String) -> TextDisplay, + onError: (Throwable) -> Unit, + onTyping: (Boolean) -> Unit, + onRichContentSelected: ((Uri) -> Unit)?, modifier: Modifier = Modifier, - onError: (Throwable) -> Unit = {}, - onRichContentSelected: ((Uri) -> Unit)? = null, ) { val bgColor = ElementTheme.colors.bgSubtleSecondary val borderColor = ElementTheme.colors.borderDisabled @@ -451,6 +454,7 @@ private fun TextInput( resolveRoomMentionDisplay = resolveRoomMentionDisplay, onError = onError, onRichContentSelected = onRichContentSelected, + onTyping = onTyping, ) } } @@ -920,6 +924,7 @@ private fun ATextComposer( onSendVoiceMessage = {}, onDeleteVoiceMessage = {}, onError = {}, + onTyping = {}, onSuggestionReceived = {}, onRichContentSelected = null, ) From 7b0dcbe6a5cb85d57c69c82bee6a2b16a89a3381 Mon Sep 17 00:00:00 2001 From: bmarty Date: Mon, 29 Jan 2024 00:09:56 +0000 Subject: [PATCH 118/127] Sync Strings from Localazy --- .../leaveroom/api/src/main/res/values-it/translations.xml | 1 + .../preferences/impl/src/main/res/values-cs/translations.xml | 2 ++ .../preferences/impl/src/main/res/values-fr/translations.xml | 2 ++ .../preferences/impl/src/main/res/values-sk/translations.xml | 2 ++ .../rageshake/impl/src/main/res/values-cs/translations.xml | 1 + .../rageshake/impl/src/main/res/values-ru/translations.xml | 1 + .../rageshake/impl/src/main/res/values-sk/translations.xml | 1 + .../roomdetails/impl/src/main/res/values-it/translations.xml | 1 + .../roomlist/impl/src/main/res/values-cs/translations.xml | 5 +++++ .../roomlist/impl/src/main/res/values-fr/translations.xml | 5 +++++ .../roomlist/impl/src/main/res/values-sk/translations.xml | 5 +++++ features/roomlist/impl/src/main/res/values/localazy.xml | 5 +++++ libraries/ui-strings/src/main/res/values-hu/translations.xml | 2 +- libraries/ui-strings/src/main/res/values-it/translations.xml | 1 + .../ui-strings/src/main/res/values-zh-rTW/translations.xml | 2 +- 15 files changed, 34 insertions(+), 2 deletions(-) diff --git a/features/leaveroom/api/src/main/res/values-it/translations.xml b/features/leaveroom/api/src/main/res/values-it/translations.xml index 60d481824a..1b403e8f93 100644 --- a/features/leaveroom/api/src/main/res/values-it/translations.xml +++ b/features/leaveroom/api/src/main/res/values-it/translations.xml @@ -1,5 +1,6 @@ + "Vuoi davvero abbandonare questa conversazione? La conversazione non è pubblica e non potrai rientrare senza un invito." "Sei sicuro di voler lasciare questa stanza? Sei l\'unica persona presente. Se esci, nessuno potrà unirsi in futuro, te compreso." "Sei sicuro di voler lasciare questa stanza? Questa stanza non è pubblica e non potrai rientrare senza un invito." "Sei sicuro di voler lasciare la stanza?" diff --git a/features/preferences/impl/src/main/res/values-cs/translations.xml b/features/preferences/impl/src/main/res/values-cs/translations.xml index 76d764c131..96aa762e00 100644 --- a/features/preferences/impl/src/main/res/values-cs/translations.xml +++ b/features/preferences/impl/src/main/res/values-cs/translations.xml @@ -6,6 +6,8 @@ "Vývojářský režim" "Povolením získáte přístup k funkcím a funkcím pro vývojáře." "Vypněte editor formátovaného textu pro ruční zadání Markdown." + "Potvrzení o přečtení" + "Pokud je vypnuto, potvrzení o přečtení se nikomu neodesílají. Stále budete dostávat potvrzení o přečtení od ostatních uživatelů." "Povolit možnost zobrazení zdroje zprávy na časové ose." "Zobrazované jméno" "Vaše zobrazované jméno" diff --git a/features/preferences/impl/src/main/res/values-fr/translations.xml b/features/preferences/impl/src/main/res/values-fr/translations.xml index dc5e6ff790..cb9ebdf2af 100644 --- a/features/preferences/impl/src/main/res/values-fr/translations.xml +++ b/features/preferences/impl/src/main/res/values-fr/translations.xml @@ -6,6 +6,8 @@ "Mode développeur" "Activer pour pouvoir accéder aux fonctionnalités destinées aux développeurs." "Désactivez l’éditeur de texte enrichi pour saisir manuellement du Markdown." + "Accusés de lecture" + "En cas de désactivation, vos accusés de lecture ne seront pas envoyés aux autres membres. Vous verrez toujours les accusés des autres membres." "Activer cette option pour pouvoir voir la source des messages dans la discussion." "Pseudonyme" "Votre pseudonyme" diff --git a/features/preferences/impl/src/main/res/values-sk/translations.xml b/features/preferences/impl/src/main/res/values-sk/translations.xml index 8171748e1d..ad0a77b61e 100644 --- a/features/preferences/impl/src/main/res/values-sk/translations.xml +++ b/features/preferences/impl/src/main/res/values-sk/translations.xml @@ -6,6 +6,8 @@ "Vývojársky režim" "Umožniť prístup k možnostiam a funkciám pre vývojárov." "Vypnite rozšírený textový editor na ručné písanie Markdown." + "Potvrdenia o prečítaní" + "Ak je táto funkcia vypnutá, vaše potvrdenia o prečítaní sa nebudú nikomu odosielať. Stále budete dostávať potvrdenia o prečítaní od ostatných používateľov." "Povoliť možnosť zobrazenia zdroja správy na časovej osi." "Zobrazované meno" "Vaše zobrazované meno" diff --git a/features/rageshake/impl/src/main/res/values-cs/translations.xml b/features/rageshake/impl/src/main/res/values-cs/translations.xml index bfea484240..824819e5ee 100644 --- a/features/rageshake/impl/src/main/res/values-cs/translations.xml +++ b/features/rageshake/impl/src/main/res/values-cs/translations.xml @@ -11,5 +11,6 @@ "Povolit protokoly" "Odeslat snímek obrazovky" "Protokoly budou součástí vaší zprávy, aby se zajistilo že vše funguje správně. Chcete-li odeslat zprávu bez protokolů, vypněte toto nastavení." + "Zobrazit protokoly" "%1$s havaroval při posledním použití. Chcete se s námi podělit o zprávu o selhání?" diff --git a/features/rageshake/impl/src/main/res/values-ru/translations.xml b/features/rageshake/impl/src/main/res/values-ru/translations.xml index c22a34bf30..7c0ea079a3 100644 --- a/features/rageshake/impl/src/main/res/values-ru/translations.xml +++ b/features/rageshake/impl/src/main/res/values-ru/translations.xml @@ -11,5 +11,6 @@ "Разрешить ведение журналов" "Отправить снимок экрана" "Чтобы убедиться, что все работает правильно, в сообщение будут включены журналы. Чтобы отправить сообщение без журналов, отключите эту настройку." + "Просмотр журналов" "При последнем использовании %1$s произошел сбой. Хотите поделиться отчетом о сбое?" diff --git a/features/rageshake/impl/src/main/res/values-sk/translations.xml b/features/rageshake/impl/src/main/res/values-sk/translations.xml index 51222367a6..8e94848650 100644 --- a/features/rageshake/impl/src/main/res/values-sk/translations.xml +++ b/features/rageshake/impl/src/main/res/values-sk/translations.xml @@ -11,5 +11,6 @@ "Povoliť záznamy" "Odoslať snímku obrazovky" "K vašej správe budú priložené záznamy o chybe, aby sme sa uistili, že všetko funguje správne. Ak chcete odoslať správu bez záznamov o chybe, vypnite toto nastavenie." + "Zobraziť záznamy" "%1$s zlyhal pri poslednom použití. Chcete zdieľať správu o páde s našim tímom?" diff --git a/features/roomdetails/impl/src/main/res/values-it/translations.xml b/features/roomdetails/impl/src/main/res/values-it/translations.xml index 9b4672a51f..664c2dbd85 100644 --- a/features/roomdetails/impl/src/main/res/values-it/translations.xml +++ b/features/roomdetails/impl/src/main/res/values-it/translations.xml @@ -47,6 +47,7 @@ "Sblocca" "Potrai vedere di nuovo tutti i suoi messaggi." "Sblocca utente" + "Abbandona la conversazione" "Esci dalla stanza" "Sicurezza" "Oggetto" diff --git a/features/roomlist/impl/src/main/res/values-cs/translations.xml b/features/roomlist/impl/src/main/res/values-cs/translations.xml index 553aba069c..506c0c60b4 100644 --- a/features/roomlist/impl/src/main/res/values-cs/translations.xml +++ b/features/roomlist/impl/src/main/res/values-cs/translations.xml @@ -5,6 +5,11 @@ "Vytvořte novou konverzaci nebo místnost" "Začněte tím, že někomu pošnete zprávu." "Zatím žádné konverzace." + "Oblíbené" + "Nízká priorita" + "Lidé" + "Místnosti" + "Nepřečtené" "Všechny chaty" "Zdá se, že používáte nové zařízení. Ověřte přihlášení, abyste měli přístup k zašifrovaným zprávám." "Ověřte, že jste to vy" diff --git a/features/roomlist/impl/src/main/res/values-fr/translations.xml b/features/roomlist/impl/src/main/res/values-fr/translations.xml index 57ad02caca..70795bcd5f 100644 --- a/features/roomlist/impl/src/main/res/values-fr/translations.xml +++ b/features/roomlist/impl/src/main/res/values-fr/translations.xml @@ -5,6 +5,11 @@ "Créer une nouvelle discussion ou un nouveau salon" "Commencez par envoyer un message à quelqu’un." "Aucune discussion pour le moment." + "Favoris" + "Priorité basse" + "Discussions" + "Salons" + "Non-lus" "Conversations" "Il semblerait que vous utilisiez un nouvel appareil. Vérifiez la session avec un autre de vos appareils pour accéder à vos messages chiffrés." "Vérifier que c’est bien vous" diff --git a/features/roomlist/impl/src/main/res/values-sk/translations.xml b/features/roomlist/impl/src/main/res/values-sk/translations.xml index b4a8e8690a..705d31cee3 100644 --- a/features/roomlist/impl/src/main/res/values-sk/translations.xml +++ b/features/roomlist/impl/src/main/res/values-sk/translations.xml @@ -5,6 +5,11 @@ "Vytvorte novú konverzáciu alebo miestnosť" "Začnite tým, že niekomu pošlete správu." "Zatiaľ žiadne konverzácie." + "Obľúbené" + "Nízka priorita" + "Ľudia" + "Miestnosti" + "Neprečítané" "Všetky konverzácie" "Vyzerá to tak, že používate nové zariadenie. Overte svoj prístup k zašifrovaným správam pomocou vášho druhého zariadenia." "Overte, že ste to vy" diff --git a/features/roomlist/impl/src/main/res/values/localazy.xml b/features/roomlist/impl/src/main/res/values/localazy.xml index 08a630c6b5..6f7332a091 100644 --- a/features/roomlist/impl/src/main/res/values/localazy.xml +++ b/features/roomlist/impl/src/main/res/values/localazy.xml @@ -5,6 +5,11 @@ "Create a new conversation or room" "Get started by messaging someone." "No chats yet." + "Favourites" + "Low Priority" + "People" + "Rooms" + "Unreads" "All Chats" "Looks like you’re using a new device. Verify with another device to access your encrypted messages." "Verify it’s you" diff --git a/libraries/ui-strings/src/main/res/values-hu/translations.xml b/libraries/ui-strings/src/main/res/values-hu/translations.xml index 530ab7125b..102320bf83 100644 --- a/libraries/ui-strings/src/main/res/values-hu/translations.xml +++ b/libraries/ui-strings/src/main/res/values-hu/translations.xml @@ -210,7 +210,7 @@ "Néhány üzenet nem került elküldésre" "Elnézést, hiba történt" "🔐️ Csatlakozz hozzám itt: %1$s" - "Beszélj velem az %1$s használatával: %2$s" + "Beszélgessünk a(z) %1$s: %2$s -n" "%1$s Android" "%1$d megadott számjegy" diff --git a/libraries/ui-strings/src/main/res/values-it/translations.xml b/libraries/ui-strings/src/main/res/values-it/translations.xml index fc783fae31..ad2738557c 100644 --- a/libraries/ui-strings/src/main/res/values-it/translations.xml +++ b/libraries/ui-strings/src/main/res/values-it/translations.xml @@ -57,6 +57,7 @@ "Entra" "Ulteriori informazioni" "Esci" + "Abbandona la conversazione" "Esci dalla stanza" "Gestisci account" "Gestisci dispositivi" diff --git a/libraries/ui-strings/src/main/res/values-zh-rTW/translations.xml b/libraries/ui-strings/src/main/res/values-zh-rTW/translations.xml index 76cdca0b2b..51d89853f2 100644 --- a/libraries/ui-strings/src/main/res/values-zh-rTW/translations.xml +++ b/libraries/ui-strings/src/main/res/values-zh-rTW/translations.xml @@ -48,7 +48,7 @@ "忘記密碼?" "轉寄" "邀請" - "邀請朋友" + "邀請夥伴" "邀請朋友使用 %1$s" "邀請夥伴使用 %1$s" "邀請" From 4f7d26eef06a3eff26c2658b3e09be974af12d5d Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Mon, 29 Jan 2024 12:12:52 +0100 Subject: [PATCH 119/127] Cleanup: no need to provide a `CurrentSessionIdHolder`, the sessionId can be retrieved from the room. --- .../android/features/messages/impl/MessagesPresenter.kt | 8 +++----- .../features/messages/impl/MessagesPresenterTest.kt | 2 -- 2 files changed, 3 insertions(+), 7 deletions(-) diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/MessagesPresenter.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/MessagesPresenter.kt index 262f6cc6b2..f5d7246810 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/MessagesPresenter.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/MessagesPresenter.kt @@ -81,7 +81,6 @@ import io.element.android.libraries.matrix.api.room.MatrixRoom import io.element.android.libraries.matrix.api.room.MatrixRoomInfo import io.element.android.libraries.matrix.api.room.MatrixRoomMembersState import io.element.android.libraries.matrix.api.room.MessageEventType -import io.element.android.libraries.matrix.api.user.CurrentSessionIdHolder import io.element.android.libraries.matrix.ui.components.AttachmentThumbnailInfo import io.element.android.libraries.matrix.ui.components.AttachmentThumbnailType import io.element.android.libraries.matrix.ui.room.canRedactOtherAsState @@ -113,7 +112,6 @@ class MessagesPresenter @AssistedInject constructor( private val htmlConverterProvider: HtmlConverterProvider, @Assisted private val navigator: MessagesNavigator, private val buildMeta: BuildMeta, - private val currentSessionIdHolder: CurrentSessionIdHolder, ) : Presenter { private val timelinePresenter = timelinePresenterFactory.create(navigator = navigator) @@ -124,7 +122,7 @@ class MessagesPresenter @AssistedInject constructor( @Composable override fun present(): MessagesState { - htmlConverterProvider.Update(currentUserId = currentSessionIdHolder.current) + htmlConverterProvider.Update(currentUserId = room.sessionId) val roomInfo by room.roomInfoFlow.collectAsState(null) val localCoroutineScope = rememberCoroutineScope() @@ -157,9 +155,9 @@ class MessagesPresenter @AssistedInject constructor( mutableStateOf(false) } - LaunchedEffect(currentSessionIdHolder.current) { + LaunchedEffect(Unit) { withContext(dispatchers.io) { - canJoinCall = room.canUserJoinCall(userId = currentSessionIdHolder.current).getOrDefault(false) + canJoinCall = room.canUserJoinCall(room.sessionId).getOrDefault(false) } } diff --git a/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/MessagesPresenterTest.kt b/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/MessagesPresenterTest.kt index 08eaf15f7b..1c10cb97e8 100644 --- a/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/MessagesPresenterTest.kt +++ b/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/MessagesPresenterTest.kt @@ -665,7 +665,6 @@ class MessagesPresenterTest { clipboardHelper: FakeClipboardHelper = FakeClipboardHelper(), analyticsService: FakeAnalyticsService = FakeAnalyticsService(), permissionsPresenter: PermissionsPresenter = FakePermissionsPresenter(), - currentSessionIdHolder: CurrentSessionIdHolder = CurrentSessionIdHolder(FakeMatrixClient(A_SESSION_ID)), ): MessagesPresenter { val mediaSender = MediaSender(FakeMediaPreProcessor(), matrixRoom) val permissionsPresenterFactory = FakePermissionsPresenterFactory(permissionsPresenter) @@ -736,7 +735,6 @@ class MessagesPresenterTest { featureFlagsService = FakeFeatureFlagService(), buildMeta = aBuildMeta(), dispatchers = coroutineDispatchers, - currentSessionIdHolder = currentSessionIdHolder, htmlConverterProvider = FakeHtmlConverterProvider(), ) } From 96bae05184bcf22b2036428834ffd459a9d650c5 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Mon, 29 Jan 2024 12:13:13 +0100 Subject: [PATCH 120/127] Remove useless `suspend` modifier. --- .../element/android/features/messages/impl/MessagesPresenter.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/MessagesPresenter.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/MessagesPresenter.kt index f5d7246810..13a0fcb00b 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/MessagesPresenter.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/MessagesPresenter.kt @@ -313,7 +313,7 @@ class MessagesPresenter @AssistedInject constructor( } } - private suspend fun handleActionEdit( + private fun handleActionEdit( targetEvent: TimelineItem.Event, composerState: MessageComposerState, enableTextFormatting: Boolean, From 6406477fef3d46b3346a9a415cb00e5b975ffaef Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Mon, 29 Jan 2024 12:15:14 +0100 Subject: [PATCH 121/127] Ensure that `canUserJoinCall` is "live" --- .../element/android/features/messages/impl/MessagesPresenter.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/MessagesPresenter.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/MessagesPresenter.kt index 13a0fcb00b..6ae5be0621 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/MessagesPresenter.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/MessagesPresenter.kt @@ -155,7 +155,7 @@ class MessagesPresenter @AssistedInject constructor( mutableStateOf(false) } - LaunchedEffect(Unit) { + LaunchedEffect(syncUpdateFlow) { withContext(dispatchers.io) { canJoinCall = room.canUserJoinCall(room.sessionId).getOrDefault(false) } From 5cffb013d0c9d104ac14749a2bf76745ba23fa47 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 30 Jan 2024 08:38:09 +0100 Subject: [PATCH 122/127] Update gradle/wrapper-validation-action action to v2 (#2315) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- .github/workflows/gradle-wrapper-validation.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/gradle-wrapper-validation.yml b/.github/workflows/gradle-wrapper-validation.yml index 4746aa3885..f2ad3eeee4 100644 --- a/.github/workflows/gradle-wrapper-validation.yml +++ b/.github/workflows/gradle-wrapper-validation.yml @@ -12,4 +12,4 @@ jobs: # No concurrency required, this is a prerequisite to other actions and should run every time. steps: - uses: actions/checkout@v4 - - uses: gradle/wrapper-validation-action@v1 + - uses: gradle/wrapper-validation-action@v2 From 05cc526be98f08f4560c6a1795c091996bbcd2e6 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Tue, 30 Jan 2024 10:19:53 +0100 Subject: [PATCH 123/127] Fix: ensure the effect is restarted on each sync update. --- .../android/features/messages/impl/MessagesPresenter.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/MessagesPresenter.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/MessagesPresenter.kt index 6ae5be0621..d378014e2f 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/MessagesPresenter.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/MessagesPresenter.kt @@ -155,7 +155,7 @@ class MessagesPresenter @AssistedInject constructor( mutableStateOf(false) } - LaunchedEffect(syncUpdateFlow) { + LaunchedEffect(syncUpdateFlow.value) { withContext(dispatchers.io) { canJoinCall = room.canUserJoinCall(room.sessionId).getOrDefault(false) } @@ -163,7 +163,7 @@ class MessagesPresenter @AssistedInject constructor( val inviteProgress = remember { mutableStateOf>(AsyncData.Uninitialized) } var showReinvitePrompt by remember { mutableStateOf(false) } - LaunchedEffect(hasDismissedInviteDialog, composerState.hasFocus, syncUpdateFlow) { + LaunchedEffect(hasDismissedInviteDialog, composerState.hasFocus, syncUpdateFlow.value) { withContext(dispatchers.io) { showReinvitePrompt = !hasDismissedInviteDialog && composerState.hasFocus && room.isDirect && room.activeMemberCount == 1L } From ede1dc0fabef597c46fd261ca20eaa7e58c3e47f Mon Sep 17 00:00:00 2001 From: Jorge Martin Espinosa Date: Tue, 30 Jan 2024 11:10:46 +0100 Subject: [PATCH 124/127] Fix crash about several DataStores using the same file (#2312) * Fix crash about several DataStores using the same file - Create `@SessionCoroutineScope` annotation to pass a session-managed coroutine scope to the DI. - Expose this scope from `MatrixClient`. - Rework DataStore file creation a bit. - Centralise session preference creation through `DefaultSessionPreferencesStoreFactory` until we figure out what went wrong with the scoping --- .../element/android/x/di/SessionComponent.kt | 1 + changelog.d/2308.bugfix | 1 + .../di/annotations/SessionCoroutineScope.kt | 27 +++++++++++++ .../libraries/matrix/api/MatrixClient.kt | 2 + .../libraries/matrix/impl/RustMatrixClient.kt | 3 +- .../matrix/impl/di/SessionMatrixModule.kt | 8 ++++ .../libraries/matrix/test/FakeMatrixClient.kt | 3 ++ .../store/DefaultSessionPreferencesStore.kt | 30 +++++++------- .../DefaultSessionPreferencesStoreFactory.kt | 37 +++++++++++++++++ .../impl/store/SessionPreferencesModule.kt | 40 +++++++++++++++++++ 10 files changed, 137 insertions(+), 15 deletions(-) create mode 100644 changelog.d/2308.bugfix create mode 100644 libraries/di/src/main/kotlin/io/element/android/libraries/di/annotations/SessionCoroutineScope.kt create mode 100644 libraries/preferences/impl/src/main/kotlin/io/element/android/libraries/preferences/impl/store/DefaultSessionPreferencesStoreFactory.kt create mode 100644 libraries/preferences/impl/src/main/kotlin/io/element/android/libraries/preferences/impl/store/SessionPreferencesModule.kt diff --git a/app/src/main/kotlin/io/element/android/x/di/SessionComponent.kt b/app/src/main/kotlin/io/element/android/x/di/SessionComponent.kt index 4ef2840e8e..a4ecc217a4 100644 --- a/app/src/main/kotlin/io/element/android/x/di/SessionComponent.kt +++ b/app/src/main/kotlin/io/element/android/x/di/SessionComponent.kt @@ -33,6 +33,7 @@ interface SessionComponent : NodeFactoriesBindings { interface Builder { @BindsInstance fun client(matrixClient: MatrixClient): Builder + fun build(): SessionComponent } diff --git a/changelog.d/2308.bugfix b/changelog.d/2308.bugfix new file mode 100644 index 0000000000..4c553c3899 --- /dev/null +++ b/changelog.d/2308.bugfix @@ -0,0 +1 @@ +Fix 'There are multiple DataStores active for the same file' crashes diff --git a/libraries/di/src/main/kotlin/io/element/android/libraries/di/annotations/SessionCoroutineScope.kt b/libraries/di/src/main/kotlin/io/element/android/libraries/di/annotations/SessionCoroutineScope.kt new file mode 100644 index 0000000000..10174dee78 --- /dev/null +++ b/libraries/di/src/main/kotlin/io/element/android/libraries/di/annotations/SessionCoroutineScope.kt @@ -0,0 +1,27 @@ +/* + * 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 io.element.android.libraries.di.annotations + +import javax.inject.Qualifier + +/** + * Qualifies a [CoroutineScope] object which represents the base coroutine scope to use for an active session. + */ +@Retention(AnnotationRetention.RUNTIME) +@MustBeDocumented +@Qualifier +annotation class SessionCoroutineScope diff --git a/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/MatrixClient.kt b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/MatrixClient.kt index e5ae0c9571..6fd6b362ea 100644 --- a/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/MatrixClient.kt +++ b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/MatrixClient.kt @@ -34,12 +34,14 @@ import io.element.android.libraries.matrix.api.sync.SyncService import io.element.android.libraries.matrix.api.user.MatrixSearchUserResults import io.element.android.libraries.matrix.api.user.MatrixUser import io.element.android.libraries.matrix.api.verification.SessionVerificationService +import kotlinx.coroutines.CoroutineScope import java.io.Closeable interface MatrixClient : Closeable { val sessionId: SessionId val roomListService: RoomListService val mediaLoader: MatrixMediaLoader + val sessionCoroutineScope: CoroutineScope suspend fun getRoom(roomId: RoomId): MatrixRoom? suspend fun findDM(userId: UserId): RoomId? suspend fun ignoreUser(userId: UserId): Result diff --git a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/RustMatrixClient.kt b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/RustMatrixClient.kt index 2c6e74c96b..18b6262073 100644 --- a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/RustMatrixClient.kt +++ b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/RustMatrixClient.kt @@ -102,9 +102,10 @@ class RustMatrixClient( private val clock: SystemClock, ) : MatrixClient { override val sessionId: UserId = UserId(client.userId()) + override val sessionCoroutineScope = appCoroutineScope.childScope(dispatchers.main, "Session-$sessionId") + private val innerRoomListService = syncService.roomListService() private val sessionDispatcher = dispatchers.io.limitedParallelism(64) - private val sessionCoroutineScope = appCoroutineScope.childScope(dispatchers.main, "Session-$sessionId") private val rustSyncService = RustSyncService(syncService, sessionCoroutineScope) private val verificationService = RustSessionVerificationService(rustSyncService, sessionCoroutineScope) private val pushersService = RustPushersService( diff --git a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/di/SessionMatrixModule.kt b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/di/SessionMatrixModule.kt index 71f01f0aac..17ea8ee444 100644 --- a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/di/SessionMatrixModule.kt +++ b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/di/SessionMatrixModule.kt @@ -20,6 +20,7 @@ import com.squareup.anvil.annotations.ContributesTo import dagger.Module import dagger.Provides import io.element.android.libraries.di.SessionScope +import io.element.android.libraries.di.annotations.SessionCoroutineScope import io.element.android.libraries.matrix.api.MatrixClient import io.element.android.libraries.matrix.api.encryption.EncryptionService import io.element.android.libraries.matrix.api.media.MatrixMediaLoader @@ -27,6 +28,7 @@ import io.element.android.libraries.matrix.api.notificationsettings.Notification import io.element.android.libraries.matrix.api.room.RoomMembershipObserver import io.element.android.libraries.matrix.api.roomlist.RoomListService import io.element.android.libraries.matrix.api.verification.SessionVerificationService +import kotlinx.coroutines.CoroutineScope @Module @ContributesTo(SessionScope::class) @@ -60,4 +62,10 @@ object SessionMatrixModule { fun provideMediaLoader(matrixClient: MatrixClient): MatrixMediaLoader { return matrixClient.mediaLoader } + + @SessionCoroutineScope + @Provides + fun provideSessionCoroutineScope(matrixClient: MatrixClient): CoroutineScope { + return matrixClient.sessionCoroutineScope + } } diff --git a/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/FakeMatrixClient.kt b/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/FakeMatrixClient.kt index 0c4704c410..1b336cfec3 100644 --- a/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/FakeMatrixClient.kt +++ b/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/FakeMatrixClient.kt @@ -43,10 +43,13 @@ import io.element.android.libraries.matrix.test.roomlist.FakeRoomListService import io.element.android.libraries.matrix.test.sync.FakeSyncService import io.element.android.libraries.matrix.test.verification.FakeSessionVerificationService import io.element.android.tests.testutils.simulateLongTask +import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.delay +import kotlinx.coroutines.test.TestScope class FakeMatrixClient( override val sessionId: SessionId = A_SESSION_ID, + override val sessionCoroutineScope: CoroutineScope = TestScope(), private val userDisplayName: Result = Result.success(A_USER_NAME), private val userAvatarUrl: Result = Result.success(AN_AVATAR_URL), override val roomListService: RoomListService = FakeRoomListService(), diff --git a/libraries/preferences/impl/src/main/kotlin/io/element/android/libraries/preferences/impl/store/DefaultSessionPreferencesStore.kt b/libraries/preferences/impl/src/main/kotlin/io/element/android/libraries/preferences/impl/store/DefaultSessionPreferencesStore.kt index 0d10d02b62..eb2fffb045 100644 --- a/libraries/preferences/impl/src/main/kotlin/io/element/android/libraries/preferences/impl/store/DefaultSessionPreferencesStore.kt +++ b/libraries/preferences/impl/src/main/kotlin/io/element/android/libraries/preferences/impl/store/DefaultSessionPreferencesStore.kt @@ -22,29 +22,31 @@ import androidx.datastore.preferences.core.Preferences import androidx.datastore.preferences.core.booleanPreferencesKey import androidx.datastore.preferences.core.edit import androidx.datastore.preferences.preferencesDataStoreFile -import com.squareup.anvil.annotations.ContributesBinding import io.element.android.features.preferences.api.store.SessionPreferencesStore import io.element.android.libraries.androidutils.file.safeDelete import io.element.android.libraries.androidutils.hash.hash -import io.element.android.libraries.di.ApplicationContext -import io.element.android.libraries.di.SessionScope -import io.element.android.libraries.di.SingleIn -import io.element.android.libraries.matrix.api.user.CurrentSessionIdHolder +import io.element.android.libraries.di.annotations.SessionCoroutineScope +import io.element.android.libraries.matrix.api.core.SessionId +import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.map -import javax.inject.Inject +import java.io.File -@ContributesBinding(SessionScope::class) -@SingleIn(SessionScope::class) -class DefaultSessionPreferencesStore @Inject constructor( - @ApplicationContext context: Context, - currentSessionIdHolder: CurrentSessionIdHolder, +class DefaultSessionPreferencesStore( + context: Context, + sessionId: SessionId, + @SessionCoroutineScope sessionCoroutineScope: CoroutineScope, ) : SessionPreferencesStore { + companion object { + fun storeFile(context: Context, sessionId: SessionId): File { + val hashedUserId = sessionId.value.hash().take(16) + return context.preferencesDataStoreFile("session_${hashedUserId}_preferences") + } + } private val sendPublicReadReceiptsKey = booleanPreferencesKey("sendPublicReadReceipts") - private val hashedUserId = currentSessionIdHolder.current.value.hash().take(16) - private val dataStoreFile = context.preferencesDataStoreFile("session_${hashedUserId}_preferences") - private val store = PreferenceDataStoreFactory.create { dataStoreFile } + private val dataStoreFile = storeFile(context, sessionId) + private val store = PreferenceDataStoreFactory.create(scope = sessionCoroutineScope) { dataStoreFile } override suspend fun setSendPublicReadReceipts(enabled: Boolean) = update(sendPublicReadReceiptsKey, enabled) override fun isSendPublicReadReceiptsEnabled(): Flow = get(sendPublicReadReceiptsKey, true) diff --git a/libraries/preferences/impl/src/main/kotlin/io/element/android/libraries/preferences/impl/store/DefaultSessionPreferencesStoreFactory.kt b/libraries/preferences/impl/src/main/kotlin/io/element/android/libraries/preferences/impl/store/DefaultSessionPreferencesStoreFactory.kt new file mode 100644 index 0000000000..84dcbac289 --- /dev/null +++ b/libraries/preferences/impl/src/main/kotlin/io/element/android/libraries/preferences/impl/store/DefaultSessionPreferencesStoreFactory.kt @@ -0,0 +1,37 @@ +/* + * 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 io.element.android.libraries.preferences.impl.store + +import android.content.Context +import io.element.android.libraries.di.AppScope +import io.element.android.libraries.di.ApplicationContext +import io.element.android.libraries.di.SingleIn +import io.element.android.libraries.matrix.api.core.SessionId +import kotlinx.coroutines.CoroutineScope +import java.util.concurrent.ConcurrentHashMap +import javax.inject.Inject + +@SingleIn(AppScope::class) +class DefaultSessionPreferencesStoreFactory @Inject constructor( + @ApplicationContext private val context: Context, +) { + private val cache = ConcurrentHashMap() + + fun get(sessionId: SessionId, sessionCoroutineScope: CoroutineScope): DefaultSessionPreferencesStore = cache.getOrPut(sessionId) { + DefaultSessionPreferencesStore(context, sessionId, sessionCoroutineScope) + } +} diff --git a/libraries/preferences/impl/src/main/kotlin/io/element/android/libraries/preferences/impl/store/SessionPreferencesModule.kt b/libraries/preferences/impl/src/main/kotlin/io/element/android/libraries/preferences/impl/store/SessionPreferencesModule.kt new file mode 100644 index 0000000000..36663f6628 --- /dev/null +++ b/libraries/preferences/impl/src/main/kotlin/io/element/android/libraries/preferences/impl/store/SessionPreferencesModule.kt @@ -0,0 +1,40 @@ +/* + * 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 io.element.android.libraries.preferences.impl.store + +import com.squareup.anvil.annotations.ContributesTo +import dagger.Module +import dagger.Provides +import io.element.android.features.preferences.api.store.SessionPreferencesStore +import io.element.android.libraries.di.SessionScope +import io.element.android.libraries.di.annotations.SessionCoroutineScope +import io.element.android.libraries.matrix.api.user.CurrentSessionIdHolder +import kotlinx.coroutines.CoroutineScope + +@Module +@ContributesTo(SessionScope::class) +object SessionPreferencesModule { + @Provides + fun providesSessionPreferencesStore( + defaultSessionPreferencesStoreFactory: DefaultSessionPreferencesStoreFactory, + currentSessionIdHolder: CurrentSessionIdHolder, + @SessionCoroutineScope sessionCoroutineScope: CoroutineScope, + ): SessionPreferencesStore { + return defaultSessionPreferencesStoreFactory + .get(currentSessionIdHolder.current, sessionCoroutineScope) + } +} From 0f5038af8fe608682eaac39f2d2d554032f78cb9 Mon Sep 17 00:00:00 2001 From: Jorge Martin Espinosa Date: Tue, 30 Jan 2024 12:39:04 +0100 Subject: [PATCH 125/127] Make the whole items in advanced settings screen clickable, standarize paddings (#2314) * Make sure the whole item in advanced settings screen triggers the toggle action * Fix UI changes when setting `onChecked` actions to null. * Fix padding in invite member list items * Remove redundant `CheckableUserRow` alternatives. * Use 4dp for padding instead --------- Co-authored-by: ElementBot --- .../SearchMultipleUsersResultItem.kt | 28 ++-- .../impl/advanced/AdvancedSettingsView.kt | 6 +- .../impl/invite/RoomInviteMembersView.kt | 27 ++-- .../designsystem/theme/components/Checkbox.kt | 3 +- .../theme/components/RadioButton.kt | 3 +- .../designsystem/theme/components/Switch.kt | 3 +- .../ui/components/CheckableMatrixUserRow.kt | 75 ----------- .../components/CheckableUnresolvedUserRow.kt | 104 -------------- .../matrix/ui/components/CheckableUserRow.kt | 127 ++++++++++++++++-- ...cesView-Day-0_1_null_0,NEXUS_5,1.0,en].png | 4 +- ...sView-Night-0_2_null_0,NEXUS_5,1.0,en].png | 4 +- ...UsersResultItem_0_null,NEXUS_5,1.0,en].png | 4 +- ...ngsView-Day-2_3_null_0,NEXUS_5,1.0,en].png | 4 +- ...sView-Night-2_4_null_0,NEXUS_5,1.0,en].png | 4 +- ...ingOption-Day-7_8_null,NEXUS_5,1.0,en].png | 4 +- ...gOption-Night-7_9_null,NEXUS_5,1.0,en].png | 4 +- ...ingView-Day-8_9_null_0,NEXUS_5,1.0,en].png | 4 +- ...ingView-Day-8_9_null_1,NEXUS_5,1.0,en].png | 4 +- ...ingView-Day-8_9_null_2,NEXUS_5,1.0,en].png | 4 +- ...ingView-Day-8_9_null_3,NEXUS_5,1.0,en].png | 4 +- ...ingView-Day-8_9_null_4,NEXUS_5,1.0,en].png | 4 +- ...View-Night-8_10_null_0,NEXUS_5,1.0,en].png | 4 +- ...View-Night-8_10_null_1,NEXUS_5,1.0,en].png | 4 +- ...View-Night-8_10_null_2,NEXUS_5,1.0,en].png | 4 +- ...View-Night-8_10_null_3,NEXUS_5,1.0,en].png | 4 +- ...View-Night-8_10_null_4,NEXUS_5,1.0,en].png | 4 +- ...ettings-Day-4_5_null_0,NEXUS_5,1.0,en].png | 4 +- ...ettings-Day-4_5_null_1,NEXUS_5,1.0,en].png | 4 +- ...ettings-Day-4_5_null_2,NEXUS_5,1.0,en].png | 4 +- ...ettings-Day-4_5_null_3,NEXUS_5,1.0,en].png | 4 +- ...ettings-Day-4_5_null_4,NEXUS_5,1.0,en].png | 4 +- ...ettings-Day-4_5_null_5,NEXUS_5,1.0,en].png | 4 +- ...ettings-Day-4_5_null_6,NEXUS_5,1.0,en].png | 4 +- ...tings-Night-4_6_null_0,NEXUS_5,1.0,en].png | 4 +- ...tings-Night-4_6_null_1,NEXUS_5,1.0,en].png | 4 +- ...tings-Night-4_6_null_2,NEXUS_5,1.0,en].png | 4 +- ...tings-Night-4_6_null_3,NEXUS_5,1.0,en].png | 4 +- ...tings-Night-4_6_null_4,NEXUS_5,1.0,en].png | 4 +- ...tings-Night-4_6_null_5,NEXUS_5,1.0,en].png | 4 +- ...tings-Night-4_6_null_6,NEXUS_5,1.0,en].png | 4 +- ...acyOption-Day-3_4_null,NEXUS_5,1.0,en].png | 4 +- ...yOption-Night-3_5_null,NEXUS_5,1.0,en].png | 4 +- ...ettings-Day-5_6_null_0,NEXUS_5,1.0,en].png | 4 +- ...tings-Night-5_7_null_0,NEXUS_5,1.0,en].png | 4 +- ...UserRow-Day-2_3_null_0,NEXUS_5,1.0,en].png | 3 - ...UserRow-Day-2_3_null_1,NEXUS_5,1.0,en].png | 3 - ...erRow-Night-2_4_null_0,NEXUS_5,1.0,en].png | 3 - ...erRow-Night-2_4_null_1,NEXUS_5,1.0,en].png | 3 - ...ResolvedUserRow_0_null,NEXUS_5,1.0,en].png | 3 + ...resolvedUserRow_0_null,NEXUS_5,1.0,en].png | 4 +- ...ceholder-Day-3_4_null,NEXUS_5,1.0,en].png} | 0 ...holder-Night-3_5_null,NEXUS_5,1.0,en].png} | 0 ...Header-Day-2_3_null_0,NEXUS_5,1.0,en].png} | 0 ...Header-Day-2_3_null_1,NEXUS_5,1.0,en].png} | 0 ...ader-Night-2_4_null_0,NEXUS_5,1.0,en].png} | 0 ...ader-Night-2_4_null_1,NEXUS_5,1.0,en].png} | 0 ...serRow-Day-4_5_null_0,NEXUS_5,1.0,en].png} | 0 ...serRow-Day-4_5_null_1,NEXUS_5,1.0,en].png} | 0 ...rRow-Night-4_6_null_0,NEXUS_5,1.0,en].png} | 0 ...rRow-Night-4_6_null_1,NEXUS_5,1.0,en].png} | 0 ...ctedRoom-Day-5_6_null,NEXUS_5,1.0,en].png} | 0 ...edRoom-Night-5_7_null,NEXUS_5,1.0,en].png} | 0 ...ctedUser-Day-6_7_null,NEXUS_5,1.0,en].png} | 0 ...edUser-Night-6_8_null,NEXUS_5,1.0,en].png} | 0 ...sersList-Day-7_8_null,NEXUS_5,1.0,en].png} | 0 ...rsList-Night-7_9_null,NEXUS_5,1.0,en].png} | 0 ...edAvatar-Day-8_9_null,NEXUS_5,1.0,en].png} | 0 ...vatar-Night-8_10_null,NEXUS_5,1.0,en].png} | 0 68 files changed, 230 insertions(+), 305 deletions(-) delete mode 100644 libraries/matrixui/src/main/kotlin/io/element/android/libraries/matrix/ui/components/CheckableMatrixUserRow.kt delete mode 100644 libraries/matrixui/src/main/kotlin/io/element/android/libraries/matrix/ui/components/CheckableUnresolvedUserRow.kt delete mode 100644 tests/uitests/src/test/snapshots/images/ui_S_t[l.matrix.ui.components_CheckableMatrixUserRow_null_CheckableMatrixUserRow-Day-2_3_null_0,NEXUS_5,1.0,en].png delete mode 100644 tests/uitests/src/test/snapshots/images/ui_S_t[l.matrix.ui.components_CheckableMatrixUserRow_null_CheckableMatrixUserRow-Day-2_3_null_1,NEXUS_5,1.0,en].png delete mode 100644 tests/uitests/src/test/snapshots/images/ui_S_t[l.matrix.ui.components_CheckableMatrixUserRow_null_CheckableMatrixUserRow-Night-2_4_null_0,NEXUS_5,1.0,en].png delete mode 100644 tests/uitests/src/test/snapshots/images/ui_S_t[l.matrix.ui.components_CheckableMatrixUserRow_null_CheckableMatrixUserRow-Night-2_4_null_1,NEXUS_5,1.0,en].png create mode 100644 tests/uitests/src/test/snapshots/images/ui_S_t[l.matrix.ui.components_CheckableResolvedUserRow_null_CheckableResolvedUserRow_0_null,NEXUS_5,1.0,en].png rename tests/uitests/src/test/snapshots/images/{ui_S_t[l.matrix.ui.components_MatrixUserHeaderPlaceholder_null_MatrixUserHeaderPlaceholder-Day-4_5_null,NEXUS_5,1.0,en].png => ui_S_t[l.matrix.ui.components_MatrixUserHeaderPlaceholder_null_MatrixUserHeaderPlaceholder-Day-3_4_null,NEXUS_5,1.0,en].png} (100%) rename tests/uitests/src/test/snapshots/images/{ui_S_t[l.matrix.ui.components_MatrixUserHeaderPlaceholder_null_MatrixUserHeaderPlaceholder-Night-4_6_null,NEXUS_5,1.0,en].png => ui_S_t[l.matrix.ui.components_MatrixUserHeaderPlaceholder_null_MatrixUserHeaderPlaceholder-Night-3_5_null,NEXUS_5,1.0,en].png} (100%) rename tests/uitests/src/test/snapshots/images/{ui_S_t[l.matrix.ui.components_MatrixUserHeader_null_MatrixUserHeader-Day-3_4_null_0,NEXUS_5,1.0,en].png => ui_S_t[l.matrix.ui.components_MatrixUserHeader_null_MatrixUserHeader-Day-2_3_null_0,NEXUS_5,1.0,en].png} (100%) rename tests/uitests/src/test/snapshots/images/{ui_S_t[l.matrix.ui.components_MatrixUserHeader_null_MatrixUserHeader-Day-3_4_null_1,NEXUS_5,1.0,en].png => ui_S_t[l.matrix.ui.components_MatrixUserHeader_null_MatrixUserHeader-Day-2_3_null_1,NEXUS_5,1.0,en].png} (100%) rename tests/uitests/src/test/snapshots/images/{ui_S_t[l.matrix.ui.components_MatrixUserHeader_null_MatrixUserHeader-Night-3_5_null_0,NEXUS_5,1.0,en].png => ui_S_t[l.matrix.ui.components_MatrixUserHeader_null_MatrixUserHeader-Night-2_4_null_0,NEXUS_5,1.0,en].png} (100%) rename tests/uitests/src/test/snapshots/images/{ui_S_t[l.matrix.ui.components_MatrixUserHeader_null_MatrixUserHeader-Night-3_5_null_1,NEXUS_5,1.0,en].png => ui_S_t[l.matrix.ui.components_MatrixUserHeader_null_MatrixUserHeader-Night-2_4_null_1,NEXUS_5,1.0,en].png} (100%) rename tests/uitests/src/test/snapshots/images/{ui_S_t[l.matrix.ui.components_MatrixUserRow_null_MatrixUserRow-Day-5_6_null_0,NEXUS_5,1.0,en].png => ui_S_t[l.matrix.ui.components_MatrixUserRow_null_MatrixUserRow-Day-4_5_null_0,NEXUS_5,1.0,en].png} (100%) rename tests/uitests/src/test/snapshots/images/{ui_S_t[l.matrix.ui.components_MatrixUserRow_null_MatrixUserRow-Day-5_6_null_1,NEXUS_5,1.0,en].png => ui_S_t[l.matrix.ui.components_MatrixUserRow_null_MatrixUserRow-Day-4_5_null_1,NEXUS_5,1.0,en].png} (100%) rename tests/uitests/src/test/snapshots/images/{ui_S_t[l.matrix.ui.components_MatrixUserRow_null_MatrixUserRow-Night-5_7_null_0,NEXUS_5,1.0,en].png => ui_S_t[l.matrix.ui.components_MatrixUserRow_null_MatrixUserRow-Night-4_6_null_0,NEXUS_5,1.0,en].png} (100%) rename tests/uitests/src/test/snapshots/images/{ui_S_t[l.matrix.ui.components_MatrixUserRow_null_MatrixUserRow-Night-5_7_null_1,NEXUS_5,1.0,en].png => ui_S_t[l.matrix.ui.components_MatrixUserRow_null_MatrixUserRow-Night-4_6_null_1,NEXUS_5,1.0,en].png} (100%) rename tests/uitests/src/test/snapshots/images/{ui_S_t[l.matrix.ui.components_SelectedRoom_null_SelectedRoom-Day-6_7_null,NEXUS_5,1.0,en].png => ui_S_t[l.matrix.ui.components_SelectedRoom_null_SelectedRoom-Day-5_6_null,NEXUS_5,1.0,en].png} (100%) rename tests/uitests/src/test/snapshots/images/{ui_S_t[l.matrix.ui.components_SelectedRoom_null_SelectedRoom-Night-6_8_null,NEXUS_5,1.0,en].png => ui_S_t[l.matrix.ui.components_SelectedRoom_null_SelectedRoom-Night-5_7_null,NEXUS_5,1.0,en].png} (100%) rename tests/uitests/src/test/snapshots/images/{ui_S_t[l.matrix.ui.components_SelectedUser_null_SelectedUser-Day-7_8_null,NEXUS_5,1.0,en].png => ui_S_t[l.matrix.ui.components_SelectedUser_null_SelectedUser-Day-6_7_null,NEXUS_5,1.0,en].png} (100%) rename tests/uitests/src/test/snapshots/images/{ui_S_t[l.matrix.ui.components_SelectedUser_null_SelectedUser-Night-7_9_null,NEXUS_5,1.0,en].png => ui_S_t[l.matrix.ui.components_SelectedUser_null_SelectedUser-Night-6_8_null,NEXUS_5,1.0,en].png} (100%) rename tests/uitests/src/test/snapshots/images/{ui_S_t[l.matrix.ui.components_SelectedUsersList_null_SelectedUsersList-Day-8_9_null,NEXUS_5,1.0,en].png => ui_S_t[l.matrix.ui.components_SelectedUsersList_null_SelectedUsersList-Day-7_8_null,NEXUS_5,1.0,en].png} (100%) rename tests/uitests/src/test/snapshots/images/{ui_S_t[l.matrix.ui.components_SelectedUsersList_null_SelectedUsersList-Night-8_10_null,NEXUS_5,1.0,en].png => ui_S_t[l.matrix.ui.components_SelectedUsersList_null_SelectedUsersList-Night-7_9_null,NEXUS_5,1.0,en].png} (100%) rename tests/uitests/src/test/snapshots/images/{ui_S_t[l.matrix.ui.components_UnsavedAvatar_null_UnsavedAvatar-Day-9_10_null,NEXUS_5,1.0,en].png => ui_S_t[l.matrix.ui.components_UnsavedAvatar_null_UnsavedAvatar-Day-8_9_null,NEXUS_5,1.0,en].png} (100%) rename tests/uitests/src/test/snapshots/images/{ui_S_t[l.matrix.ui.components_UnsavedAvatar_null_UnsavedAvatar-Night-9_11_null,NEXUS_5,1.0,en].png => ui_S_t[l.matrix.ui.components_UnsavedAvatar_null_UnsavedAvatar-Night-8_10_null,NEXUS_5,1.0,en].png} (100%) diff --git a/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/components/SearchMultipleUsersResultItem.kt b/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/components/SearchMultipleUsersResultItem.kt index b53c8a7170..37ae6bd2fc 100644 --- a/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/components/SearchMultipleUsersResultItem.kt +++ b/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/components/SearchMultipleUsersResultItem.kt @@ -23,10 +23,11 @@ import androidx.compose.ui.tooling.preview.Preview import io.element.android.libraries.designsystem.components.avatar.AvatarSize import io.element.android.libraries.designsystem.preview.ElementThemedPreview import io.element.android.libraries.designsystem.theme.components.HorizontalDivider -import io.element.android.libraries.matrix.ui.components.CheckableMatrixUserRow -import io.element.android.libraries.matrix.ui.components.CheckableUnresolvedUserRow +import io.element.android.libraries.matrix.ui.components.CheckableUserRow +import io.element.android.libraries.matrix.ui.components.CheckableUserRowData import io.element.android.libraries.matrix.ui.components.aMatrixUser import io.element.android.libraries.matrix.ui.model.getAvatarData +import io.element.android.libraries.matrix.ui.model.getBestName import io.element.android.libraries.usersearch.api.UserSearchResult @Composable @@ -36,23 +37,24 @@ fun SearchMultipleUsersResultItem( onCheckedChange: (Boolean) -> Unit, modifier: Modifier = Modifier, ) { - if (searchResult.isUnresolved) { - CheckableUnresolvedUserRow( - checked = isUserSelected, - modifier = modifier, + val data = if (searchResult.isUnresolved) { + CheckableUserRowData.Unresolved( avatarData = searchResult.matrixUser.getAvatarData(AvatarSize.UserListItem), id = searchResult.matrixUser.userId.value, - onCheckedChange = onCheckedChange, ) } else { - CheckableMatrixUserRow( - checked = isUserSelected, - modifier = modifier, - matrixUser = searchResult.matrixUser, - avatarSize = AvatarSize.UserListItem, - onCheckedChange = onCheckedChange, + CheckableUserRowData.Resolved( + name = searchResult.matrixUser.getBestName(), + subtext = if (searchResult.matrixUser.displayName.isNullOrEmpty()) null else searchResult.matrixUser.userId.value, + avatarData = searchResult.matrixUser.getAvatarData(AvatarSize.UserListItem), ) } + CheckableUserRow( + checked = isUserSelected, + modifier = modifier, + data = data, + onCheckedChange = onCheckedChange, + ) } @Preview diff --git a/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/advanced/AdvancedSettingsView.kt b/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/advanced/AdvancedSettingsView.kt index c78f0a6543..7079a4daea 100644 --- a/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/advanced/AdvancedSettingsView.kt +++ b/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/advanced/AdvancedSettingsView.kt @@ -66,8 +66,8 @@ fun AdvancedSettingsView( }, trailingContent = ListItemContent.Switch( checked = state.isRichTextEditorEnabled, - onChange = { state.eventSink(AdvancedSettingsEvents.SetRichTextEditorEnabled(it)) }, ), + onClick = { state.eventSink(AdvancedSettingsEvents.SetRichTextEditorEnabled(!state.isRichTextEditorEnabled)) } ) ListItem( headlineContent = { @@ -78,8 +78,8 @@ fun AdvancedSettingsView( }, trailingContent = ListItemContent.Switch( checked = state.isDeveloperModeEnabled, - onChange = { state.eventSink(AdvancedSettingsEvents.SetDeveloperModeEnabled(it)) }, ), + onClick = { state.eventSink(AdvancedSettingsEvents.SetDeveloperModeEnabled(!state.isDeveloperModeEnabled)) } ) ListItem( headlineContent = { @@ -90,8 +90,8 @@ fun AdvancedSettingsView( }, trailingContent = ListItemContent.Switch( checked = state.isSendPublicReadReceiptsEnabled, - onChange = { state.eventSink(AdvancedSettingsEvents.SetSendPublicReadReceiptsEnabled(it)) }, ), + onClick = { state.eventSink(AdvancedSettingsEvents.SetSendPublicReadReceiptsEnabled(!state.isSendPublicReadReceiptsEnabled)) } ) } diff --git a/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/invite/RoomInviteMembersView.kt b/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/invite/RoomInviteMembersView.kt index a66813a699..d51e7c0a47 100644 --- a/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/invite/RoomInviteMembersView.kt +++ b/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/invite/RoomInviteMembersView.kt @@ -46,8 +46,8 @@ import io.element.android.libraries.designsystem.theme.components.Text import io.element.android.libraries.designsystem.theme.components.TextButton import io.element.android.libraries.designsystem.theme.components.TopAppBar import io.element.android.libraries.matrix.api.user.MatrixUser -import io.element.android.libraries.matrix.ui.components.CheckableUnresolvedUserRow import io.element.android.libraries.matrix.ui.components.CheckableUserRow +import io.element.android.libraries.matrix.ui.components.CheckableUserRowData import io.element.android.libraries.matrix.ui.components.SelectedUsersList import io.element.android.libraries.matrix.ui.model.getAvatarData import io.element.android.libraries.matrix.ui.model.getBestName @@ -186,18 +186,16 @@ private fun RoomInviteMembersSearchBar( LazyColumn { itemsIndexed(results) { index, invitableUser -> - if (invitableUser.isUnresolved && !invitableUser.isAlreadyInvited && !invitableUser.isAlreadyJoined) { - CheckableUnresolvedUserRow( - checked = invitableUser.isSelected, + val notInvitedOrJoined = !(invitableUser.isAlreadyInvited || invitableUser.isAlreadyJoined) + val isUnresolved = invitableUser.isUnresolved && notInvitedOrJoined + val enabled = isUnresolved || notInvitedOrJoined + val data = if (isUnresolved) { + CheckableUserRowData.Unresolved( avatarData = invitableUser.matrixUser.getAvatarData(AvatarSize.UserListItem), id = invitableUser.matrixUser.userId.value, - onCheckedChange = { onUserToggled(invitableUser.matrixUser) }, - modifier = Modifier.fillMaxWidth() ) } else { - CheckableUserRow( - checked = invitableUser.isSelected, - enabled = !invitableUser.isAlreadyInvited && !invitableUser.isAlreadyJoined, + CheckableUserRowData.Resolved( avatarData = invitableUser.matrixUser.getAvatarData(AvatarSize.UserListItem), name = invitableUser.matrixUser.getBestName(), subtext = when { @@ -207,11 +205,16 @@ private fun RoomInviteMembersSearchBar( // Otherwise show the ID, unless that's already used for their name invitableUser.matrixUser.displayName.isNullOrEmpty().not() -> invitableUser.matrixUser.userId.value else -> null - }, - onCheckedChange = { onUserToggled(invitableUser.matrixUser) }, - modifier = Modifier.fillMaxWidth() + } ) } + CheckableUserRow( + checked = invitableUser.isSelected, + enabled = enabled, + data = data, + onCheckedChange = { onUserToggled(invitableUser.matrixUser) }, + modifier = Modifier.fillMaxWidth() + ) if (index < results.lastIndex) { HorizontalDivider() diff --git a/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/theme/components/Checkbox.kt b/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/theme/components/Checkbox.kt index 007755ddff..77ecd3afd6 100644 --- a/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/theme/components/Checkbox.kt +++ b/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/theme/components/Checkbox.kt @@ -22,6 +22,7 @@ import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row import androidx.compose.material3.CheckboxColors import androidx.compose.material3.CheckboxDefaults +import androidx.compose.material3.minimumInteractiveComponentSize import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf @@ -57,7 +58,7 @@ fun Checkbox( onCheckedChange(!checked) } }, - modifier = modifier, + modifier = modifier.minimumInteractiveComponentSize(), enabled = enabled, colors = colors, interactionSource = interactionSource, diff --git a/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/theme/components/RadioButton.kt b/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/theme/components/RadioButton.kt index 3b438b5f2f..d8c84ac69b 100644 --- a/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/theme/components/RadioButton.kt +++ b/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/theme/components/RadioButton.kt @@ -22,6 +22,7 @@ import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row import androidx.compose.material3.RadioButtonColors import androidx.compose.material3.RadioButtonDefaults +import androidx.compose.material3.minimumInteractiveComponentSize import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf @@ -48,7 +49,7 @@ fun RadioButton( androidx.compose.material3.RadioButton( selected = selected, onClick = onClick, - modifier = modifier, + modifier = modifier.minimumInteractiveComponentSize(), enabled = enabled, colors = colors, interactionSource = interactionSource, diff --git a/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/theme/components/Switch.kt b/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/theme/components/Switch.kt index 7efb9d52eb..d93a01e4b6 100644 --- a/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/theme/components/Switch.kt +++ b/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/theme/components/Switch.kt @@ -23,6 +23,7 @@ import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.padding import androidx.compose.material3.SwitchColors import androidx.compose.material3.SwitchDefaults +import androidx.compose.material3.minimumInteractiveComponentSize import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf @@ -52,7 +53,7 @@ fun Switch( Material3Switch( checked = checked, onCheckedChange = onCheckedChange, - modifier = modifier, + modifier = modifier.minimumInteractiveComponentSize(), enabled = enabled, colors = colors, interactionSource = interactionSource, diff --git a/libraries/matrixui/src/main/kotlin/io/element/android/libraries/matrix/ui/components/CheckableMatrixUserRow.kt b/libraries/matrixui/src/main/kotlin/io/element/android/libraries/matrix/ui/components/CheckableMatrixUserRow.kt deleted file mode 100644 index 805e240194..0000000000 --- a/libraries/matrixui/src/main/kotlin/io/element/android/libraries/matrix/ui/components/CheckableMatrixUserRow.kt +++ /dev/null @@ -1,75 +0,0 @@ -/* - * Copyright (c) 2023 New Vector Ltd - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.element.android.libraries.matrix.ui.components - -import androidx.compose.foundation.layout.Column -import androidx.compose.runtime.Composable -import androidx.compose.ui.Modifier -import androidx.compose.ui.tooling.preview.PreviewParameter -import io.element.android.libraries.designsystem.components.avatar.AvatarSize -import io.element.android.libraries.designsystem.preview.ElementPreview -import io.element.android.libraries.designsystem.preview.PreviewsDayNight -import io.element.android.libraries.matrix.api.user.MatrixUser -import io.element.android.libraries.matrix.ui.model.getAvatarData -import io.element.android.libraries.matrix.ui.model.getBestName - -@Composable -fun CheckableMatrixUserRow( - checked: Boolean, - matrixUser: MatrixUser, - onCheckedChange: (Boolean) -> Unit, - modifier: Modifier = Modifier, - avatarSize: AvatarSize = AvatarSize.UserListItem, - enabled: Boolean = true, -) = CheckableUserRow( - checked = checked, - avatarData = matrixUser.getAvatarData(avatarSize), - name = matrixUser.getBestName(), - subtext = if (matrixUser.displayName.isNullOrEmpty()) null else matrixUser.userId.value, - modifier = modifier, - onCheckedChange = onCheckedChange, - enabled = enabled, -) - -@PreviewsDayNight -@Composable -internal fun CheckableMatrixUserRowPreview(@PreviewParameter(MatrixUserProvider::class) matrixUser: MatrixUser) = ElementPreview { - Column { - CheckableMatrixUserRow( - checked = true, - onCheckedChange = { }, - matrixUser = matrixUser, - ) - CheckableMatrixUserRow( - checked = false, - onCheckedChange = { }, - matrixUser = matrixUser, - ) - CheckableMatrixUserRow( - checked = true, - onCheckedChange = { }, - matrixUser = matrixUser, - enabled = false, - ) - CheckableMatrixUserRow( - checked = false, - onCheckedChange = { }, - matrixUser = matrixUser, - enabled = false, - ) - } -} diff --git a/libraries/matrixui/src/main/kotlin/io/element/android/libraries/matrix/ui/components/CheckableUnresolvedUserRow.kt b/libraries/matrixui/src/main/kotlin/io/element/android/libraries/matrix/ui/components/CheckableUnresolvedUserRow.kt deleted file mode 100644 index 125b9b13f6..0000000000 --- a/libraries/matrixui/src/main/kotlin/io/element/android/libraries/matrix/ui/components/CheckableUnresolvedUserRow.kt +++ /dev/null @@ -1,104 +0,0 @@ -/* - * Copyright (c) 2023 New Vector Ltd - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.element.android.libraries.matrix.ui.components - -import androidx.compose.foundation.clickable -import androidx.compose.foundation.layout.Column -import androidx.compose.foundation.layout.Row -import androidx.compose.foundation.layout.fillMaxWidth -import androidx.compose.foundation.layout.padding -import androidx.compose.runtime.Composable -import androidx.compose.ui.Alignment -import androidx.compose.ui.Modifier -import androidx.compose.ui.semantics.Role -import androidx.compose.ui.tooling.preview.Preview -import androidx.compose.ui.unit.dp -import io.element.android.libraries.designsystem.components.avatar.AvatarData -import io.element.android.libraries.designsystem.components.avatar.AvatarSize -import io.element.android.libraries.designsystem.preview.ElementThemedPreview -import io.element.android.libraries.designsystem.theme.components.Checkbox -import io.element.android.libraries.designsystem.theme.components.HorizontalDivider -import io.element.android.libraries.matrix.ui.model.getAvatarData - -@Composable -fun CheckableUnresolvedUserRow( - checked: Boolean, - onCheckedChange: (Boolean) -> Unit, - avatarData: AvatarData, - id: String, - modifier: Modifier = Modifier, - enabled: Boolean = true, -) { - Row( - modifier = modifier - .fillMaxWidth() - .clickable(role = Role.Checkbox, enabled = enabled) { - onCheckedChange(!checked) - }, - verticalAlignment = Alignment.CenterVertically, - ) { - UnresolvedUserRow( - modifier = Modifier.weight(1f), - avatarData = avatarData, - id = id, - ) - - Checkbox( - modifier = Modifier.padding(end = 16.dp), - checked = checked, - onCheckedChange = null, - enabled = enabled, - ) - } -} - -@Preview -@Composable -internal fun CheckableUnresolvedUserRowPreview() = ElementThemedPreview { - val matrixUser = aMatrixUser() - Column { - CheckableUnresolvedUserRow( - checked = false, - onCheckedChange = { }, - avatarData = matrixUser.getAvatarData(AvatarSize.UserListItem), - id = matrixUser.userId.value, - ) - HorizontalDivider() - CheckableUnresolvedUserRow( - checked = true, - onCheckedChange = { }, - avatarData = matrixUser.getAvatarData(AvatarSize.UserListItem), - id = matrixUser.userId.value, - ) - HorizontalDivider() - CheckableUnresolvedUserRow( - checked = false, - onCheckedChange = { }, - avatarData = matrixUser.getAvatarData(AvatarSize.UserListItem), - id = matrixUser.userId.value, - enabled = false, - ) - HorizontalDivider() - CheckableUnresolvedUserRow( - checked = true, - onCheckedChange = { }, - avatarData = matrixUser.getAvatarData(AvatarSize.UserListItem), - id = matrixUser.userId.value, - enabled = false, - ) - } -} diff --git a/libraries/matrixui/src/main/kotlin/io/element/android/libraries/matrix/ui/components/CheckableUserRow.kt b/libraries/matrixui/src/main/kotlin/io/element/android/libraries/matrix/ui/components/CheckableUserRow.kt index 1b7ead9131..318ab7eabd 100644 --- a/libraries/matrixui/src/main/kotlin/io/element/android/libraries/matrix/ui/components/CheckableUserRow.kt +++ b/libraries/matrixui/src/main/kotlin/io/element/android/libraries/matrix/ui/components/CheckableUserRow.kt @@ -17,24 +17,29 @@ package io.element.android.libraries.matrix.ui.components import androidx.compose.foundation.clickable +import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.padding import androidx.compose.runtime.Composable +import androidx.compose.runtime.Immutable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.semantics.Role +import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import io.element.android.libraries.designsystem.components.avatar.AvatarData +import io.element.android.libraries.designsystem.components.avatar.AvatarSize +import io.element.android.libraries.designsystem.preview.ElementThemedPreview import io.element.android.libraries.designsystem.theme.components.Checkbox +import io.element.android.libraries.designsystem.theme.components.HorizontalDivider +import io.element.android.libraries.matrix.ui.model.getAvatarData @Composable fun CheckableUserRow( checked: Boolean, onCheckedChange: (Boolean) -> Unit, - avatarData: AvatarData, - name: String, - subtext: String?, + data: CheckableUserRowData, modifier: Modifier = Modifier, enabled: Boolean = true, ) { @@ -46,19 +51,119 @@ fun CheckableUserRow( }, verticalAlignment = Alignment.CenterVertically, ) { - UserRow( - modifier = Modifier.weight(1f), - avatarData = avatarData, - name = name, - subtext = subtext, - ) + val rowModifier = Modifier.weight(1f) + when (data) { + is CheckableUserRowData.Resolved -> { + UserRow( + modifier = rowModifier, + avatarData = data.avatarData, + name = data.name, + subtext = data.subtext, + ) + } + is CheckableUserRowData.Unresolved -> { + UnresolvedUserRow( + modifier = rowModifier, + avatarData = data.avatarData, + id = data.id, + ) + } + } Checkbox( - modifier = Modifier - .padding(end = 16.dp), + modifier = Modifier.padding(end = 4.dp), checked = checked, onCheckedChange = null, enabled = enabled, ) } } + +@Immutable +sealed interface CheckableUserRowData { + data class Resolved( + val avatarData: AvatarData, + val name: String, + val subtext: String?, + ) : CheckableUserRowData + + data class Unresolved( + val avatarData: AvatarData, + val id: String, + ) : CheckableUserRowData +} + +@Preview +@Composable +internal fun CheckableResolvedUserRowPreview() = ElementThemedPreview { + val matrixUser = aMatrixUser() + val data = CheckableUserRowData.Resolved( + avatarData = matrixUser.getAvatarData(AvatarSize.UserListItem), + name = matrixUser.displayName.orEmpty(), + subtext = matrixUser.userId.value, + ) + Column { + CheckableUserRow( + checked = false, + onCheckedChange = { }, + data = data, + ) + HorizontalDivider() + CheckableUserRow( + checked = true, + onCheckedChange = { }, + data = data, + ) + HorizontalDivider() + CheckableUserRow( + checked = false, + onCheckedChange = { }, + data = data, + enabled = false, + ) + HorizontalDivider() + CheckableUserRow( + checked = true, + onCheckedChange = { }, + data = data, + enabled = false, + ) + } +} + +@Preview +@Composable +internal fun CheckableUnresolvedUserRowPreview() = ElementThemedPreview { + val matrixUser = aMatrixUser() + val data = CheckableUserRowData.Unresolved( + avatarData = matrixUser.getAvatarData(AvatarSize.UserListItem), + id = matrixUser.userId.value, + ) + Column { + CheckableUserRow( + checked = false, + onCheckedChange = { }, + data = data, + ) + HorizontalDivider() + CheckableUserRow( + checked = true, + onCheckedChange = { }, + data = data, + ) + HorizontalDivider() + CheckableUserRow( + checked = false, + onCheckedChange = { }, + data = data, + enabled = false, + ) + HorizontalDivider() + CheckableUserRow( + checked = true, + onCheckedChange = { }, + data = data, + enabled = false, + ) + } +} diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.analytics.api.preferences_AnalyticsPreferencesView_null_AnalyticsPreferencesView-Day-0_1_null_0,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.analytics.api.preferences_AnalyticsPreferencesView_null_AnalyticsPreferencesView-Day-0_1_null_0,NEXUS_5,1.0,en].png index 127d644e9a..aae2beab88 100644 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.analytics.api.preferences_AnalyticsPreferencesView_null_AnalyticsPreferencesView-Day-0_1_null_0,NEXUS_5,1.0,en].png +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.analytics.api.preferences_AnalyticsPreferencesView_null_AnalyticsPreferencesView-Day-0_1_null_0,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:6638cb923a57c8ee4a577626bef41c87da3ad5081a6bda6b4a303f094be30bfd -size 23181 +oid sha256:6e66e3395d8ce9b9b98ba21c99a82111f3e007e31d5845524f3c19284f478a8c +size 23232 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.analytics.api.preferences_AnalyticsPreferencesView_null_AnalyticsPreferencesView-Night-0_2_null_0,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.analytics.api.preferences_AnalyticsPreferencesView_null_AnalyticsPreferencesView-Night-0_2_null_0,NEXUS_5,1.0,en].png index c934db9816..7f6c3ded31 100644 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.analytics.api.preferences_AnalyticsPreferencesView_null_AnalyticsPreferencesView-Night-0_2_null_0,NEXUS_5,1.0,en].png +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.analytics.api.preferences_AnalyticsPreferencesView_null_AnalyticsPreferencesView-Night-0_2_null_0,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:4ffb2f6bd00607dd9f84d9b9dd4014f4389d0a3dd73fea8881a867680c0aa47b -size 22301 +oid sha256:9e0fee8d19a8522b34ec4ec3bbf8473284a01ec827aeb520f58b8df67079df53 +size 22367 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.createroom.impl.components_SearchMultipleUsersResultItem_null_SearchMultipleUsersResultItem_0_null,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.createroom.impl.components_SearchMultipleUsersResultItem_null_SearchMultipleUsersResultItem_0_null,NEXUS_5,1.0,en].png index 2bd50fb9bc..7199f240fb 100644 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.createroom.impl.components_SearchMultipleUsersResultItem_null_SearchMultipleUsersResultItem_0_null,NEXUS_5,1.0,en].png +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.createroom.impl.components_SearchMultipleUsersResultItem_null_SearchMultipleUsersResultItem_0_null,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:748900111b5b9cb1235f979d889098366ed66a88e8078224ec2780feac47a2e8 -size 86365 +oid sha256:0334ad25584ed508739fefb75a44d419d3904620e957c9ffa125985532d0bc10 +size 86328 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.analytics_AnalyticsSettingsView_null_AnalyticsSettingsView-Day-2_3_null_0,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.analytics_AnalyticsSettingsView_null_AnalyticsSettingsView-Day-2_3_null_0,NEXUS_5,1.0,en].png index c15c1daddb..445b507065 100644 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.analytics_AnalyticsSettingsView_null_AnalyticsSettingsView-Day-2_3_null_0,NEXUS_5,1.0,en].png +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.analytics_AnalyticsSettingsView_null_AnalyticsSettingsView-Day-2_3_null_0,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:2fc96ed56a48c2feaaa712ce57253678d0d79f834423aa5b41315df9213b4da9 -size 26277 +oid sha256:c3128ee234cf48f37fa0432f904d2e791614d20c82c16dc639edb849b42c4fe4 +size 26348 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.analytics_AnalyticsSettingsView_null_AnalyticsSettingsView-Night-2_4_null_0,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.analytics_AnalyticsSettingsView_null_AnalyticsSettingsView-Night-2_4_null_0,NEXUS_5,1.0,en].png index 2e17aa53e4..ab1f6f8645 100644 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.analytics_AnalyticsSettingsView_null_AnalyticsSettingsView-Night-2_4_null_0,NEXUS_5,1.0,en].png +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.analytics_AnalyticsSettingsView_null_AnalyticsSettingsView-Night-2_4_null_0,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:a09f0d8c68fb4af7dcd239f342ec2d68b3d3af4720e27277d4bfd6e37c15541e -size 25141 +oid sha256:4ceb2fe1dd526d36f90efe2bdcc4e4c5d407709fee053937ff8e53b760f85e0a +size 25186 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.notifications.edit_DefaultNotificationSettingOption_null_DefaultNotificationSettingOption-Day-7_8_null,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.notifications.edit_DefaultNotificationSettingOption_null_DefaultNotificationSettingOption-Day-7_8_null,NEXUS_5,1.0,en].png index 9a2c5a84b3..c67cb249df 100644 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.notifications.edit_DefaultNotificationSettingOption_null_DefaultNotificationSettingOption-Day-7_8_null,NEXUS_5,1.0,en].png +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.notifications.edit_DefaultNotificationSettingOption_null_DefaultNotificationSettingOption-Day-7_8_null,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:f38cda30a54ee8b4c4f95e6303c9cca43b06fa0ce4c2d690c992b2037537453f -size 35986 +oid sha256:1e55a3501da2a4217a245b7e6a9527ab5963a018dfc70aa2bce62c558f88f75b +size 36138 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.notifications.edit_DefaultNotificationSettingOption_null_DefaultNotificationSettingOption-Night-7_9_null,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.notifications.edit_DefaultNotificationSettingOption_null_DefaultNotificationSettingOption-Night-7_9_null,NEXUS_5,1.0,en].png index cb7908ac46..d47de6ed61 100644 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.notifications.edit_DefaultNotificationSettingOption_null_DefaultNotificationSettingOption-Night-7_9_null,NEXUS_5,1.0,en].png +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.notifications.edit_DefaultNotificationSettingOption_null_DefaultNotificationSettingOption-Night-7_9_null,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:41896059efcfa8b424cd80cf93f233a263498222a8a555b6eb8cfa9a5f62d941 -size 33347 +oid sha256:4c5baa96c59c7e61f84be5e730c56a6f18b0f180fa4c2c7b9bd64e53b20d52b5 +size 33392 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.notifications.edit_EditDefaultNotificationSettingView_null_EditDefaultNotificationSettingView-Day-8_9_null_0,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.notifications.edit_EditDefaultNotificationSettingView_null_EditDefaultNotificationSettingView-Day-8_9_null_0,NEXUS_5,1.0,en].png index c943b96993..bd1f36da91 100644 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.notifications.edit_EditDefaultNotificationSettingView_null_EditDefaultNotificationSettingView-Day-8_9_null_0,NEXUS_5,1.0,en].png +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.notifications.edit_EditDefaultNotificationSettingView_null_EditDefaultNotificationSettingView-Day-8_9_null_0,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:1aaf3d3282191d2e775ef8c8184ed7c56fdc34f8649e1ff8e7ad9da8b8cb4a9d -size 35806 +oid sha256:d659a2a7be6a053aa8c4468f2e833687de20248a6b2fd9dcd4a5d47ea54df20c +size 35913 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.notifications.edit_EditDefaultNotificationSettingView_null_EditDefaultNotificationSettingView-Day-8_9_null_1,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.notifications.edit_EditDefaultNotificationSettingView_null_EditDefaultNotificationSettingView-Day-8_9_null_1,NEXUS_5,1.0,en].png index 5fdf152997..f8484d174b 100644 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.notifications.edit_EditDefaultNotificationSettingView_null_EditDefaultNotificationSettingView-Day-8_9_null_1,NEXUS_5,1.0,en].png +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.notifications.edit_EditDefaultNotificationSettingView_null_EditDefaultNotificationSettingView-Day-8_9_null_1,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:7076ab247512b4b0c0e631d060e193af0f4d741e5819dcf891368b2b1f3cd890 -size 35739 +oid sha256:4ddd2c2a6bec2701d8ca8ae755d31713d5dbfcbbe30642f636f0a8ce22712996 +size 35843 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.notifications.edit_EditDefaultNotificationSettingView_null_EditDefaultNotificationSettingView-Day-8_9_null_2,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.notifications.edit_EditDefaultNotificationSettingView_null_EditDefaultNotificationSettingView-Day-8_9_null_2,NEXUS_5,1.0,en].png index 4f7db1bf02..9d718720b8 100644 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.notifications.edit_EditDefaultNotificationSettingView_null_EditDefaultNotificationSettingView-Day-8_9_null_2,NEXUS_5,1.0,en].png +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.notifications.edit_EditDefaultNotificationSettingView_null_EditDefaultNotificationSettingView-Day-8_9_null_2,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:5168d33c67566213cab7f71ee0fc71f151172dc8c5065e302249c6bd01cb751c -size 33507 +oid sha256:6cacbc497b8211b3c18cec602e24ecca799c07790c1c6766b91c2c84556161f5 +size 32322 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.notifications.edit_EditDefaultNotificationSettingView_null_EditDefaultNotificationSettingView-Day-8_9_null_3,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.notifications.edit_EditDefaultNotificationSettingView_null_EditDefaultNotificationSettingView-Day-8_9_null_3,NEXUS_5,1.0,en].png index e080a71d7c..8511338d8a 100644 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.notifications.edit_EditDefaultNotificationSettingView_null_EditDefaultNotificationSettingView-Day-8_9_null_3,NEXUS_5,1.0,en].png +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.notifications.edit_EditDefaultNotificationSettingView_null_EditDefaultNotificationSettingView-Day-8_9_null_3,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:c264a1541965790ed5661a3a319e6d6a87e48cc85a95a3590d9595ad39deb760 -size 36654 +oid sha256:b8cee12ff95d1ccfce0f4445a8e32cea154d8f956cf05888129c23f3d9fe43d5 +size 36865 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.notifications.edit_EditDefaultNotificationSettingView_null_EditDefaultNotificationSettingView-Day-8_9_null_4,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.notifications.edit_EditDefaultNotificationSettingView_null_EditDefaultNotificationSettingView-Day-8_9_null_4,NEXUS_5,1.0,en].png index affc28ddb6..e421d4cb14 100644 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.notifications.edit_EditDefaultNotificationSettingView_null_EditDefaultNotificationSettingView-Day-8_9_null_4,NEXUS_5,1.0,en].png +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.notifications.edit_EditDefaultNotificationSettingView_null_EditDefaultNotificationSettingView-Day-8_9_null_4,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:f65c369e8f8c9526910f375b1d4b7166d1025a143400c6d53f61f3ce6537d67f -size 49858 +oid sha256:e08c52be5c9c77c5d3743522f4b2ac4d5dad5cebbaba11245202a9f0e2ca1ccb +size 50275 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.notifications.edit_EditDefaultNotificationSettingView_null_EditDefaultNotificationSettingView-Night-8_10_null_0,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.notifications.edit_EditDefaultNotificationSettingView_null_EditDefaultNotificationSettingView-Night-8_10_null_0,NEXUS_5,1.0,en].png index a13c0bc646..65fd53c320 100644 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.notifications.edit_EditDefaultNotificationSettingView_null_EditDefaultNotificationSettingView-Night-8_10_null_0,NEXUS_5,1.0,en].png +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.notifications.edit_EditDefaultNotificationSettingView_null_EditDefaultNotificationSettingView-Night-8_10_null_0,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:e89d557862545f7468cefd88593d0995c813dc8871a92c94552ce26f9ae4651b -size 33066 +oid sha256:c54ea0c5ffdb094bea1fe07208a5ed9683f7104ca9d7c85a452c5f0983aeff47 +size 33119 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.notifications.edit_EditDefaultNotificationSettingView_null_EditDefaultNotificationSettingView-Night-8_10_null_1,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.notifications.edit_EditDefaultNotificationSettingView_null_EditDefaultNotificationSettingView-Night-8_10_null_1,NEXUS_5,1.0,en].png index 9c4e212b7e..9460689a1b 100644 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.notifications.edit_EditDefaultNotificationSettingView_null_EditDefaultNotificationSettingView-Night-8_10_null_1,NEXUS_5,1.0,en].png +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.notifications.edit_EditDefaultNotificationSettingView_null_EditDefaultNotificationSettingView-Night-8_10_null_1,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:d0fa8bac7f79b1a4feb4b7e808afae0c6b897867539c234daa9faea1bf6daf6e -size 33021 +oid sha256:bf6f825427bab3e344617e78971521a1cbbd2daaaf132334b8bd32335111c605 +size 33075 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.notifications.edit_EditDefaultNotificationSettingView_null_EditDefaultNotificationSettingView-Night-8_10_null_2,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.notifications.edit_EditDefaultNotificationSettingView_null_EditDefaultNotificationSettingView-Night-8_10_null_2,NEXUS_5,1.0,en].png index bc7f9d3c2c..15f32e9239 100644 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.notifications.edit_EditDefaultNotificationSettingView_null_EditDefaultNotificationSettingView-Night-8_10_null_2,NEXUS_5,1.0,en].png +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.notifications.edit_EditDefaultNotificationSettingView_null_EditDefaultNotificationSettingView-Night-8_10_null_2,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:c8f2cc0a8cf7303aef994db2d23efb83b7a8a1c74af39dcef61ae3cfd3277c65 -size 30350 +oid sha256:144fe1c105acf228ddf28d29f141cff5eca275529e11e38877bdfc8c5a37065f +size 29042 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.notifications.edit_EditDefaultNotificationSettingView_null_EditDefaultNotificationSettingView-Night-8_10_null_3,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.notifications.edit_EditDefaultNotificationSettingView_null_EditDefaultNotificationSettingView-Night-8_10_null_3,NEXUS_5,1.0,en].png index 0048715eb9..546f033245 100644 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.notifications.edit_EditDefaultNotificationSettingView_null_EditDefaultNotificationSettingView-Night-8_10_null_3,NEXUS_5,1.0,en].png +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.notifications.edit_EditDefaultNotificationSettingView_null_EditDefaultNotificationSettingView-Night-8_10_null_3,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:5dfc5747625a6743966a518dd693cd8c55899ca241005df8179167b1728c2589 -size 32274 +oid sha256:e7e8b50a6e456b812b0ae5a58442361d85051951979634f89148e09812c0bada +size 32312 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.notifications.edit_EditDefaultNotificationSettingView_null_EditDefaultNotificationSettingView-Night-8_10_null_4,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.notifications.edit_EditDefaultNotificationSettingView_null_EditDefaultNotificationSettingView-Night-8_10_null_4,NEXUS_5,1.0,en].png index 4877789704..949f04d314 100644 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.notifications.edit_EditDefaultNotificationSettingView_null_EditDefaultNotificationSettingView-Night-8_10_null_4,NEXUS_5,1.0,en].png +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.notifications.edit_EditDefaultNotificationSettingView_null_EditDefaultNotificationSettingView-Night-8_10_null_4,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:19e89d8cab891198e62951c0b08ed1318a14347795a35b5e8d94f6358c9f1964 -size 47052 +oid sha256:3105639c450f6f867cf5592c2cc5c029f20d01c31273ac2eb7680d8d9548f1c0 +size 47447 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl.notificationsettings_RoomNotificationSettings_null_RoomNotificationSettings-Day-4_5_null_0,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl.notificationsettings_RoomNotificationSettings_null_RoomNotificationSettings-Day-4_5_null_0,NEXUS_5,1.0,en].png index cc6fb20b61..d557a9dbb9 100644 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl.notificationsettings_RoomNotificationSettings_null_RoomNotificationSettings-Day-4_5_null_0,NEXUS_5,1.0,en].png +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl.notificationsettings_RoomNotificationSettings_null_RoomNotificationSettings-Day-4_5_null_0,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:44096d9f97614b5e84cf5dd0d966f674b47b50da065daaaa4a70476b3ecdcf91 -size 33908 +oid sha256:8cea32585e950298058338f5a195ac4a4699f04aa60adb5d794da26dbe43a64f +size 33848 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl.notificationsettings_RoomNotificationSettings_null_RoomNotificationSettings-Day-4_5_null_1,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl.notificationsettings_RoomNotificationSettings_null_RoomNotificationSettings-Day-4_5_null_1,NEXUS_5,1.0,en].png index 1dea7481b0..eb40963185 100644 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl.notificationsettings_RoomNotificationSettings_null_RoomNotificationSettings-Day-4_5_null_1,NEXUS_5,1.0,en].png +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl.notificationsettings_RoomNotificationSettings_null_RoomNotificationSettings-Day-4_5_null_1,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:605ab2a5cc9b2b10c09908a2f9dd3629f1731742909936ae180c74855e32eed8 -size 37695 +oid sha256:96db0b988e47a0e3cbaae3982561053f4c7a68a3d0f475c2723619cfce8f891a +size 37959 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl.notificationsettings_RoomNotificationSettings_null_RoomNotificationSettings-Day-4_5_null_2,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl.notificationsettings_RoomNotificationSettings_null_RoomNotificationSettings-Day-4_5_null_2,NEXUS_5,1.0,en].png index 830c17b5a7..dc91bf4970 100644 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl.notificationsettings_RoomNotificationSettings_null_RoomNotificationSettings-Day-4_5_null_2,NEXUS_5,1.0,en].png +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl.notificationsettings_RoomNotificationSettings_null_RoomNotificationSettings-Day-4_5_null_2,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:ccab888ebe0e5ed94f2cb00117e3d69a888ad656b985768dc08e7fddacdceee7 -size 34011 +oid sha256:c4b244008a0a0946605641e26ac1ee2b2ed0d689af8e45223458cd06d54970cf +size 33905 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl.notificationsettings_RoomNotificationSettings_null_RoomNotificationSettings-Day-4_5_null_3,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl.notificationsettings_RoomNotificationSettings_null_RoomNotificationSettings-Day-4_5_null_3,NEXUS_5,1.0,en].png index 8ed21af54b..46cdd3df16 100644 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl.notificationsettings_RoomNotificationSettings_null_RoomNotificationSettings-Day-4_5_null_3,NEXUS_5,1.0,en].png +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl.notificationsettings_RoomNotificationSettings_null_RoomNotificationSettings-Day-4_5_null_3,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:1510614f000837b743b847e616f7e40e86a259846058c1c0ea7a41233392117b -size 41239 +oid sha256:60dbf7ac48dc77b79f80c15ea811381ee5885e2c5f702e522e789f16672c694b +size 41164 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl.notificationsettings_RoomNotificationSettings_null_RoomNotificationSettings-Day-4_5_null_4,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl.notificationsettings_RoomNotificationSettings_null_RoomNotificationSettings-Day-4_5_null_4,NEXUS_5,1.0,en].png index 830c17b5a7..dc91bf4970 100644 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl.notificationsettings_RoomNotificationSettings_null_RoomNotificationSettings-Day-4_5_null_4,NEXUS_5,1.0,en].png +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl.notificationsettings_RoomNotificationSettings_null_RoomNotificationSettings-Day-4_5_null_4,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:ccab888ebe0e5ed94f2cb00117e3d69a888ad656b985768dc08e7fddacdceee7 -size 34011 +oid sha256:c4b244008a0a0946605641e26ac1ee2b2ed0d689af8e45223458cd06d54970cf +size 33905 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl.notificationsettings_RoomNotificationSettings_null_RoomNotificationSettings-Day-4_5_null_5,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl.notificationsettings_RoomNotificationSettings_null_RoomNotificationSettings-Day-4_5_null_5,NEXUS_5,1.0,en].png index 8ed21af54b..46cdd3df16 100644 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl.notificationsettings_RoomNotificationSettings_null_RoomNotificationSettings-Day-4_5_null_5,NEXUS_5,1.0,en].png +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl.notificationsettings_RoomNotificationSettings_null_RoomNotificationSettings-Day-4_5_null_5,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:1510614f000837b743b847e616f7e40e86a259846058c1c0ea7a41233392117b -size 41239 +oid sha256:60dbf7ac48dc77b79f80c15ea811381ee5885e2c5f702e522e789f16672c694b +size 41164 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl.notificationsettings_RoomNotificationSettings_null_RoomNotificationSettings-Day-4_5_null_6,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl.notificationsettings_RoomNotificationSettings_null_RoomNotificationSettings-Day-4_5_null_6,NEXUS_5,1.0,en].png index cc6fb20b61..d557a9dbb9 100644 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl.notificationsettings_RoomNotificationSettings_null_RoomNotificationSettings-Day-4_5_null_6,NEXUS_5,1.0,en].png +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl.notificationsettings_RoomNotificationSettings_null_RoomNotificationSettings-Day-4_5_null_6,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:44096d9f97614b5e84cf5dd0d966f674b47b50da065daaaa4a70476b3ecdcf91 -size 33908 +oid sha256:8cea32585e950298058338f5a195ac4a4699f04aa60adb5d794da26dbe43a64f +size 33848 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl.notificationsettings_RoomNotificationSettings_null_RoomNotificationSettings-Night-4_6_null_0,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl.notificationsettings_RoomNotificationSettings_null_RoomNotificationSettings-Night-4_6_null_0,NEXUS_5,1.0,en].png index f9df86aa2f..fda8ee34bd 100644 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl.notificationsettings_RoomNotificationSettings_null_RoomNotificationSettings-Night-4_6_null_0,NEXUS_5,1.0,en].png +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl.notificationsettings_RoomNotificationSettings_null_RoomNotificationSettings-Night-4_6_null_0,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:ef6d0fe324b2f622732cfbda77b55bd5debaf058eadd278f820a23de7c164103 -size 31553 +oid sha256:ab4197e309e72fb1e486210ef92655b18814eb1f21e9cbcb1e6e60ec7fc8627a +size 31463 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl.notificationsettings_RoomNotificationSettings_null_RoomNotificationSettings-Night-4_6_null_1,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl.notificationsettings_RoomNotificationSettings_null_RoomNotificationSettings-Night-4_6_null_1,NEXUS_5,1.0,en].png index 8443ee647a..876b8499fd 100644 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl.notificationsettings_RoomNotificationSettings_null_RoomNotificationSettings-Night-4_6_null_1,NEXUS_5,1.0,en].png +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl.notificationsettings_RoomNotificationSettings_null_RoomNotificationSettings-Night-4_6_null_1,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:4af656ee89190d8b818e2dfa1c260afca60c4b5f3e24ec6f4d30fe0cd2ed267d -size 34758 +oid sha256:103e9412a0a04a5c98290ef51670fbcfaf64b6d76e62fcecf486cb777c4373fa +size 35088 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl.notificationsettings_RoomNotificationSettings_null_RoomNotificationSettings-Night-4_6_null_2,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl.notificationsettings_RoomNotificationSettings_null_RoomNotificationSettings-Night-4_6_null_2,NEXUS_5,1.0,en].png index 858a3576a3..da1bde323f 100644 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl.notificationsettings_RoomNotificationSettings_null_RoomNotificationSettings-Night-4_6_null_2,NEXUS_5,1.0,en].png +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl.notificationsettings_RoomNotificationSettings_null_RoomNotificationSettings-Night-4_6_null_2,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:fddde23759a830f0e0ed9bab9d1754970ce2b2e8ffa78c02c458b090dbbb76aa -size 30719 +oid sha256:41b7d2e99dc922af5990a87bea479cefa1da0a274e373d88b3505df0b13ff05a +size 30622 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl.notificationsettings_RoomNotificationSettings_null_RoomNotificationSettings-Night-4_6_null_3,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl.notificationsettings_RoomNotificationSettings_null_RoomNotificationSettings-Night-4_6_null_3,NEXUS_5,1.0,en].png index e3d95f0f75..2be1daa946 100644 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl.notificationsettings_RoomNotificationSettings_null_RoomNotificationSettings-Night-4_6_null_3,NEXUS_5,1.0,en].png +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl.notificationsettings_RoomNotificationSettings_null_RoomNotificationSettings-Night-4_6_null_3,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:c78c34bc3f0df68b9130263ac5d35ac1c8b6f98a0e9aa0316461b473653dedc5 -size 36730 +oid sha256:052a42e15095538d05231b73fd7f5259bd3782d1b280ef0726a0445a9dd719ad +size 36640 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl.notificationsettings_RoomNotificationSettings_null_RoomNotificationSettings-Night-4_6_null_4,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl.notificationsettings_RoomNotificationSettings_null_RoomNotificationSettings-Night-4_6_null_4,NEXUS_5,1.0,en].png index 858a3576a3..da1bde323f 100644 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl.notificationsettings_RoomNotificationSettings_null_RoomNotificationSettings-Night-4_6_null_4,NEXUS_5,1.0,en].png +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl.notificationsettings_RoomNotificationSettings_null_RoomNotificationSettings-Night-4_6_null_4,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:fddde23759a830f0e0ed9bab9d1754970ce2b2e8ffa78c02c458b090dbbb76aa -size 30719 +oid sha256:41b7d2e99dc922af5990a87bea479cefa1da0a274e373d88b3505df0b13ff05a +size 30622 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl.notificationsettings_RoomNotificationSettings_null_RoomNotificationSettings-Night-4_6_null_5,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl.notificationsettings_RoomNotificationSettings_null_RoomNotificationSettings-Night-4_6_null_5,NEXUS_5,1.0,en].png index e3d95f0f75..2be1daa946 100644 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl.notificationsettings_RoomNotificationSettings_null_RoomNotificationSettings-Night-4_6_null_5,NEXUS_5,1.0,en].png +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl.notificationsettings_RoomNotificationSettings_null_RoomNotificationSettings-Night-4_6_null_5,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:c78c34bc3f0df68b9130263ac5d35ac1c8b6f98a0e9aa0316461b473653dedc5 -size 36730 +oid sha256:052a42e15095538d05231b73fd7f5259bd3782d1b280ef0726a0445a9dd719ad +size 36640 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl.notificationsettings_RoomNotificationSettings_null_RoomNotificationSettings-Night-4_6_null_6,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl.notificationsettings_RoomNotificationSettings_null_RoomNotificationSettings-Night-4_6_null_6,NEXUS_5,1.0,en].png index f9df86aa2f..fda8ee34bd 100644 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl.notificationsettings_RoomNotificationSettings_null_RoomNotificationSettings-Night-4_6_null_6,NEXUS_5,1.0,en].png +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl.notificationsettings_RoomNotificationSettings_null_RoomNotificationSettings-Night-4_6_null_6,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:ef6d0fe324b2f622732cfbda77b55bd5debaf058eadd278f820a23de7c164103 -size 31553 +oid sha256:ab4197e309e72fb1e486210ef92655b18814eb1f21e9cbcb1e6e60ec7fc8627a +size 31463 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl.notificationsettings_RoomPrivacyOption_null_RoomPrivacyOption-Day-3_4_null,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl.notificationsettings_RoomPrivacyOption_null_RoomPrivacyOption-Day-3_4_null,NEXUS_5,1.0,en].png index c6d3aa92c7..eeef333d47 100644 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl.notificationsettings_RoomPrivacyOption_null_RoomPrivacyOption-Day-3_4_null,NEXUS_5,1.0,en].png +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl.notificationsettings_RoomPrivacyOption_null_RoomPrivacyOption-Day-3_4_null,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:3a3cb6371045e712f494857cd35268724936558550e7dc41344581fd2a1936c3 -size 31012 +oid sha256:1ed4d3d6c3148ea14e1680c9f7c3af86bc5158a3ffa8ce3f2b62283983bc91f4 +size 31166 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl.notificationsettings_RoomPrivacyOption_null_RoomPrivacyOption-Night-3_5_null,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl.notificationsettings_RoomPrivacyOption_null_RoomPrivacyOption-Night-3_5_null,NEXUS_5,1.0,en].png index a4e863f338..02479078b6 100644 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl.notificationsettings_RoomPrivacyOption_null_RoomPrivacyOption-Night-3_5_null,NEXUS_5,1.0,en].png +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl.notificationsettings_RoomPrivacyOption_null_RoomPrivacyOption-Night-3_5_null,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:ee41b24ea7b2ca8b7c9fa568c0a66537ec9d39c7fc80bf99bfda1592156ec174 -size 29041 +oid sha256:1a5a64aab614f944cef77887b0c9e848e4273d8e2acf0561aafd28a064767937 +size 29319 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl.notificationsettings_UserDefinedRoomNotificationSettings_null_UserDefinedRoomNotificationSettings-Day-5_6_null_0,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl.notificationsettings_UserDefinedRoomNotificationSettings_null_UserDefinedRoomNotificationSettings-Day-5_6_null_0,NEXUS_5,1.0,en].png index d9c14068b9..05521df511 100644 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl.notificationsettings_UserDefinedRoomNotificationSettings_null_UserDefinedRoomNotificationSettings-Day-5_6_null_0,NEXUS_5,1.0,en].png +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl.notificationsettings_UserDefinedRoomNotificationSettings_null_UserDefinedRoomNotificationSettings-Day-5_6_null_0,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:ffb71a4dbd1324963ead4b188986a6c90dc6755a5d49e520c5aa74d3cce00384 -size 24290 +oid sha256:ca0abf8c339aeb7ccaf6e6dd4482288bae180319dbf9f5c25b5ec65011c6838b +size 24211 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl.notificationsettings_UserDefinedRoomNotificationSettings_null_UserDefinedRoomNotificationSettings-Night-5_7_null_0,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl.notificationsettings_UserDefinedRoomNotificationSettings_null_UserDefinedRoomNotificationSettings-Night-5_7_null_0,NEXUS_5,1.0,en].png index 43e51c8aaf..016645f55d 100644 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl.notificationsettings_UserDefinedRoomNotificationSettings_null_UserDefinedRoomNotificationSettings-Night-5_7_null_0,NEXUS_5,1.0,en].png +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl.notificationsettings_UserDefinedRoomNotificationSettings_null_UserDefinedRoomNotificationSettings-Night-5_7_null_0,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:132d77ede5c96774b958b79ec3143c99a66734b04659796351a7b127ab3e2243 -size 22852 +oid sha256:aa8dfdcdacf72109ab7b0944e3af0f7cbdd6ae2ad42429128f0885483baed011 +size 22630 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[l.matrix.ui.components_CheckableMatrixUserRow_null_CheckableMatrixUserRow-Day-2_3_null_0,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[l.matrix.ui.components_CheckableMatrixUserRow_null_CheckableMatrixUserRow-Day-2_3_null_0,NEXUS_5,1.0,en].png deleted file mode 100644 index 28c78fd115..0000000000 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[l.matrix.ui.components_CheckableMatrixUserRow_null_CheckableMatrixUserRow-Day-2_3_null_0,NEXUS_5,1.0,en].png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:2d91c6228c80d1d38217e557552e18e64494a94d284de8702d07cc3793150406 -size 29177 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[l.matrix.ui.components_CheckableMatrixUserRow_null_CheckableMatrixUserRow-Day-2_3_null_1,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[l.matrix.ui.components_CheckableMatrixUserRow_null_CheckableMatrixUserRow-Day-2_3_null_1,NEXUS_5,1.0,en].png deleted file mode 100644 index f1abda92fc..0000000000 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[l.matrix.ui.components_CheckableMatrixUserRow_null_CheckableMatrixUserRow-Day-2_3_null_1,NEXUS_5,1.0,en].png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:eeb5b50675e186318458d0900b2d3872ec52710df8e25ba7b633a4be7e13c8da -size 28196 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[l.matrix.ui.components_CheckableMatrixUserRow_null_CheckableMatrixUserRow-Night-2_4_null_0,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[l.matrix.ui.components_CheckableMatrixUserRow_null_CheckableMatrixUserRow-Night-2_4_null_0,NEXUS_5,1.0,en].png deleted file mode 100644 index f7861fa9c7..0000000000 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[l.matrix.ui.components_CheckableMatrixUserRow_null_CheckableMatrixUserRow-Night-2_4_null_0,NEXUS_5,1.0,en].png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:35d63106802f7bce6ddc7ae56a2b206120e9eba1459169480a10bcc5a0d3f9e3 -size 29334 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[l.matrix.ui.components_CheckableMatrixUserRow_null_CheckableMatrixUserRow-Night-2_4_null_1,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[l.matrix.ui.components_CheckableMatrixUserRow_null_CheckableMatrixUserRow-Night-2_4_null_1,NEXUS_5,1.0,en].png deleted file mode 100644 index fcd01bd2aa..0000000000 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[l.matrix.ui.components_CheckableMatrixUserRow_null_CheckableMatrixUserRow-Night-2_4_null_1,NEXUS_5,1.0,en].png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:3e4c742ac4907f79f5830f2fed5fbacc4ae352e24fcf7e15b75f3f3d8ce85ab2 -size 27151 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[l.matrix.ui.components_CheckableResolvedUserRow_null_CheckableResolvedUserRow_0_null,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[l.matrix.ui.components_CheckableResolvedUserRow_null_CheckableResolvedUserRow_0_null,NEXUS_5,1.0,en].png new file mode 100644 index 0000000000..bc072adaf6 --- /dev/null +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[l.matrix.ui.components_CheckableResolvedUserRow_null_CheckableResolvedUserRow_0_null,NEXUS_5,1.0,en].png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:9ffaad9291e2a8bb3168b08365faac8417a77dbe1e39e94cd4f1d7dfb12ef7e4 +size 54838 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[l.matrix.ui.components_CheckableUnresolvedUserRow_null_CheckableUnresolvedUserRow_0_null,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[l.matrix.ui.components_CheckableUnresolvedUserRow_null_CheckableUnresolvedUserRow_0_null,NEXUS_5,1.0,en].png index 5d459747a8..69d51f01ad 100644 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[l.matrix.ui.components_CheckableUnresolvedUserRow_null_CheckableUnresolvedUserRow_0_null,NEXUS_5,1.0,en].png +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[l.matrix.ui.components_CheckableUnresolvedUserRow_null_CheckableUnresolvedUserRow_0_null,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:3dd3995ea7bdf218f55d2883fade50c29558d2ed2faca318c8d18a0eb7f06a34 -size 116197 +oid sha256:85ead49e9a818ddc9b337e8386b78d80dcb1723e8f77cb8fe4ce5278680eb6a9 +size 116251 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[l.matrix.ui.components_MatrixUserHeaderPlaceholder_null_MatrixUserHeaderPlaceholder-Day-4_5_null,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[l.matrix.ui.components_MatrixUserHeaderPlaceholder_null_MatrixUserHeaderPlaceholder-Day-3_4_null,NEXUS_5,1.0,en].png similarity index 100% rename from tests/uitests/src/test/snapshots/images/ui_S_t[l.matrix.ui.components_MatrixUserHeaderPlaceholder_null_MatrixUserHeaderPlaceholder-Day-4_5_null,NEXUS_5,1.0,en].png rename to tests/uitests/src/test/snapshots/images/ui_S_t[l.matrix.ui.components_MatrixUserHeaderPlaceholder_null_MatrixUserHeaderPlaceholder-Day-3_4_null,NEXUS_5,1.0,en].png diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[l.matrix.ui.components_MatrixUserHeaderPlaceholder_null_MatrixUserHeaderPlaceholder-Night-4_6_null,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[l.matrix.ui.components_MatrixUserHeaderPlaceholder_null_MatrixUserHeaderPlaceholder-Night-3_5_null,NEXUS_5,1.0,en].png similarity index 100% rename from tests/uitests/src/test/snapshots/images/ui_S_t[l.matrix.ui.components_MatrixUserHeaderPlaceholder_null_MatrixUserHeaderPlaceholder-Night-4_6_null,NEXUS_5,1.0,en].png rename to tests/uitests/src/test/snapshots/images/ui_S_t[l.matrix.ui.components_MatrixUserHeaderPlaceholder_null_MatrixUserHeaderPlaceholder-Night-3_5_null,NEXUS_5,1.0,en].png diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[l.matrix.ui.components_MatrixUserHeader_null_MatrixUserHeader-Day-3_4_null_0,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[l.matrix.ui.components_MatrixUserHeader_null_MatrixUserHeader-Day-2_3_null_0,NEXUS_5,1.0,en].png similarity index 100% rename from tests/uitests/src/test/snapshots/images/ui_S_t[l.matrix.ui.components_MatrixUserHeader_null_MatrixUserHeader-Day-3_4_null_0,NEXUS_5,1.0,en].png rename to tests/uitests/src/test/snapshots/images/ui_S_t[l.matrix.ui.components_MatrixUserHeader_null_MatrixUserHeader-Day-2_3_null_0,NEXUS_5,1.0,en].png diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[l.matrix.ui.components_MatrixUserHeader_null_MatrixUserHeader-Day-3_4_null_1,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[l.matrix.ui.components_MatrixUserHeader_null_MatrixUserHeader-Day-2_3_null_1,NEXUS_5,1.0,en].png similarity index 100% rename from tests/uitests/src/test/snapshots/images/ui_S_t[l.matrix.ui.components_MatrixUserHeader_null_MatrixUserHeader-Day-3_4_null_1,NEXUS_5,1.0,en].png rename to tests/uitests/src/test/snapshots/images/ui_S_t[l.matrix.ui.components_MatrixUserHeader_null_MatrixUserHeader-Day-2_3_null_1,NEXUS_5,1.0,en].png diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[l.matrix.ui.components_MatrixUserHeader_null_MatrixUserHeader-Night-3_5_null_0,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[l.matrix.ui.components_MatrixUserHeader_null_MatrixUserHeader-Night-2_4_null_0,NEXUS_5,1.0,en].png similarity index 100% rename from tests/uitests/src/test/snapshots/images/ui_S_t[l.matrix.ui.components_MatrixUserHeader_null_MatrixUserHeader-Night-3_5_null_0,NEXUS_5,1.0,en].png rename to tests/uitests/src/test/snapshots/images/ui_S_t[l.matrix.ui.components_MatrixUserHeader_null_MatrixUserHeader-Night-2_4_null_0,NEXUS_5,1.0,en].png diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[l.matrix.ui.components_MatrixUserHeader_null_MatrixUserHeader-Night-3_5_null_1,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[l.matrix.ui.components_MatrixUserHeader_null_MatrixUserHeader-Night-2_4_null_1,NEXUS_5,1.0,en].png similarity index 100% rename from tests/uitests/src/test/snapshots/images/ui_S_t[l.matrix.ui.components_MatrixUserHeader_null_MatrixUserHeader-Night-3_5_null_1,NEXUS_5,1.0,en].png rename to tests/uitests/src/test/snapshots/images/ui_S_t[l.matrix.ui.components_MatrixUserHeader_null_MatrixUserHeader-Night-2_4_null_1,NEXUS_5,1.0,en].png diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[l.matrix.ui.components_MatrixUserRow_null_MatrixUserRow-Day-5_6_null_0,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[l.matrix.ui.components_MatrixUserRow_null_MatrixUserRow-Day-4_5_null_0,NEXUS_5,1.0,en].png similarity index 100% rename from tests/uitests/src/test/snapshots/images/ui_S_t[l.matrix.ui.components_MatrixUserRow_null_MatrixUserRow-Day-5_6_null_0,NEXUS_5,1.0,en].png rename to tests/uitests/src/test/snapshots/images/ui_S_t[l.matrix.ui.components_MatrixUserRow_null_MatrixUserRow-Day-4_5_null_0,NEXUS_5,1.0,en].png diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[l.matrix.ui.components_MatrixUserRow_null_MatrixUserRow-Day-5_6_null_1,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[l.matrix.ui.components_MatrixUserRow_null_MatrixUserRow-Day-4_5_null_1,NEXUS_5,1.0,en].png similarity index 100% rename from tests/uitests/src/test/snapshots/images/ui_S_t[l.matrix.ui.components_MatrixUserRow_null_MatrixUserRow-Day-5_6_null_1,NEXUS_5,1.0,en].png rename to tests/uitests/src/test/snapshots/images/ui_S_t[l.matrix.ui.components_MatrixUserRow_null_MatrixUserRow-Day-4_5_null_1,NEXUS_5,1.0,en].png diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[l.matrix.ui.components_MatrixUserRow_null_MatrixUserRow-Night-5_7_null_0,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[l.matrix.ui.components_MatrixUserRow_null_MatrixUserRow-Night-4_6_null_0,NEXUS_5,1.0,en].png similarity index 100% rename from tests/uitests/src/test/snapshots/images/ui_S_t[l.matrix.ui.components_MatrixUserRow_null_MatrixUserRow-Night-5_7_null_0,NEXUS_5,1.0,en].png rename to tests/uitests/src/test/snapshots/images/ui_S_t[l.matrix.ui.components_MatrixUserRow_null_MatrixUserRow-Night-4_6_null_0,NEXUS_5,1.0,en].png diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[l.matrix.ui.components_MatrixUserRow_null_MatrixUserRow-Night-5_7_null_1,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[l.matrix.ui.components_MatrixUserRow_null_MatrixUserRow-Night-4_6_null_1,NEXUS_5,1.0,en].png similarity index 100% rename from tests/uitests/src/test/snapshots/images/ui_S_t[l.matrix.ui.components_MatrixUserRow_null_MatrixUserRow-Night-5_7_null_1,NEXUS_5,1.0,en].png rename to tests/uitests/src/test/snapshots/images/ui_S_t[l.matrix.ui.components_MatrixUserRow_null_MatrixUserRow-Night-4_6_null_1,NEXUS_5,1.0,en].png diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[l.matrix.ui.components_SelectedRoom_null_SelectedRoom-Day-6_7_null,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[l.matrix.ui.components_SelectedRoom_null_SelectedRoom-Day-5_6_null,NEXUS_5,1.0,en].png similarity index 100% rename from tests/uitests/src/test/snapshots/images/ui_S_t[l.matrix.ui.components_SelectedRoom_null_SelectedRoom-Day-6_7_null,NEXUS_5,1.0,en].png rename to tests/uitests/src/test/snapshots/images/ui_S_t[l.matrix.ui.components_SelectedRoom_null_SelectedRoom-Day-5_6_null,NEXUS_5,1.0,en].png diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[l.matrix.ui.components_SelectedRoom_null_SelectedRoom-Night-6_8_null,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[l.matrix.ui.components_SelectedRoom_null_SelectedRoom-Night-5_7_null,NEXUS_5,1.0,en].png similarity index 100% rename from tests/uitests/src/test/snapshots/images/ui_S_t[l.matrix.ui.components_SelectedRoom_null_SelectedRoom-Night-6_8_null,NEXUS_5,1.0,en].png rename to tests/uitests/src/test/snapshots/images/ui_S_t[l.matrix.ui.components_SelectedRoom_null_SelectedRoom-Night-5_7_null,NEXUS_5,1.0,en].png diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[l.matrix.ui.components_SelectedUser_null_SelectedUser-Day-7_8_null,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[l.matrix.ui.components_SelectedUser_null_SelectedUser-Day-6_7_null,NEXUS_5,1.0,en].png similarity index 100% rename from tests/uitests/src/test/snapshots/images/ui_S_t[l.matrix.ui.components_SelectedUser_null_SelectedUser-Day-7_8_null,NEXUS_5,1.0,en].png rename to tests/uitests/src/test/snapshots/images/ui_S_t[l.matrix.ui.components_SelectedUser_null_SelectedUser-Day-6_7_null,NEXUS_5,1.0,en].png diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[l.matrix.ui.components_SelectedUser_null_SelectedUser-Night-7_9_null,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[l.matrix.ui.components_SelectedUser_null_SelectedUser-Night-6_8_null,NEXUS_5,1.0,en].png similarity index 100% rename from tests/uitests/src/test/snapshots/images/ui_S_t[l.matrix.ui.components_SelectedUser_null_SelectedUser-Night-7_9_null,NEXUS_5,1.0,en].png rename to tests/uitests/src/test/snapshots/images/ui_S_t[l.matrix.ui.components_SelectedUser_null_SelectedUser-Night-6_8_null,NEXUS_5,1.0,en].png diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[l.matrix.ui.components_SelectedUsersList_null_SelectedUsersList-Day-8_9_null,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[l.matrix.ui.components_SelectedUsersList_null_SelectedUsersList-Day-7_8_null,NEXUS_5,1.0,en].png similarity index 100% rename from tests/uitests/src/test/snapshots/images/ui_S_t[l.matrix.ui.components_SelectedUsersList_null_SelectedUsersList-Day-8_9_null,NEXUS_5,1.0,en].png rename to tests/uitests/src/test/snapshots/images/ui_S_t[l.matrix.ui.components_SelectedUsersList_null_SelectedUsersList-Day-7_8_null,NEXUS_5,1.0,en].png diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[l.matrix.ui.components_SelectedUsersList_null_SelectedUsersList-Night-8_10_null,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[l.matrix.ui.components_SelectedUsersList_null_SelectedUsersList-Night-7_9_null,NEXUS_5,1.0,en].png similarity index 100% rename from tests/uitests/src/test/snapshots/images/ui_S_t[l.matrix.ui.components_SelectedUsersList_null_SelectedUsersList-Night-8_10_null,NEXUS_5,1.0,en].png rename to tests/uitests/src/test/snapshots/images/ui_S_t[l.matrix.ui.components_SelectedUsersList_null_SelectedUsersList-Night-7_9_null,NEXUS_5,1.0,en].png diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[l.matrix.ui.components_UnsavedAvatar_null_UnsavedAvatar-Day-9_10_null,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[l.matrix.ui.components_UnsavedAvatar_null_UnsavedAvatar-Day-8_9_null,NEXUS_5,1.0,en].png similarity index 100% rename from tests/uitests/src/test/snapshots/images/ui_S_t[l.matrix.ui.components_UnsavedAvatar_null_UnsavedAvatar-Day-9_10_null,NEXUS_5,1.0,en].png rename to tests/uitests/src/test/snapshots/images/ui_S_t[l.matrix.ui.components_UnsavedAvatar_null_UnsavedAvatar-Day-8_9_null,NEXUS_5,1.0,en].png diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[l.matrix.ui.components_UnsavedAvatar_null_UnsavedAvatar-Night-9_11_null,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[l.matrix.ui.components_UnsavedAvatar_null_UnsavedAvatar-Night-8_10_null,NEXUS_5,1.0,en].png similarity index 100% rename from tests/uitests/src/test/snapshots/images/ui_S_t[l.matrix.ui.components_UnsavedAvatar_null_UnsavedAvatar-Night-9_11_null,NEXUS_5,1.0,en].png rename to tests/uitests/src/test/snapshots/images/ui_S_t[l.matrix.ui.components_UnsavedAvatar_null_UnsavedAvatar-Night-8_10_null,NEXUS_5,1.0,en].png From 631b7d34d3ffe2b64fe06d9bc1a27746383d0ba6 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Wed, 31 Jan 2024 10:05:59 +0100 Subject: [PATCH 126/127] Changelog for version 0.4.2 --- CHANGES.md | 34 +++++++++++++++++++ ...l-tracing-configuration-for-nightlies.misc | 1 - .../+try-mitigating-unexpected-logouts.misc | 3 -- ...ade-material3-compose-to-1.2.0-beta02.misc | 3 -- changelog.d/2176.bugfix | 1 - changelog.d/2204.feature | 1 - changelog.d/2215.misc | 1 - changelog.d/2217.misc | 1 - changelog.d/2219.misc | 1 - changelog.d/2224.misc | 1 - changelog.d/2240.feature | 1 - changelog.d/2248.misc | 1 - changelog.d/2260.bugfix | 1 - changelog.d/2263.bugfix | 1 - changelog.d/2275.misc | 1 - changelog.d/2276.misc | 1 - changelog.d/2282.bugfix | 1 - changelog.d/2308.bugfix | 1 - changelog.d/921.bugfix | 1 - 19 files changed, 34 insertions(+), 22 deletions(-) delete mode 100644 changelog.d/+add-special-tracing-configuration-for-nightlies.misc delete mode 100644 changelog.d/+try-mitigating-unexpected-logouts.misc delete mode 100644 changelog.d/+upgrade-material3-compose-to-1.2.0-beta02.misc delete mode 100644 changelog.d/2176.bugfix delete mode 100644 changelog.d/2204.feature delete mode 100644 changelog.d/2215.misc delete mode 100644 changelog.d/2217.misc delete mode 100644 changelog.d/2219.misc delete mode 100644 changelog.d/2224.misc delete mode 100644 changelog.d/2240.feature delete mode 100644 changelog.d/2248.misc delete mode 100644 changelog.d/2260.bugfix delete mode 100644 changelog.d/2263.bugfix delete mode 100644 changelog.d/2275.misc delete mode 100644 changelog.d/2276.misc delete mode 100644 changelog.d/2282.bugfix delete mode 100644 changelog.d/2308.bugfix delete mode 100644 changelog.d/921.bugfix diff --git a/CHANGES.md b/CHANGES.md index 3ceac1ef35..1688c6c86d 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,3 +1,37 @@ +Changes in Element X v0.4.2 (2024-01-31) +======================================== + +Matrix SDK 🦀 v0.1.95 + +Features ✨ +---------- + - Add 'send private read receipts' option in advanced settings ([#2204](https://github.com/element-hq/element-x-android/issues/2204)) + - Send typing notification ([#2240](https://github.com/element-hq/element-x-android/issues/2240)). Disabling the sending of typing notification and rendering typing notification will come soon. + +Bugfixes 🐛 +---------- + - Make the room settings screen update automatically when new room info (name, avatar, topic) is available. ([#921](https://github.com/element-hq/element-x-android/issues/921)) + - Update timeline items' read receipts when the room members info is loaded. ([#2176](https://github.com/element-hq/element-x-android/issues/2176)) + - Edited text message bubbles should resize when edited ([#2260](https://github.com/element-hq/element-x-android/issues/2260)) + - Ensure login and password exclude `\n` ([#2263](https://github.com/element-hq/element-x-android/issues/2263)) + - Room list Ensure the indicators stay grey if the global setting is set to mention only and a regular message is received. ([#2282](https://github.com/element-hq/element-x-android/issues/2282)) + +Other changes +------------- + - Add a special logging configuration for nightlies so we can get more detailed info for existing issues. ([#+add-special-tracing-configuration-for-nightlies](https://github.com/element-hq/element-x-android/issues/+add-special-tracing-configuration-for-nightlies)) + - Try mitigating unexpected logouts by making getting/storing session data use a Mutex for synchronization. + Also added some more logs so we can understand exactly where it's failing. ([#+try-mitigating-unexpected-logouts](https://github.com/element-hq/element-x-android/issues/+try-mitigating-unexpected-logouts)) + - Upgrade Material3 Compose to `1.2.0-beta02`. + There is also a constraint on a transitive Compose Foundation dependency version (1.6.0-beta02) that fixes the timeline scrolling issue. ([#0-beta02](https://github.com/element-hq/element-x-android/issues/0-beta02)) + - Disambiguate display name in the timeline. ([#2215](https://github.com/element-hq/element-x-android/issues/2215)) +- Disambiguate display name in notifications ([#2224](https://github.com/element-hq/element-x-android/issues/2224)) + - Remove room creation, self-join of room creator and 'this is the beginning of X' timeline items for DMs. ([#2217](https://github.com/element-hq/element-x-android/issues/2217)) + - Encrypt databases used by the Rust SDK on Nightly and Debug builds. ([#2219](https://github.com/element-hq/element-x-android/issues/2219)) + - Fallback to UnifiedPush (if available) if the PlayServices are not installed on the device. ([#2248](https://github.com/element-hq/element-x-android/issues/2248)) + - Add "Report a problem" button to the onboarding screen ([#2275](https://github.com/element-hq/element-x-android/issues/2275)) + - Add in app logs viewer to the "Report a problem" screen. ([#2276](https://github.com/element-hq/element-x-android/issues/2276)) + + Changes in Element X v0.4.1 (2024-01-17) ======================================== diff --git a/changelog.d/+add-special-tracing-configuration-for-nightlies.misc b/changelog.d/+add-special-tracing-configuration-for-nightlies.misc deleted file mode 100644 index 89f72f4332..0000000000 --- a/changelog.d/+add-special-tracing-configuration-for-nightlies.misc +++ /dev/null @@ -1 +0,0 @@ -Add a special logging configuration for nightlies so we can get more detailed info for existing issues. diff --git a/changelog.d/+try-mitigating-unexpected-logouts.misc b/changelog.d/+try-mitigating-unexpected-logouts.misc deleted file mode 100644 index e9b675ad71..0000000000 --- a/changelog.d/+try-mitigating-unexpected-logouts.misc +++ /dev/null @@ -1,3 +0,0 @@ -Try mitigating unexpected logouts by making getting/storing session data use a Mutex for synchronization. - -Also added some more logs so we can understand exactly where it's failing. diff --git a/changelog.d/+upgrade-material3-compose-to-1.2.0-beta02.misc b/changelog.d/+upgrade-material3-compose-to-1.2.0-beta02.misc deleted file mode 100644 index 65f4b287f9..0000000000 --- a/changelog.d/+upgrade-material3-compose-to-1.2.0-beta02.misc +++ /dev/null @@ -1,3 +0,0 @@ -Upgrade Material3 Compose to `1.2.0-beta02`. - -There is also a constraint on a transitive Compose Foundation dependency version (1.6.0-beta02) that fixes the timeline scrolling issue. diff --git a/changelog.d/2176.bugfix b/changelog.d/2176.bugfix deleted file mode 100644 index 7588dfdd3a..0000000000 --- a/changelog.d/2176.bugfix +++ /dev/null @@ -1 +0,0 @@ -Update timeline items' read receipts when the room members info is loaded. diff --git a/changelog.d/2204.feature b/changelog.d/2204.feature deleted file mode 100644 index 0a26acc5de..0000000000 --- a/changelog.d/2204.feature +++ /dev/null @@ -1 +0,0 @@ -Add 'send private read receipts' option in advanced settings diff --git a/changelog.d/2215.misc b/changelog.d/2215.misc deleted file mode 100644 index 1b343d2eb5..0000000000 --- a/changelog.d/2215.misc +++ /dev/null @@ -1 +0,0 @@ -Disambiguate display name in the timeline. diff --git a/changelog.d/2217.misc b/changelog.d/2217.misc deleted file mode 100644 index 40d4bd7fc6..0000000000 --- a/changelog.d/2217.misc +++ /dev/null @@ -1 +0,0 @@ -Remove room creation, self-join of room creator and 'this is the beginning of X' timeline items for DMs. diff --git a/changelog.d/2219.misc b/changelog.d/2219.misc deleted file mode 100644 index c8c11e8105..0000000000 --- a/changelog.d/2219.misc +++ /dev/null @@ -1 +0,0 @@ -Encrypt databases used by the Rust SDK on Nightly and Debug builds. diff --git a/changelog.d/2224.misc b/changelog.d/2224.misc deleted file mode 100644 index 6ec471f392..0000000000 --- a/changelog.d/2224.misc +++ /dev/null @@ -1 +0,0 @@ -Disambiguate display name in notifications diff --git a/changelog.d/2240.feature b/changelog.d/2240.feature deleted file mode 100644 index 99d98058c8..0000000000 --- a/changelog.d/2240.feature +++ /dev/null @@ -1 +0,0 @@ -Send typing notification diff --git a/changelog.d/2248.misc b/changelog.d/2248.misc deleted file mode 100644 index eed13375a0..0000000000 --- a/changelog.d/2248.misc +++ /dev/null @@ -1 +0,0 @@ -Fallback to UnifiedPush (if available) if the PlayServices are not installed on the device. diff --git a/changelog.d/2260.bugfix b/changelog.d/2260.bugfix deleted file mode 100644 index 23501e3264..0000000000 --- a/changelog.d/2260.bugfix +++ /dev/null @@ -1 +0,0 @@ -Edited text message bubbles should resize when edited diff --git a/changelog.d/2263.bugfix b/changelog.d/2263.bugfix deleted file mode 100644 index 016555ac44..0000000000 --- a/changelog.d/2263.bugfix +++ /dev/null @@ -1 +0,0 @@ -Ensure login and password exclude `\n` diff --git a/changelog.d/2275.misc b/changelog.d/2275.misc deleted file mode 100644 index ba8eabfebd..0000000000 --- a/changelog.d/2275.misc +++ /dev/null @@ -1 +0,0 @@ -Add "Report a problem" button to the onboarding screen diff --git a/changelog.d/2276.misc b/changelog.d/2276.misc deleted file mode 100644 index 47efbb63e9..0000000000 --- a/changelog.d/2276.misc +++ /dev/null @@ -1 +0,0 @@ -Add in app logs viewer to the "Report a problem" screen. diff --git a/changelog.d/2282.bugfix b/changelog.d/2282.bugfix deleted file mode 100644 index 959bc42189..0000000000 --- a/changelog.d/2282.bugfix +++ /dev/null @@ -1 +0,0 @@ -Room list Ensure the indicators stay grey if the global setting is set to mention only and a regular message is received. diff --git a/changelog.d/2308.bugfix b/changelog.d/2308.bugfix deleted file mode 100644 index 4c553c3899..0000000000 --- a/changelog.d/2308.bugfix +++ /dev/null @@ -1 +0,0 @@ -Fix 'There are multiple DataStores active for the same file' crashes diff --git a/changelog.d/921.bugfix b/changelog.d/921.bugfix deleted file mode 100644 index 939455b177..0000000000 --- a/changelog.d/921.bugfix +++ /dev/null @@ -1 +0,0 @@ -Make the room settings screen update automatically when new room info (name, avatar, topic) is available. From c06af4b8eaef79e1a75c499768d96b0211d99554 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Wed, 31 Jan 2024 10:07:33 +0100 Subject: [PATCH 127/127] Adding fastlane file for version 0.4.2 --- fastlane/metadata/android/en-US/changelogs/40004020.txt | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 fastlane/metadata/android/en-US/changelogs/40004020.txt diff --git a/fastlane/metadata/android/en-US/changelogs/40004020.txt b/fastlane/metadata/android/en-US/changelogs/40004020.txt new file mode 100644 index 0000000000..b55bf0be0d --- /dev/null +++ b/fastlane/metadata/android/en-US/changelogs/40004020.txt @@ -0,0 +1,2 @@ +Main changes in this version: be able to send a problem from the first screen, and add an internal log viewer. Be able to send private read receipt, send typing notification, improve performance. +Full changelog: https://github.com/element-hq/element-x-android/releases