diff --git a/.gitignore b/.gitignore index bde49b3cf4..12bdb4eda8 100644 --- a/.gitignore +++ b/.gitignore @@ -65,6 +65,9 @@ captures/ .idea/shelf .idea/sonarlint +# .kotlin folder +.kotlin + # Keystore files # Uncomment the following lines if you do not want to check your keystore files in. #*.jks diff --git a/.idea/kotlinc.xml b/.idea/kotlinc.xml index 4cb7457249..d4b7accbaa 100644 --- a/.idea/kotlinc.xml +++ b/.idea/kotlinc.xml @@ -1,6 +1,6 @@ - \ No newline at end of file diff --git a/CHANGES.md b/CHANGES.md index c3d343b303..54bfed06c2 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,3 +1,77 @@ +Changes in Element X v0.6.5 (2024-10-09) +======================================== + +## What's Changed +### ✨ Features +* Add developer setting to hide images in the timeline by @bmarty in https://github.com/element-hq/element-x-android/pull/3592 +* Warn the user when unverified user has changed their identity by @bmarty in https://github.com/element-hq/element-x-android/pull/3621 +### 🙌 Improvements +* Handle no network error when starting Element Call. by @bmarty in https://github.com/element-hq/element-x-android/pull/3527 +### 🐛 Bugfixes +* Fix room settings not treating unencrypted DMs as DMs by @jmartinesp in https://github.com/element-hq/element-x-android/pull/3545 +* Fix crash when aspectRatio is null. by @bmarty in https://github.com/element-hq/element-x-android/pull/3561 +* Don't delete uploaded logs by @jmartinesp in https://github.com/element-hq/element-x-android/pull/3540 +* Don't display security banner for unknown RecoveryState by @jmartinesp in https://github.com/element-hq/element-x-android/pull/3579 +* Fix the logic of the room list banner state by @jmartinesp in https://github.com/element-hq/element-x-android/pull/3615 +### 🗣 Translations +* Sync Strings by @ElementBot in https://github.com/element-hq/element-x-android/pull/3560 +* Sync Strings - import translations to Persian by @ElementBot in https://github.com/element-hq/element-x-android/pull/3612 +### 🧱 Build +* Introduce ModulesConfig by @bmarty in https://github.com/element-hq/element-x-android/pull/3530 +* Centralise the DI code generation logic by @jmartinesp in https://github.com/element-hq/element-x-android/pull/3562 +* Update Gradle impl module template with `setupAnvil()` call by @jmartinesp in https://github.com/element-hq/element-x-android/pull/3563 +* Use Anvil KSP instead of the Square KAPT one by @jmartinesp in https://github.com/element-hq/element-x-android/pull/3564 +* Upgrade the used JDK in the project to v21 by @jmartinesp in https://github.com/element-hq/element-x-android/pull/3582 +* Merge unit, screenshot tests and coverage in a single CI call by @jmartinesp in https://github.com/element-hq/element-x-android/pull/3593 +* Disable configuration cache in the CI by default by @jmartinesp in https://github.com/element-hq/element-x-android/pull/3601 +* Fix screenshot recording in CI by @jmartinesp in https://github.com/element-hq/element-x-android/pull/3607 +* Ensure the CI compile and execute all the unit tests. by @bmarty in https://github.com/element-hq/element-x-android/pull/3617 +### Dependency upgrades +* Update dependency androidx.compose:compose-bom to v2024.09.00 by @renovate in https://github.com/element-hq/element-x-android/pull/3399 +* Update dependency androidx.compose:compose-bom to v2024.09.02 by @renovate in https://github.com/element-hq/element-x-android/pull/3544 +* Update dependency io.element.android:compound-android to v0.1.0 by @renovate in https://github.com/element-hq/element-x-android/pull/3524 +* Update dependency com.google.firebase:firebase-bom to v33.3.0 by @renovate in https://github.com/element-hq/element-x-android/pull/3549 +* Update dependency org.maplibre.gl:android-sdk to v11.5.0 by @renovate in https://github.com/element-hq/element-x-android/pull/3550 +* Update dependency org.maplibre.gl:android-plugin-annotation-v9 to v3.0.1 by @renovate in https://github.com/element-hq/element-x-android/pull/3505 +* Update dependency androidx.webkit:webkit to v1.12.0 by @renovate in https://github.com/element-hq/element-x-android/pull/3520 +* Update dependency com.posthog:posthog-android to v3.7.5 by @renovate in https://github.com/element-hq/element-x-android/pull/3546 +* Update gradle-update/update-gradle-wrapper-action action to v2 by @renovate in https://github.com/element-hq/element-x-android/pull/3551 +* Update dependency com.lemonappdev:konsist to v0.16.1 by @renovate in https://github.com/element-hq/element-x-android/pull/3371 +* Update android.gradle.plugin to v8.6.1 by @renovate in https://github.com/element-hq/element-x-android/pull/3504 +* Update dependency org.matrix.rustcomponents:sdk-android to v0.2.49 by @renovate in https://github.com/element-hq/element-x-android/pull/3553 +* Update lifecycle to v2.8.6 by @renovate in https://github.com/element-hq/element-x-android/pull/3398 +* Update dependency com.google.accompanist:accompanist-permissions to v0.36.0 by @renovate in https://github.com/element-hq/element-x-android/pull/3400 +* Update dependency org.matrix.rustcomponents:sdk-android to v0.2.50 by @renovate in https://github.com/element-hq/element-x-android/pull/3565 +* Update dependency com.google.firebase:firebase-bom to v33.4.0 by @renovate in https://github.com/element-hq/element-x-android/pull/3578 +* Update android.gradle.plugin to v8.7.0 by @renovate in https://github.com/element-hq/element-x-android/pull/3577 +* Update dependency com.posthog:posthog-android to v3.8.0 by @renovate in https://github.com/element-hq/element-x-android/pull/3591 +* dependency: Bump rust sdk to 0.2.51 by @BillCarsonFr in https://github.com/element-hq/element-x-android/pull/3602 +* chore(deps): update dependencyanalysis to v2.1.3 by @renovate in https://github.com/element-hq/element-x-android/pull/3559 +* Update wysiwyg to v2.37.13 by @renovate in https://github.com/element-hq/element-x-android/pull/3596 +* fix(deps): update dependency io.nlopez.compose.rules:detekt to v0.4.15 by @renovate in https://github.com/element-hq/element-x-android/pull/3595 +* fix(deps): update dependency com.google.testparameterinjector:test-parameter-injector to v1.18 by @renovate in https://github.com/element-hq/element-x-android/pull/3606 +* fix(deps): update dependency com.squareup:kotlinpoet-ksp to v1.18.1 by @renovate in https://github.com/element-hq/element-x-android/pull/3580 +* Update dependency org.matrix.rustcomponents:sdk-android to v0.2.52 by @renovate in https://github.com/element-hq/element-x-android/pull/3619 +* SDK 0.2.53 19b9a73ecc3e31d502dbf0c5850bfdfaddf02afe by @bmarty in https://github.com/element-hq/element-x-android/pull/3622 +* Update dependency org.maplibre.gl:android-sdk to v11.5.1 by @renovate in https://github.com/element-hq/element-x-android/pull/3608 +### Others +* rename invisible flag to onlySignedDeviceIsolation flag by @BillCarsonFr in https://github.com/element-hq/element-x-android/pull/3542 +* Fix image viewer glitch by @ganfra in https://github.com/element-hq/element-x-android/pull/3537 +* Prefix message sent by the current user by `You` instead of the sender name. by @bmarty in https://github.com/element-hq/element-x-android/pull/3547 +* timeline : remove animateItem by @ganfra in https://github.com/element-hq/element-x-android/pull/3548 +* Fix a couple of build-time warnings in Gradle output by @frebib in https://github.com/element-hq/element-x-android/pull/3349 +* Use MSC2530 filename when loading media by @frebib in https://github.com/element-hq/element-x-android/pull/3567 +* Prevent crash with duplicate room suggestion by @frebib in https://github.com/element-hq/element-x-android/pull/3576 +* Add unit tests on TimelineItemsSubscriber by @bmarty in https://github.com/element-hq/element-x-android/pull/3554 +* Fix tests on develop by @bmarty in https://github.com/element-hq/element-x-android/pull/3585 +* Timeline better jump to behaviours by @ganfra in https://github.com/element-hq/element-x-android/pull/3597 +* Fix building the app using a local SDK. by @bmarty in https://github.com/element-hq/element-x-android/pull/3604 +* crypto: Use OnlySigned isolation flag to setup decryption trust req. by @BillCarsonFr in https://github.com/element-hq/element-x-android/pull/3569 +* Fix black-on-black status bars with hidden media by @frebib in https://github.com/element-hq/element-x-android/pull/3611 +* Remove supportSlidingSync boolean. by @bmarty in https://github.com/element-hq/element-x-android/pull/3609 +* Ensure that `Presenter`s do not depend on other presenters. by @bmarty in https://github.com/element-hq/element-x-android/pull/3618 +* Do not render pin violation in clear rooms. by @bmarty in https://github.com/element-hq/element-x-android/pull/3630 + Changes in Element X v0.6.4 (2024-09-25) ======================================== diff --git a/appconfig/src/main/kotlin/io/element/android/appconfig/LearnMoreConfig.kt b/appconfig/src/main/kotlin/io/element/android/appconfig/LearnMoreConfig.kt index 662c332582..d1db7e5da4 100644 --- a/appconfig/src/main/kotlin/io/element/android/appconfig/LearnMoreConfig.kt +++ b/appconfig/src/main/kotlin/io/element/android/appconfig/LearnMoreConfig.kt @@ -8,6 +8,7 @@ package io.element.android.appconfig object LearnMoreConfig { + const val ENCRYPTION_URL: String = "https://element.io/help#encryption" const val SECURE_BACKUP_URL: String = "https://element.io/help#encryption5" const val IDENTITY_CHANGE_URL: String = "https://element.io/help#encryption18" } diff --git a/appnav/src/main/kotlin/io/element/android/appnav/room/RoomFlowNode.kt b/appnav/src/main/kotlin/io/element/android/appnav/room/RoomFlowNode.kt index 3e2a805b5c..0562c5e2d6 100644 --- a/appnav/src/main/kotlin/io/element/android/appnav/room/RoomFlowNode.kt +++ b/appnav/src/main/kotlin/io/element/android/appnav/room/RoomFlowNode.kt @@ -45,6 +45,8 @@ import io.element.android.libraries.matrix.api.MatrixClient import io.element.android.libraries.matrix.api.core.RoomAlias import io.element.android.libraries.matrix.api.core.RoomId import io.element.android.libraries.matrix.api.core.RoomIdOrAlias +import io.element.android.libraries.matrix.api.core.toRoomIdOrAlias +import io.element.android.libraries.matrix.api.getRoomInfoFlow import io.element.android.libraries.matrix.api.room.CurrentUserMembership import io.element.android.libraries.matrix.api.room.alias.ResolvedRoomAlias import kotlinx.coroutines.flow.combine @@ -120,12 +122,9 @@ class RoomFlowNode @AssistedInject constructor( } private fun subscribeToRoomInfoFlow(roomId: RoomId, serverNames: List) { - val roomInfoFlow = client.getRoomInfoFlow( - roomId = roomId - ).map { it.getOrNull() } - - val isSpaceFlow = roomInfoFlow.map { it?.isSpace.orFalse() }.distinctUntilChanged() - val currentMembershipFlow = roomInfoFlow.map { it?.currentUserMembership }.distinctUntilChanged() + val roomInfoFlow = client.getRoomInfoFlow(roomIdOrAlias = roomId.toRoomIdOrAlias()) + val isSpaceFlow = roomInfoFlow.map { it.getOrNull()?.isSpace.orFalse() }.distinctUntilChanged() + val currentMembershipFlow = roomInfoFlow.map { it.getOrNull()?.currentUserMembership }.distinctUntilChanged() combine(currentMembershipFlow, isSpaceFlow) { membership, isSpace -> Timber.d("Room membership: $membership") when (membership) { diff --git a/appnav/src/test/kotlin/io/element/android/appnav/loggedin/LoggedInPresenterTest.kt b/appnav/src/test/kotlin/io/element/android/appnav/loggedin/LoggedInPresenterTest.kt index 519cceddfe..961856148e 100644 --- a/appnav/src/test/kotlin/io/element/android/appnav/loggedin/LoggedInPresenterTest.kt +++ b/appnav/src/test/kotlin/io/element/android/appnav/loggedin/LoggedInPresenterTest.kt @@ -478,7 +478,7 @@ class LoggedInPresenterTest { distributors = listOf(Distributor("aDistributorValue1", "aDistributorName1")), currentDistributor = { null }, ), - registerWithLambda: suspend (MatrixClient, PushProvider, Distributor) -> Result = { _, _, _ -> + registerWithLambda: (MatrixClient, PushProvider, Distributor) -> Result = { _, _, _ -> Result.success(Unit) }, selectPushProviderLambda: (MatrixClient, PushProvider) -> Unit = { _, _ -> lambdaError() }, diff --git a/build.gradle.kts b/build.gradle.kts index 01a1c7164c..d008c6b1d4 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -18,6 +18,7 @@ plugins { alias(libs.plugins.android.application) apply false alias(libs.plugins.android.library) apply false alias(libs.plugins.kotlin.android) apply false + alias(libs.plugins.compose.compiler) apply false alias(libs.plugins.ksp) apply false alias(libs.plugins.anvil) apply false alias(libs.plugins.kotlin.jvm) apply false @@ -82,20 +83,15 @@ allprojects { } tasks.withType { - // Warnings are potential errors, so stop ignoring them - // This is disabled by default, but the CI will enforce this. - // You can override by passing `-PallWarningsAsErrors=true` in the command line - // Or add a line with "allWarningsAsErrors=true" in your ~/.gradle/gradle.properties file - kotlinOptions.allWarningsAsErrors = project.properties["allWarningsAsErrors"] == "true" + compilerOptions { + // Warnings are potential errors, so stop ignoring them + // This is disabled by default, but the CI will enforce this. + // You can override by passing `-PallWarningsAsErrors=true` in the command line + // Or add a line with "allWarningsAsErrors=true" in your ~/.gradle/gradle.properties file + allWarningsAsErrors = project.properties["allWarningsAsErrors"] == "true" - kotlinOptions { - /* // Uncomment to suppress Compose Kotlin compiler compatibility warning - freeCompilerArgs += listOf( - "-P", - "plugin:androidx.compose.compiler.plugins.kotlin:suppressKotlinVersionCompatibilityCheck=true" - ) - */ +// freeCompilerArgs.addAll(listOf("-P", "plugin:androidx.compose.compiler.plugins.kotlin:suppressKotlinVersionCompatibilityCheck=true")) } } } @@ -192,19 +188,23 @@ subprojects { subprojects { tasks.withType().configureEach { - kotlinOptions { + compilerOptions { if (project.findProperty("composeCompilerReports") == "true") { - freeCompilerArgs += listOf( - "-P", - "plugin:androidx.compose.compiler.plugins.kotlin:reportsDestination=" + - "${project.layout.buildDirectory.asFile.get().absolutePath}/compose_compiler" + freeCompilerArgs.addAll( + listOf( + "-P", + "plugin:androidx.compose.compiler.plugins.kotlin:reportsDestination=" + + "${project.layout.buildDirectory.asFile.get().absolutePath}/compose_compiler" + ) ) } if (project.findProperty("composeCompilerMetrics") == "true") { - freeCompilerArgs += listOf( - "-P", - "plugin:androidx.compose.compiler.plugins.kotlin:metricsDestination=" + - "${project.layout.buildDirectory.asFile.get().absolutePath}/compose_compiler" + freeCompilerArgs.addAll( + listOf( + "-P", + "plugin:androidx.compose.compiler.plugins.kotlin:metricsDestination=" + + "${project.layout.buildDirectory.asFile.get().absolutePath}/compose_compiler" + ) ) } } diff --git a/fastlane/metadata/android/en-US/changelogs/40007000.txt b/fastlane/metadata/android/en-US/changelogs/40007000.txt new file mode 100644 index 0000000000..0e38b17b08 --- /dev/null +++ b/fastlane/metadata/android/en-US/changelogs/40007000.txt @@ -0,0 +1,2 @@ +Main changes in this version: bug fixes and performance improvement. +Full changelog: https://github.com/element-hq/element-x-android/releases diff --git a/features/cachecleaner/api/build.gradle.kts b/features/cachecleaner/api/build.gradle.kts index ebe4fe0dd7..30dfd6d42c 100644 --- a/features/cachecleaner/api/build.gradle.kts +++ b/features/cachecleaner/api/build.gradle.kts @@ -1,3 +1,5 @@ +import extension.setupAnvil + /* * Copyright 2023, 2024 New Vector Ltd. * @@ -7,13 +9,14 @@ plugins { id("io.element.android-library") - alias(libs.plugins.anvil) } android { namespace = "io.element.android.features.cachecleaner.api" } +setupAnvil() + dependencies { implementation(projects.libraries.architecture) implementation(libs.androidx.startup) diff --git a/features/call/impl/src/main/kotlin/io/element/android/features/call/impl/ui/CallScreenView.kt b/features/call/impl/src/main/kotlin/io/element/android/features/call/impl/ui/CallScreenView.kt index 5fa4856476..ce9319d0cf 100644 --- a/features/call/impl/src/main/kotlin/io/element/android/features/call/impl/ui/CallScreenView.kt +++ b/features/call/impl/src/main/kotlin/io/element/android/features/call/impl/ui/CallScreenView.kt @@ -8,7 +8,9 @@ package io.element.android.features.call.impl.ui import android.annotation.SuppressLint +import android.util.Log import android.view.ViewGroup +import android.webkit.ConsoleMessage import android.webkit.PermissionRequest import android.webkit.WebChromeClient import android.webkit.WebView @@ -43,6 +45,7 @@ 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 timber.log.Timber typealias RequestPermissionCallback = (Array) -> Unit @@ -189,6 +192,25 @@ private fun WebView.setup( override fun onPermissionRequest(request: PermissionRequest) { onPermissionsRequested(request) } + + override fun onConsoleMessage(consoleMessage: ConsoleMessage): Boolean { + val priority = when (consoleMessage.messageLevel()) { + ConsoleMessage.MessageLevel.ERROR -> Log.ERROR + ConsoleMessage.MessageLevel.WARNING -> Log.WARN + else -> Log.DEBUG + } + Timber.tag("WebView").log( + priority = priority, + message = buildString { + append(consoleMessage.sourceId()) + append(":") + append(consoleMessage.lineNumber()) + append(" ") + append(consoleMessage.message()) + }, + ) + return true + } } } diff --git a/features/call/impl/src/test/kotlin/io/element/android/features/call/ui/CallScreenPresenterTest.kt b/features/call/impl/src/test/kotlin/io/element/android/features/call/ui/CallScreenPresenterTest.kt index 7390b5fde9..f0e5708db3 100644 --- a/features/call/impl/src/test/kotlin/io/element/android/features/call/ui/CallScreenPresenterTest.kt +++ b/features/call/impl/src/test/kotlin/io/element/android/features/call/ui/CallScreenPresenterTest.kt @@ -109,12 +109,7 @@ class CallScreenPresenterTest { assertThat(initialState.isInWidgetMode).isTrue() assertThat(widgetProvider.getWidgetCalled).isTrue() assertThat(widgetDriver.runCalledCount).isEqualTo(1) - // Called several times because of the recomposition - analyticsLambda.assertions().isCalledExactly(2) - .withSequence( - listOf(value(MobileScreen.ScreenName.RoomCall)), - listOf(value(MobileScreen.ScreenName.RoomCall)) - ) + analyticsLambda.assertions().isCalledOnce().with(value(MobileScreen.ScreenName.RoomCall)) sendCallNotificationIfNeededLambda.assertions().isCalledOnce() } } diff --git a/features/enterprise/impl/build.gradle.kts b/features/enterprise/impl/build.gradle.kts index fa03bd48e7..5e4ce5c387 100644 --- a/features/enterprise/impl/build.gradle.kts +++ b/features/enterprise/impl/build.gradle.kts @@ -1,3 +1,5 @@ +import extension.setupAnvil + /* * Copyright 2024 New Vector Ltd. * @@ -6,13 +8,14 @@ */ plugins { id("io.element.android-library") - alias(libs.plugins.anvil) } android { namespace = "io.element.android.features.enterprise.impl" } +setupAnvil() + dependencies { implementation(projects.anvilannotations) api(projects.features.enterprise.api) diff --git a/features/ftue/test/build.gradle.kts b/features/ftue/test/build.gradle.kts index 989c3382d6..223b5c855a 100644 --- a/features/ftue/test/build.gradle.kts +++ b/features/ftue/test/build.gradle.kts @@ -1,3 +1,5 @@ +import extension.setupAnvil + /* * Copyright 2024 New Vector Ltd. * @@ -7,7 +9,6 @@ plugins { id("io.element.android-compose-library") - alias(libs.plugins.anvil) id("kotlin-parcelize") } @@ -15,6 +16,8 @@ android { namespace = "io.element.android.features.ftue.test" } +setupAnvil() + dependencies { implementation(projects.features.ftue.api) implementation(projects.tests.testutils) diff --git a/features/invite/impl/src/test/kotlin/io/element/android/features/invite/impl/response/AcceptDeclineInvitePresenterTest.kt b/features/invite/impl/src/test/kotlin/io/element/android/features/invite/impl/response/AcceptDeclineInvitePresenterTest.kt index 45fb2efc86..f194404f8e 100644 --- a/features/invite/impl/src/test/kotlin/io/element/android/features/invite/impl/response/AcceptDeclineInvitePresenterTest.kt +++ b/features/invite/impl/src/test/kotlin/io/element/android/features/invite/impl/response/AcceptDeclineInvitePresenterTest.kt @@ -99,7 +99,7 @@ class AcceptDeclineInvitePresenterTest { InternalAcceptDeclineInviteEvents.ConfirmDeclineInvite ) } - skipItems(1) + skipItems(2) awaitItem().also { state -> assertThat(state.declineAction).isInstanceOf(AsyncAction.Failure::class.java) state.eventSink( @@ -147,7 +147,7 @@ class AcceptDeclineInvitePresenterTest { InternalAcceptDeclineInviteEvents.ConfirmDeclineInvite ) } - skipItems(1) + skipItems(2) awaitItem().also { state -> assertThat(state.declineAction).isInstanceOf(AsyncAction.Success::class.java) } diff --git a/features/joinroom/impl/src/main/kotlin/io/element/android/features/joinroom/impl/JoinRoomPresenter.kt b/features/joinroom/impl/src/main/kotlin/io/element/android/features/joinroom/impl/JoinRoomPresenter.kt index eceece9660..8e0fa9193e 100644 --- a/features/joinroom/impl/src/main/kotlin/io/element/android/features/joinroom/impl/JoinRoomPresenter.kt +++ b/features/joinroom/impl/src/main/kotlin/io/element/android/features/joinroom/impl/JoinRoomPresenter.kt @@ -33,6 +33,8 @@ import io.element.android.libraries.core.meta.BuildMeta import io.element.android.libraries.matrix.api.MatrixClient import io.element.android.libraries.matrix.api.core.RoomId import io.element.android.libraries.matrix.api.core.RoomIdOrAlias +import io.element.android.libraries.matrix.api.core.toRoomIdOrAlias +import io.element.android.libraries.matrix.api.getRoomInfoFlow 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.RoomType @@ -70,7 +72,7 @@ class JoinRoomPresenter @AssistedInject constructor( override fun present(): JoinRoomState { val coroutineScope = rememberCoroutineScope() var retryCount by remember { mutableIntStateOf(0) } - val roomInfo by matrixClient.getRoomInfoFlow(roomId).collectAsState(initial = Optional.empty()) + val roomInfo by matrixClient.getRoomInfoFlow(roomId.toRoomIdOrAlias()).collectAsState(initial = Optional.empty()) val joinAction: MutableState> = remember { mutableStateOf(AsyncAction.Uninitialized) } val knockAction: MutableState> = remember { mutableStateOf(AsyncAction.Uninitialized) } val contentState by produceState( @@ -204,7 +206,7 @@ internal fun MatrixRoomInfo.toContentState(): ContentState { name = name, topic = topic, alias = canonicalAlias, - numberOfMembers = activeMembersCount, + numberOfMembers = activeMembersCount.toLong(), isDm = isDm, roomType = if (isSpace) RoomType.Space else RoomType.Room, roomAvatarUrl = avatarUrl, diff --git a/features/joinroom/impl/src/main/kotlin/io/element/android/features/joinroom/impl/JoinRoomStateProvider.kt b/features/joinroom/impl/src/main/kotlin/io/element/android/features/joinroom/impl/JoinRoomStateProvider.kt index 730bedea98..a560b5fea8 100644 --- a/features/joinroom/impl/src/main/kotlin/io/element/android/features/joinroom/impl/JoinRoomStateProvider.kt +++ b/features/joinroom/impl/src/main/kotlin/io/element/android/features/joinroom/impl/JoinRoomStateProvider.kt @@ -19,7 +19,6 @@ import io.element.android.libraries.matrix.api.core.RoomIdOrAlias import io.element.android.libraries.matrix.api.core.UserId import io.element.android.libraries.matrix.api.core.toRoomIdOrAlias import io.element.android.libraries.matrix.api.room.RoomType -import io.element.android.libraries.matrix.api.room.isDm import io.element.android.libraries.matrix.ui.model.InviteSender open class JoinRoomStateProvider : PreviewParameterProvider { diff --git a/features/joinroom/impl/src/test/kotlin/io/element/android/features/joinroom/impl/JoinRoomPresenterTest.kt b/features/joinroom/impl/src/test/kotlin/io/element/android/features/joinroom/impl/JoinRoomPresenterTest.kt index 835640bdea..0a323122ac 100644 --- a/features/joinroom/impl/src/test/kotlin/io/element/android/features/joinroom/impl/JoinRoomPresenterTest.kt +++ b/features/joinroom/impl/src/test/kotlin/io/element/android/features/joinroom/impl/JoinRoomPresenterTest.kt @@ -32,8 +32,8 @@ import io.element.android.libraries.matrix.test.A_ROOM_NAME import io.element.android.libraries.matrix.test.A_SERVER_LIST import io.element.android.libraries.matrix.test.FakeMatrixClient import io.element.android.libraries.matrix.test.core.aBuildMeta -import io.element.android.libraries.matrix.test.room.aRoomInfo import io.element.android.libraries.matrix.test.room.aRoomMember +import io.element.android.libraries.matrix.test.room.aRoomSummary import io.element.android.libraries.matrix.test.room.join.FakeJoinRoom import io.element.android.libraries.matrix.ui.model.toInviteSender import io.element.android.tests.testutils.WarmUpRule @@ -67,10 +67,10 @@ class JoinRoomPresenterTest { @Test fun `present - when room is joined then content state is filled with his data`() = runTest { - val roomInfo = aRoomInfo() + val roomSummary = aRoomSummary() val matrixClient = FakeMatrixClient().apply { - getRoomInfoFlowLambda = { _ -> - flowOf(Optional.of(roomInfo)) + getRoomSummaryFlowLambda = { _ -> + flowOf(Optional.of(roomSummary)) } } val presenter = createJoinRoomPresenter( @@ -81,22 +81,22 @@ class JoinRoomPresenterTest { awaitItem().also { state -> val contentState = state.contentState as ContentState.Loaded assertThat(contentState.roomId).isEqualTo(A_ROOM_ID) - assertThat(contentState.name).isEqualTo(roomInfo.name) - assertThat(contentState.topic).isEqualTo(roomInfo.topic) - assertThat(contentState.alias).isEqualTo(roomInfo.canonicalAlias) - assertThat(contentState.numberOfMembers).isEqualTo(roomInfo.activeMembersCount) - assertThat(contentState.isDm).isEqualTo(roomInfo.isDirect) - assertThat(contentState.roomAvatarUrl).isEqualTo(roomInfo.avatarUrl) + assertThat(contentState.name).isEqualTo(roomSummary.info.name) + assertThat(contentState.topic).isEqualTo(roomSummary.info.topic) + assertThat(contentState.alias).isEqualTo(roomSummary.info.canonicalAlias) + assertThat(contentState.numberOfMembers).isEqualTo(roomSummary.info.activeMembersCount) + assertThat(contentState.isDm).isEqualTo(roomSummary.info.isDirect) + assertThat(contentState.roomAvatarUrl).isEqualTo(roomSummary.info.avatarUrl) } } } @Test fun `present - when room is invited then join authorization is equal to invited`() = runTest { - val roomInfo = aRoomInfo(currentUserMembership = CurrentUserMembership.INVITED) + val roomSummary = aRoomSummary(currentUserMembership = CurrentUserMembership.INVITED) val matrixClient = FakeMatrixClient().apply { - getRoomInfoFlowLambda = { _ -> - flowOf(Optional.of(roomInfo)) + getRoomSummaryFlowLambda = { _ -> + flowOf(Optional.of(roomSummary)) } } val presenter = createJoinRoomPresenter( @@ -114,13 +114,13 @@ class JoinRoomPresenterTest { fun `present - when room is invited then join authorization is equal to invited, an inviter is provided`() = runTest { val inviter = aRoomMember(userId = UserId("@bob:example.com"), displayName = "Bob") val expectedInviteSender = inviter.toInviteSender() - val roomInfo = aRoomInfo( + val roomSummary = aRoomSummary( currentUserMembership = CurrentUserMembership.INVITED, inviter = inviter, ) val matrixClient = FakeMatrixClient().apply { - getRoomInfoFlowLambda = { _ -> - flowOf(Optional.of(roomInfo)) + getRoomSummaryFlowLambda = { _ -> + flowOf(Optional.of(roomSummary)) } } val presenter = createJoinRoomPresenter( @@ -140,10 +140,10 @@ class JoinRoomPresenterTest { val acceptDeclinePresenter = Presenter { anAcceptDeclineInviteState(eventSink = eventSinkRecorder) } - val roomInfo = aRoomInfo(currentUserMembership = CurrentUserMembership.INVITED) + val roomSummary = aRoomSummary(currentUserMembership = CurrentUserMembership.INVITED) val matrixClient = FakeMatrixClient().apply { - getRoomInfoFlowLambda = { _ -> - flowOf(Optional.of(roomInfo)) + getRoomSummaryFlowLambda = { _ -> + flowOf(Optional.of(roomSummary)) } } val presenter = createJoinRoomPresenter( @@ -224,10 +224,10 @@ class JoinRoomPresenterTest { @Test fun `present - when room is left and public then join authorization is equal to canJoin`() = runTest { - val roomInfo = aRoomInfo(currentUserMembership = CurrentUserMembership.LEFT, isPublic = true) + val roomSummary = aRoomSummary(currentUserMembership = CurrentUserMembership.LEFT, isPublic = true) val matrixClient = FakeMatrixClient().apply { - getRoomInfoFlowLambda = { _ -> - flowOf(Optional.of(roomInfo)) + getRoomSummaryFlowLambda = { _ -> + flowOf(Optional.of(roomSummary)) } } val presenter = createJoinRoomPresenter( @@ -243,10 +243,10 @@ class JoinRoomPresenterTest { @Test fun `present - when room is left and not public then join authorization is equal to unknown`() = runTest { - val roomInfo = aRoomInfo(currentUserMembership = CurrentUserMembership.LEFT, isPublic = false) + val roomSummary = aRoomSummary(currentUserMembership = CurrentUserMembership.LEFT, isPublic = false) val matrixClient = FakeMatrixClient().apply { - getRoomInfoFlowLambda = { _ -> - flowOf(Optional.of(roomInfo)) + getRoomSummaryFlowLambda = { _ -> + flowOf(Optional.of(roomSummary)) } } val presenter = createJoinRoomPresenter( @@ -338,11 +338,15 @@ class JoinRoomPresenterTest { awaitItem().also { state -> state.eventSink(JoinRoomEvents.KnockRoom) } + + assertThat(awaitItem().knockAction).isEqualTo(AsyncAction.Loading) awaitItem().also { state -> assertThat(state.knockAction).isEqualTo(AsyncAction.Success(Unit)) fakeKnockRoom.lambda = knockRoomFailure state.eventSink(JoinRoomEvents.KnockRoom) } + + assertThat(awaitItem().knockAction).isEqualTo(AsyncAction.Loading) awaitItem().also { state -> assertThat(state.knockAction).isInstanceOf(AsyncAction.Failure::class.java) } diff --git a/features/licenses/impl/build.gradle.kts b/features/licenses/impl/build.gradle.kts index 36bbd7ef34..9b86cb94a6 100644 --- a/features/licenses/impl/build.gradle.kts +++ b/features/licenses/impl/build.gradle.kts @@ -10,7 +10,6 @@ import extension.setupAnvil plugins { id("io.element.android-compose-library") id("kotlin-parcelize") - alias(libs.plugins.anvil) alias(libs.plugins.kotlin.serialization) } diff --git a/features/login/impl/src/main/kotlin/io/element/android/features/login/impl/screens/createaccount/WebViewMessageInterceptor.kt b/features/login/impl/src/main/kotlin/io/element/android/features/login/impl/screens/createaccount/WebViewMessageInterceptor.kt index 6dfe903b09..fedc288855 100644 --- a/features/login/impl/src/main/kotlin/io/element/android/features/login/impl/screens/createaccount/WebViewMessageInterceptor.kt +++ b/features/login/impl/src/main/kotlin/io/element/android/features/login/impl/screens/createaccount/WebViewMessageInterceptor.kt @@ -51,7 +51,7 @@ class WebViewMessageInterceptor( } override fun shouldOverrideUrlLoading(view: WebView?, request: WebResourceRequest?): Boolean { - request ?: return super.shouldOverrideUrlLoading(view, request) + request ?: return false // Load the URL in a Chrome Custom Tab, and return true to cancel the load onOpenExternalUrl(request.url.toString()) return true diff --git a/features/login/impl/src/main/kotlin/io/element/android/features/login/impl/screens/qrcode/intro/QrCodeIntroView.kt b/features/login/impl/src/main/kotlin/io/element/android/features/login/impl/screens/qrcode/intro/QrCodeIntroView.kt index a128884e40..0a2892d661 100644 --- a/features/login/impl/src/main/kotlin/io/element/android/features/login/impl/screens/qrcode/intro/QrCodeIntroView.kt +++ b/features/login/impl/src/main/kotlin/io/element/android/features/login/impl/screens/qrcode/intro/QrCodeIntroView.kt @@ -30,7 +30,6 @@ import io.element.android.libraries.designsystem.theme.components.Button import io.element.android.libraries.designsystem.theme.components.Icon import io.element.android.libraries.designsystem.utils.annotatedTextWithBold import io.element.android.libraries.permissions.api.PermissionsView -import io.element.android.libraries.ui.strings.CommonStrings import kotlinx.collections.immutable.persistentListOf @Composable @@ -51,6 +50,7 @@ fun QrCodeIntroView( onBackClick = onBackClick, iconStyle = BigIcon.Style.Default(CompoundIcons.Computer()), title = stringResource(id = R.string.screen_qr_code_login_initial_state_title, state.desktopAppName), + subTitle = stringResource(id = R.string.screen_qr_code_login_initial_state_subtitle), content = { Content(state = state) }, buttons = { Buttons(state = state) } ) @@ -87,7 +87,7 @@ private fun ColumnScope.Buttons( state: QrCodeIntroState, ) { Button( - text = stringResource(id = CommonStrings.action_continue), + text = stringResource(id = R.string.screen_qr_code_login_initial_state_button_title), modifier = Modifier.fillMaxWidth(), onClick = { state.eventSink.invoke(QrCodeIntroEvents.Continue) diff --git a/features/login/impl/src/main/res/values/localazy.xml b/features/login/impl/src/main/res/values/localazy.xml index a46b083d63..be01bd56d5 100644 --- a/features/login/impl/src/main/res/values/localazy.xml +++ b/features/login/impl/src/main/res/values/localazy.xml @@ -60,6 +60,7 @@ Try signing in manually, or scan the QR code with another device." "Select %1$s" "“Link new device”" "Scan the QR code with this device" + "Only available if your account provider supports it." "Open %1$s on another device to get the QR code" "Use the QR code shown on the other device." "Try again" diff --git a/features/login/impl/src/test/kotlin/io/element/android/features/login/impl/screens/qrcode/intro/QrCodeIntroViewTest.kt b/features/login/impl/src/test/kotlin/io/element/android/features/login/impl/screens/qrcode/intro/QrCodeIntroViewTest.kt index 11762d502b..2655624c0e 100644 --- a/features/login/impl/src/test/kotlin/io/element/android/features/login/impl/screens/qrcode/intro/QrCodeIntroViewTest.kt +++ b/features/login/impl/src/test/kotlin/io/element/android/features/login/impl/screens/qrcode/intro/QrCodeIntroViewTest.kt @@ -11,7 +11,7 @@ import androidx.activity.ComponentActivity import androidx.compose.ui.test.junit4.AndroidComposeTestRule import androidx.compose.ui.test.junit4.createAndroidComposeRule import androidx.test.ext.junit.runners.AndroidJUnit4 -import io.element.android.libraries.ui.strings.CommonStrings +import io.element.android.features.login.impl.R import io.element.android.tests.testutils.EnsureNeverCalled import io.element.android.tests.testutils.EventsRecorder import io.element.android.tests.testutils.clickOn @@ -61,12 +61,12 @@ class QrCodeIntroViewTest { } @Test - fun `on continue button clicked - emits the Continue event`() { + fun `on submit button clicked - emits the Continue event`() { val eventRecorder = EventsRecorder() rule.setQrCodeIntroView( state = aQrCodeIntroState(eventSink = eventRecorder), ) - rule.clickOn(CommonStrings.action_continue) + rule.clickOn(R.string.screen_qr_code_login_initial_state_button_title) eventRecorder.assertSingle(QrCodeIntroEvents.Continue) } diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/crypto/identity/IdentityChangeStatePresenter.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/crypto/identity/IdentityChangeStatePresenter.kt index cded6e38de..a4a13986e8 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/crypto/identity/IdentityChangeStatePresenter.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/crypto/identity/IdentityChangeStatePresenter.kt @@ -15,6 +15,8 @@ import androidx.compose.runtime.rememberCoroutineScope import io.element.android.libraries.architecture.Presenter import io.element.android.libraries.designsystem.components.avatar.AvatarData import io.element.android.libraries.designsystem.components.avatar.AvatarSize +import io.element.android.libraries.featureflag.api.FeatureFlagService +import io.element.android.libraries.featureflag.api.FeatureFlags import io.element.android.libraries.matrix.api.core.UserId import io.element.android.libraries.matrix.api.encryption.EncryptionService import io.element.android.libraries.matrix.api.room.MatrixRoom @@ -31,7 +33,6 @@ import kotlinx.coroutines.flow.distinctUntilChanged import kotlinx.coroutines.flow.filter import kotlinx.coroutines.flow.flatMapLatest import kotlinx.coroutines.flow.launchIn -import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.onEach import kotlinx.coroutines.launch import timber.log.Timber @@ -40,6 +41,7 @@ import javax.inject.Inject class IdentityChangeStatePresenter @Inject constructor( private val room: MatrixRoom, private val encryptionService: EncryptionService, + private val featureFlagService: FeatureFlagService, ) : Presenter { @Composable override fun present(): IdentityChangeState { @@ -62,14 +64,18 @@ class IdentityChangeStatePresenter @Inject constructor( @OptIn(ExperimentalCoroutinesApi::class) private fun ProduceStateScope>.observeRoomMemberIdentityStateChange() { - room.syncUpdateFlow + featureFlagService.isFeatureEnabledFlow(FeatureFlags.IdentityPinningViolationNotifications) + .filter { it } + .flatMapLatest { + room.syncUpdateFlow + } .filter { // Room cannot become unencrypted, so we can just apply a filter here. room.isEncrypted } .distinctUntilChanged() .flatMapLatest { - combine(room.identityStateChangesFlow, room.membersStateFlow,) { identityStateChanges, membersState -> + combine(room.identityStateChangesFlow, room.membersStateFlow) { identityStateChanges, membersState -> identityStateChanges.map { identityStateChange -> val member = membersState.roomMembers() ?.firstOrNull { roomMember -> roomMember.userId == identityStateChange.userId } 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 8529732b06..d0daa9bcb9 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 @@ -31,6 +31,7 @@ import im.vector.app.features.analytics.plan.Interaction import io.element.android.features.messages.impl.attachments.Attachment import io.element.android.features.messages.impl.attachments.preview.error.sendAttachmentError import io.element.android.features.messages.impl.draft.ComposerDraftService +import io.element.android.features.messages.impl.messagecomposer.suggestions.RoomAliasSuggestionsDataSource import io.element.android.features.messages.impl.messagecomposer.suggestions.SuggestionsProcessor import io.element.android.features.messages.impl.timeline.TimelineController import io.element.android.features.messages.impl.utils.TextPillificationHelper diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/messagecomposer/RoomAliasSuggestionsDataSource.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/messagecomposer/suggestions/RoomAliasSuggestionsDataSource.kt similarity index 75% rename from features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/messagecomposer/RoomAliasSuggestionsDataSource.kt rename to features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/messagecomposer/suggestions/RoomAliasSuggestionsDataSource.kt index 45a1da8e6a..c6eec0cbab 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/messagecomposer/RoomAliasSuggestionsDataSource.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/messagecomposer/suggestions/RoomAliasSuggestionsDataSource.kt @@ -5,20 +5,22 @@ * Please see LICENSE in the repository root for full details. */ -package io.element.android.features.messages.impl.messagecomposer +package io.element.android.features.messages.impl.messagecomposer.suggestions import com.squareup.anvil.annotations.ContributesBinding import io.element.android.libraries.di.SessionScope import io.element.android.libraries.matrix.api.core.RoomAlias +import io.element.android.libraries.matrix.api.core.RoomId import io.element.android.libraries.matrix.api.roomlist.RoomListService -import io.element.android.libraries.matrix.api.roomlist.RoomSummary import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.map import javax.inject.Inject data class RoomAliasSuggestion( val roomAlias: RoomAlias, - val roomSummary: RoomSummary, + val roomId: RoomId, + val roomName: String?, + val roomAvatarUrl: String?, ) interface RoomAliasSuggestionsDataSource { @@ -32,14 +34,16 @@ class DefaultRoomAliasSuggestionsDataSource @Inject constructor( override fun getAllRoomAliasSuggestions(): Flow> { return roomListService .allRooms - .filteredSummaries + .summaries .map { roomSummaries -> roomSummaries .mapNotNull { roomSummary -> - roomSummary.canonicalAlias?.let { roomAlias -> + roomSummary.info.canonicalAlias?.let { roomAlias -> RoomAliasSuggestion( roomAlias = roomAlias, - roomSummary = roomSummary, + roomId = roomSummary.roomId, + roomName = roomSummary.info.name, + roomAvatarUrl = roomSummary.info.avatarUrl, ) } } diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/messagecomposer/suggestions/SuggestionsPickerView.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/messagecomposer/suggestions/SuggestionsPickerView.kt index 7a9c542a1b..a7692fcd31 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/messagecomposer/suggestions/SuggestionsPickerView.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/messagecomposer/suggestions/SuggestionsPickerView.kt @@ -36,7 +36,6 @@ 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.RoomMembershipState -import io.element.android.libraries.matrix.ui.components.aRoomSummaryDetails import io.element.android.libraries.matrix.ui.model.getAvatarData import io.element.android.libraries.textcomposer.mentions.ResolvedSuggestion import kotlinx.collections.immutable.ImmutableList @@ -60,7 +59,7 @@ fun SuggestionsPickerView( when (suggestion) { is ResolvedSuggestion.AtRoom -> "@room" is ResolvedSuggestion.Member -> suggestion.roomMember.userId.value - is ResolvedSuggestion.Alias -> suggestion.roomSummary.roomId.value + is ResolvedSuggestion.Alias -> suggestion.roomId.value } } ) { @@ -96,12 +95,12 @@ private fun SuggestionItemView( val avatarData = when (suggestion) { is ResolvedSuggestion.AtRoom -> roomAvatar?.copy(size = avatarSize) ?: AvatarData(roomId, roomName, null, avatarSize) is ResolvedSuggestion.Member -> suggestion.roomMember.getAvatarData(avatarSize) - is ResolvedSuggestion.Alias -> suggestion.roomSummary.getAvatarData(avatarSize) + is ResolvedSuggestion.Alias -> suggestion.getAvatarData(avatarSize) } val title = when (suggestion) { is ResolvedSuggestion.AtRoom -> stringResource(R.string.screen_room_mentions_at_room_title) is ResolvedSuggestion.Member -> suggestion.roomMember.displayName - is ResolvedSuggestion.Alias -> suggestion.roomSummary.name + is ResolvedSuggestion.Alias -> suggestion.roomName } val subtitle = when (suggestion) { is ResolvedSuggestion.AtRoom -> "@room" @@ -152,11 +151,6 @@ internal fun SuggestionsPickerViewPreview() { role = RoomMember.Role.USER, ) val anAlias = remember { RoomAlias("#room:domain.org") } - val roomSummaryDetails = remember { - aRoomSummaryDetails( - name = "My room", - ) - } SuggestionsPickerView( roomId = RoomId("!room:matrix.org"), roomName = "Room", @@ -166,8 +160,10 @@ internal fun SuggestionsPickerViewPreview() { ResolvedSuggestion.Member(roomMember), ResolvedSuggestion.Member(roomMember.copy(userId = UserId("@bob:server.org"), displayName = "Bob")), ResolvedSuggestion.Alias( - anAlias, - roomSummaryDetails, + roomAlias = anAlias, + roomId = RoomId("!room:matrix.org"), + roomName = "My room", + roomAvatarUrl = null, ) ), onSelectSuggestion = {} diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/messagecomposer/suggestions/SuggestionsProcessor.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/messagecomposer/suggestions/SuggestionsProcessor.kt index b1a9f977d1..aab533903b 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/messagecomposer/suggestions/SuggestionsProcessor.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/messagecomposer/suggestions/SuggestionsProcessor.kt @@ -7,7 +7,6 @@ package io.element.android.features.messages.impl.messagecomposer.suggestions -import io.element.android.features.messages.impl.messagecomposer.RoomAliasSuggestion import io.element.android.libraries.core.data.filterUpTo import io.element.android.libraries.matrix.api.core.UserId import io.element.android.libraries.matrix.api.room.MatrixRoomMembersState @@ -55,7 +54,14 @@ class SuggestionsProcessor @Inject constructor() { SuggestionType.Room -> { roomAliasSuggestions .filter { it.roomAlias.value.contains(suggestion.text, ignoreCase = true) } - .map { ResolvedSuggestion.Alias(it.roomAlias, it.roomSummary) } + .map { + ResolvedSuggestion.Alias( + roomAlias = it.roomAlias, + roomId = it.roomId, + roomName = it.roomName, + roomAvatarUrl = it.roomAvatarUrl, + ) + } } SuggestionType.Command, is SuggestionType.Custom -> { diff --git a/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/crypto/identity/IdentityChangeStatePresenterTest.kt b/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/crypto/identity/IdentityChangeStatePresenterTest.kt index afc21efd97..4ff0c8f340 100644 --- a/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/crypto/identity/IdentityChangeStatePresenterTest.kt +++ b/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/crypto/identity/IdentityChangeStatePresenterTest.kt @@ -9,6 +9,9 @@ package io.element.android.features.messages.impl.crypto.identity import com.google.common.truth.Truth.assertThat import io.element.android.libraries.designsystem.components.avatar.AvatarSize +import io.element.android.libraries.featureflag.api.FeatureFlagService +import io.element.android.libraries.featureflag.api.FeatureFlags +import io.element.android.libraries.featureflag.test.FakeFeatureFlagService import io.element.android.libraries.matrix.api.core.UserId import io.element.android.libraries.matrix.api.encryption.EncryptionService import io.element.android.libraries.matrix.api.encryption.identity.IdentityState @@ -65,6 +68,43 @@ class IdentityChangeStatePresenterTest { } } + @Test + fun `present - when the room emits identity change, but the feature is disabled, the presenter emits new state`() = runTest { + val room = FakeMatrixRoom( + isEncrypted = true, + ) + val featureFlagService = FakeFeatureFlagService( + initialState = mapOf( + FeatureFlags.IdentityPinningViolationNotifications.key to false, + ) + ) + val presenter = createIdentityChangeStatePresenter( + room = room, + featureFlagService = featureFlagService, + ) + presenter.test { + val initialState = awaitItem() + assertThat(initialState.roomMemberIdentityStateChanges).isEmpty() + room.emitIdentityStateChanges( + listOf( + IdentityStateChange( + userId = A_USER_ID_2, + identityState = IdentityState.PinViolation, + ), + ) + ) + // No item emitted. + expectNoEvents() + // Enable the feature + featureFlagService.setFeatureEnabled(FeatureFlags.IdentityPinningViolationNotifications, true) + val finalItem = awaitItem() + assertThat(finalItem.roomMemberIdentityStateChanges).hasSize(1) + val value = finalItem.roomMemberIdentityStateChanges.first() + assertThat(value.identityRoomMember.userId).isEqualTo(A_USER_ID_2) + assertThat(value.identityState).isEqualTo(IdentityState.PinViolation) + } + } + @Test fun `present - when the clear room emits identity change, the presenter does not emits new state`() = runTest { val room = FakeMatrixRoom(isEncrypted = false) @@ -147,10 +187,16 @@ class IdentityChangeStatePresenterTest { private fun createIdentityChangeStatePresenter( room: MatrixRoom = FakeMatrixRoom(), encryptionService: EncryptionService = FakeEncryptionService(), + featureFlagService: FeatureFlagService = FakeFeatureFlagService( + initialState = mapOf( + FeatureFlags.IdentityPinningViolationNotifications.key to true, + ) + ), ): IdentityChangeStatePresenter { return IdentityChangeStatePresenter( room = room, encryptionService = encryptionService, + featureFlagService = featureFlagService, ) } } diff --git a/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/messagecomposer/DefaultRoomAliasSuggestionsDataSourceTest.kt b/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/messagecomposer/DefaultRoomAliasSuggestionsDataSourceTest.kt index f05cc82aa6..9a443fb174 100644 --- a/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/messagecomposer/DefaultRoomAliasSuggestionsDataSourceTest.kt +++ b/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/messagecomposer/DefaultRoomAliasSuggestionsDataSourceTest.kt @@ -9,6 +9,8 @@ package io.element.android.features.messages.impl.messagecomposer import app.cash.turbine.test import com.google.common.truth.Truth.assertThat +import io.element.android.features.messages.impl.messagecomposer.suggestions.DefaultRoomAliasSuggestionsDataSource +import io.element.android.features.messages.impl.messagecomposer.suggestions.RoomAliasSuggestion import io.element.android.libraries.matrix.test.A_ROOM_ALIAS import io.element.android.libraries.matrix.test.A_ROOM_ID_2 import io.element.android.libraries.matrix.test.room.aRoomSummary @@ -38,7 +40,9 @@ class DefaultRoomAliasSuggestionsDataSourceTest { listOf( RoomAliasSuggestion( roomAlias = A_ROOM_ALIAS, - roomSummary = aRoomSummaryWithAnAlias + roomId = aRoomSummaryWithAnAlias.roomId, + roomName = aRoomSummaryWithAnAlias.info.name, + roomAvatarUrl = aRoomSummaryWithAnAlias.info.avatarUrl ) ) ) diff --git a/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/messagecomposer/FakeRoomAliasSuggestionsDataSource.kt b/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/messagecomposer/FakeRoomAliasSuggestionsDataSource.kt index c916d2bc9c..3a9a72799a 100644 --- a/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/messagecomposer/FakeRoomAliasSuggestionsDataSource.kt +++ b/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/messagecomposer/FakeRoomAliasSuggestionsDataSource.kt @@ -7,6 +7,8 @@ package io.element.android.features.messages.impl.messagecomposer +import io.element.android.features.messages.impl.messagecomposer.suggestions.RoomAliasSuggestion +import io.element.android.features.messages.impl.messagecomposer.suggestions.RoomAliasSuggestionsDataSource import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.MutableStateFlow diff --git a/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/messagecomposer/suggestions/SuggestionsProcessorTest.kt b/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/messagecomposer/suggestions/SuggestionsProcessorTest.kt index 1cb7596e89..48000e79b4 100644 --- a/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/messagecomposer/suggestions/SuggestionsProcessorTest.kt +++ b/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/messagecomposer/suggestions/SuggestionsProcessorTest.kt @@ -8,7 +8,6 @@ package io.element.android.features.messages.impl.messagecomposer.suggestions import com.google.common.truth.Truth.assertThat -import io.element.android.features.messages.impl.messagecomposer.RoomAliasSuggestion 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.RoomMembershipState @@ -110,13 +109,25 @@ class SuggestionsProcessorTest { val result = suggestionsProcessor.process( suggestion = aRoomSuggestion("ALI"), roomMembersState = MatrixRoomMembersState.Ready(persistentListOf()), - roomAliasSuggestions = listOf(RoomAliasSuggestion(A_ROOM_ALIAS, aRoomSummary)), + roomAliasSuggestions = listOf( + RoomAliasSuggestion( + roomAlias = A_ROOM_ALIAS, + roomId = aRoomSummary.roomId, + roomName = aRoomSummary.info.name, + roomAvatarUrl = aRoomSummary.info.avatarUrl, + ) + ), currentUserId = A_USER_ID, canSendRoomMention = { true }, ) assertThat(result).isEqualTo( listOf( - ResolvedSuggestion.Alias(A_ROOM_ALIAS, aRoomSummary) + ResolvedSuggestion.Alias( + roomAlias = A_ROOM_ALIAS, + roomId = aRoomSummary.roomId, + roomName = aRoomSummary.info.name, + roomAvatarUrl = aRoomSummary.info.avatarUrl, + ) ) ) } @@ -127,13 +138,25 @@ class SuggestionsProcessorTest { val result = suggestionsProcessor.process( suggestion = aRoomSuggestion("ali"), roomMembersState = MatrixRoomMembersState.Ready(persistentListOf()), - roomAliasSuggestions = listOf(RoomAliasSuggestion(A_ROOM_ALIAS, aRoomSummary)), + roomAliasSuggestions = listOf( + RoomAliasSuggestion( + roomAlias = A_ROOM_ALIAS, + roomId = aRoomSummary.roomId, + roomName = aRoomSummary.info.name, + roomAvatarUrl = aRoomSummary.info.avatarUrl, + ) + ), currentUserId = A_USER_ID, canSendRoomMention = { true }, ) assertThat(result).isEqualTo( listOf( - ResolvedSuggestion.Alias(A_ROOM_ALIAS, aRoomSummary) + ResolvedSuggestion.Alias( + roomAlias = A_ROOM_ALIAS, + roomId = aRoomSummary.roomId, + roomName = aRoomSummary.info.name, + roomAvatarUrl = aRoomSummary.info.avatarUrl, + ) ) ) } @@ -144,7 +167,14 @@ class SuggestionsProcessorTest { val result = suggestionsProcessor.process( suggestion = aRoomSuggestion("tot"), roomMembersState = MatrixRoomMembersState.Ready(persistentListOf()), - roomAliasSuggestions = listOf(RoomAliasSuggestion(A_ROOM_ALIAS, aRoomSummary)), + roomAliasSuggestions = listOf( + RoomAliasSuggestion( + roomAlias = A_ROOM_ALIAS, + roomId = aRoomSummary.roomId, + roomName = aRoomSummary.info.name, + roomAvatarUrl = aRoomSummary.info.avatarUrl, + ) + ), currentUserId = A_USER_ID, canSendRoomMention = { true }, ) diff --git a/features/migration/impl/build.gradle.kts b/features/migration/impl/build.gradle.kts index 30e1b0c331..c89af9115d 100644 --- a/features/migration/impl/build.gradle.kts +++ b/features/migration/impl/build.gradle.kts @@ -1,3 +1,5 @@ +import extension.setupAnvil + /* * Copyright 2024 New Vector Ltd. * @@ -7,13 +9,14 @@ plugins { id("io.element.android-compose-library") - alias(libs.plugins.anvil) } android { namespace = "io.element.android.features.migration.impl" } +setupAnvil() + dependencies { implementation(projects.features.migration.api) implementation(projects.libraries.architecture) diff --git a/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/notifications/edit/EditDefaultNotificationSettingPresenter.kt b/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/notifications/edit/EditDefaultNotificationSettingPresenter.kt index dffd1b14a4..50c31cb764 100644 --- a/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/notifications/edit/EditDefaultNotificationSettingPresenter.kt +++ b/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/notifications/edit/EditDefaultNotificationSettingPresenter.kt @@ -21,11 +21,12 @@ import dagger.assisted.AssistedInject import io.element.android.libraries.architecture.AsyncAction import io.element.android.libraries.architecture.Presenter import io.element.android.libraries.architecture.runUpdatingStateNoSuccess -import io.element.android.libraries.matrix.api.MatrixClient +import io.element.android.libraries.designsystem.components.avatar.AvatarSize import io.element.android.libraries.matrix.api.notificationsettings.NotificationSettingsService import io.element.android.libraries.matrix.api.room.RoomNotificationMode import io.element.android.libraries.matrix.api.roomlist.RoomListService import io.element.android.libraries.matrix.api.roomlist.RoomSummary +import io.element.android.libraries.matrix.ui.model.getAvatarData import kotlinx.collections.immutable.toImmutableList import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.FlowPreview @@ -40,7 +41,6 @@ class EditDefaultNotificationSettingPresenter @AssistedInject constructor( private val notificationSettingsService: NotificationSettingsService, @Assisted private val isOneToOne: Boolean, private val roomListService: RoomListService, - private val matrixClient: MatrixClient, ) : Presenter { @AssistedFactory interface Factory { @@ -57,8 +57,8 @@ class EditDefaultNotificationSettingPresenter @AssistedInject constructor( val changeNotificationSettingAction: MutableState> = remember { mutableStateOf(AsyncAction.Uninitialized) } - val roomsWithUserDefinedMode: MutableState> = remember { - mutableStateOf(listOf()) + val roomsWithUserDefinedMode: MutableState> = remember { + mutableStateOf(emptyList()) } val localCoroutineScope = rememberCoroutineScope() @@ -106,31 +106,37 @@ class EditDefaultNotificationSettingPresenter @AssistedInject constructor( .launchIn(this) } - private fun CoroutineScope.observeRoomSummaries(roomsWithUserDefinedMode: MutableState>) { + private fun CoroutineScope.observeRoomSummaries(roomsWithUserDefinedMode: MutableState>) { roomListService.allRooms .summaries - .onEach { - updateRoomsWithUserDefinedMode(it, roomsWithUserDefinedMode) + .onEach { roomSummaries -> + updateRoomsWithUserDefinedMode(roomSummaries, roomsWithUserDefinedMode) } .launchIn(this) } - private fun CoroutineScope.updateRoomsWithUserDefinedMode( + private suspend fun updateRoomsWithUserDefinedMode( summaries: List, - roomsWithUserDefinedMode: MutableState> - ) = launch { - val roomWithUserDefinedRules: Set = notificationSettingsService.getRoomsWithUserDefinedRules().getOrThrow().toSet() - - val sortedSummaries = summaries - .filterIsInstance() - .filter { - val room = matrixClient.getRoom(it.roomId) ?: return@filter false - roomWithUserDefinedRules.contains(it.roomId.value) && isOneToOne == room.isOneToOne + roomsWithUserDefinedMode: MutableState> + ) { + val roomWithUserDefinedRules: Set = notificationSettingsService.getRoomsWithUserDefinedRules().getOrDefault(emptyList()).toSet() + roomsWithUserDefinedMode.value = summaries + .filter { roomSummary -> + roomWithUserDefinedRules.contains(roomSummary.roomId.value) && roomSummary.isOneToOne == isOneToOne + } + .map { roomSummary -> + EditNotificationSettingRoomInfo( + roomId = roomSummary.roomId, + name = roomSummary.info.name, + heroesAvatar = roomSummary.info.heroes.map { hero -> + hero.getAvatarData(AvatarSize.CustomRoomNotificationSetting) + }.toImmutableList(), + avatarData = roomSummary.info.getAvatarData(AvatarSize.CustomRoomNotificationSetting), + notificationMode = roomSummary.info.userDefinedNotificationMode, + ) } // locale sensitive sorting - .sortedWith(compareBy(Collator.getInstance()) { it.name }) - - roomsWithUserDefinedMode.value = sortedSummaries + .sortedWith(compareBy(Collator.getInstance()) { roomSummary -> roomSummary.name }) } private fun CoroutineScope.setDefaultNotificationMode(mode: RoomNotificationMode, action: MutableState>) = launch { diff --git a/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/notifications/edit/EditDefaultNotificationSettingState.kt b/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/notifications/edit/EditDefaultNotificationSettingState.kt index fc087f4ac7..8e61d5c62c 100644 --- a/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/notifications/edit/EditDefaultNotificationSettingState.kt +++ b/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/notifications/edit/EditDefaultNotificationSettingState.kt @@ -9,13 +9,12 @@ package io.element.android.features.preferences.impl.notifications.edit import io.element.android.libraries.architecture.AsyncAction import io.element.android.libraries.matrix.api.room.RoomNotificationMode -import io.element.android.libraries.matrix.api.roomlist.RoomSummary import kotlinx.collections.immutable.ImmutableList data class EditDefaultNotificationSettingState( val isOneToOne: Boolean, val mode: RoomNotificationMode?, - val roomsWithUserDefinedMode: ImmutableList, + val roomsWithUserDefinedMode: ImmutableList, val changeNotificationSettingAction: AsyncAction, val displayMentionsOnlyDisclaimer: Boolean, val eventSink: (EditDefaultNotificationSettingStateEvents) -> Unit, 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 d620ecc01a..b941d738ea 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 @@ -9,9 +9,10 @@ package io.element.android.features.preferences.impl.notifications.edit import androidx.compose.ui.tooling.preview.PreviewParameterProvider import io.element.android.libraries.architecture.AsyncAction +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 -import io.element.android.libraries.matrix.ui.components.aRoomSummaryDetails import kotlinx.collections.immutable.persistentListOf open class EditDefaultNotificationSettingStateProvider : PreviewParameterProvider { @@ -33,21 +34,25 @@ private fun anEditDefaultNotificationSettingsState( isOneToOne = isOneToOne, mode = RoomNotificationMode.MENTIONS_AND_KEYWORDS_ONLY, roomsWithUserDefinedMode = persistentListOf( - aRoomSummary("Room"), - aRoomSummary(null), + anEditNotificationSettingRoomInfo("Room"), + anEditNotificationSettingRoomInfo(null), ), changeNotificationSettingAction = changeNotificationSettingAction, displayMentionsOnlyDisclaimer = displayMentionsOnlyDisclaimer, eventSink = {} ) -private fun aRoomSummary( +private fun anEditNotificationSettingRoomInfo( name: String?, -) = aRoomSummaryDetails( +) = EditNotificationSettingRoomInfo( roomId = RoomId("!roomId:domain"), name = name, - avatarUrl = null, - isDirect = false, - lastMessage = null, + avatarData = AvatarData( + id = "!roomId:domain", + name = name, + url = null, + size = AvatarSize.CustomRoomNotificationSetting, + ), + heroesAvatar = persistentListOf(), notificationMode = 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 7ed28dd904..1e6932e1e5 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 @@ -16,7 +16,6 @@ import androidx.compose.ui.text.font.FontStyle import androidx.compose.ui.tooling.preview.PreviewParameter import io.element.android.features.preferences.impl.R import io.element.android.libraries.designsystem.components.async.AsyncActionView -import io.element.android.libraries.designsystem.components.avatar.AvatarSize import io.element.android.libraries.designsystem.components.avatar.CompositeAvatar import io.element.android.libraries.designsystem.components.list.ListItemContent import io.element.android.libraries.designsystem.components.preferences.PreferenceCategory @@ -27,9 +26,7 @@ import io.element.android.libraries.designsystem.theme.components.ListItem 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.RoomNotificationMode -import io.element.android.libraries.matrix.ui.model.getAvatarData import io.element.android.libraries.ui.strings.CommonStrings -import kotlinx.collections.immutable.toPersistentList /** * A view that allows a user to edit the default notification setting for rooms. This can be set separately @@ -80,7 +77,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.userDefinedNotificationMode) { + val subtitle = when (summary.notificationMode) { 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) @@ -101,10 +98,8 @@ fun EditDefaultNotificationSettingView( }, leadingContent = ListItemContent.Custom { CompositeAvatar( - avatarData = summary.getAvatarData(size = AvatarSize.CustomRoomNotificationSetting), - heroes = summary.heroes.map { user -> - user.getAvatarData(size = AvatarSize.CustomRoomNotificationSetting) - }.toPersistentList() + avatarData = summary.avatarData, + heroes = summary.heroesAvatar, ) }, onClick = { diff --git a/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/notifications/edit/EditNotificationSettingRoomInfo.kt b/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/notifications/edit/EditNotificationSettingRoomInfo.kt new file mode 100644 index 0000000000..5510cb8c55 --- /dev/null +++ b/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/notifications/edit/EditNotificationSettingRoomInfo.kt @@ -0,0 +1,21 @@ +/* + * Copyright 2024 New Vector Ltd. + * + * SPDX-License-Identifier: AGPL-3.0-only + * Please see LICENSE in the repository root for full details. + */ + +package io.element.android.features.preferences.impl.notifications.edit + +import io.element.android.libraries.designsystem.components.avatar.AvatarData +import io.element.android.libraries.matrix.api.core.RoomId +import io.element.android.libraries.matrix.api.room.RoomNotificationMode +import kotlinx.collections.immutable.ImmutableList + +data class EditNotificationSettingRoomInfo( + val roomId: RoomId, + val name: String?, + val heroesAvatar: ImmutableList, + val avatarData: AvatarData, + val notificationMode: RoomNotificationMode? +) diff --git a/features/preferences/impl/src/test/kotlin/io/element/android/features/preferences/impl/notifications/EditDefaultNotificationSettingsPresenterTest.kt b/features/preferences/impl/src/test/kotlin/io/element/android/features/preferences/impl/notifications/EditDefaultNotificationSettingsPresenterTest.kt index d854042717..5916097dc0 100644 --- a/features/preferences/impl/src/test/kotlin/io/element/android/features/preferences/impl/notifications/EditDefaultNotificationSettingsPresenterTest.kt +++ b/features/preferences/impl/src/test/kotlin/io/element/android/features/preferences/impl/notifications/EditDefaultNotificationSettingsPresenterTest.kt @@ -14,11 +14,8 @@ import com.google.common.truth.Truth.assertThat import io.element.android.features.preferences.impl.notifications.edit.EditDefaultNotificationSettingPresenter import io.element.android.features.preferences.impl.notifications.edit.EditDefaultNotificationSettingStateEvents import io.element.android.libraries.matrix.api.room.RoomNotificationMode -import io.element.android.libraries.matrix.test.A_ROOM_ID 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.aRoomSummary import io.element.android.libraries.matrix.test.roomlist.FakeRoomListService import io.element.android.tests.testutils.awaitLastSequentialItem @@ -49,24 +46,20 @@ class EditDefaultNotificationSettingsPresenterTest { @Test fun `present - ensure list of rooms with user defined mode`() = runTest { - val room = FakeMatrixRoom() val notificationSettingsService = FakeNotificationSettingsService( initialRoomMode = RoomNotificationMode.ALL_MESSAGES, initialRoomModeIsDefault = false ) - val matrixClient = FakeMatrixClient(notificationSettingsService = notificationSettingsService).apply { - givenGetRoomResult(A_ROOM_ID, room) - } val roomListService = FakeRoomListService() - val presenter = createEditDefaultNotificationSettingPresenter(notificationSettingsService, roomListService, matrixClient) + val presenter = createEditDefaultNotificationSettingPresenter(notificationSettingsService, roomListService) moleculeFlow(RecompositionMode.Immediate) { presenter.present() }.test { - roomListService.postAllRooms(listOf(aRoomSummary(notificationMode = RoomNotificationMode.ALL_MESSAGES))) + roomListService.postAllRooms(listOf(aRoomSummary(userDefinedNotificationMode = RoomNotificationMode.ALL_MESSAGES))) val loadedState = consumeItemsUntilPredicate { state -> - state.roomsWithUserDefinedMode.any { it.userDefinedNotificationMode == RoomNotificationMode.ALL_MESSAGES } + state.roomsWithUserDefinedMode.any { it.notificationMode == RoomNotificationMode.ALL_MESSAGES } }.last() - assertThat(loadedState.roomsWithUserDefinedMode.any { it.userDefinedNotificationMode == RoomNotificationMode.ALL_MESSAGES }).isTrue() + assertThat(loadedState.roomsWithUserDefinedMode.any { it.notificationMode == RoomNotificationMode.ALL_MESSAGES }).isTrue() } } @@ -121,13 +114,11 @@ class EditDefaultNotificationSettingsPresenterTest { private fun createEditDefaultNotificationSettingPresenter( notificationSettingsService: FakeNotificationSettingsService = FakeNotificationSettingsService(), roomListService: FakeRoomListService = FakeRoomListService(), - matrixClient: FakeMatrixClient = FakeMatrixClient(notificationSettingsService = notificationSettingsService) ): EditDefaultNotificationSettingPresenter { return EditDefaultNotificationSettingPresenter( notificationSettingsService = notificationSettingsService, isOneToOne = false, roomListService = roomListService, - matrixClient = matrixClient ) } } diff --git a/features/roomdirectory/impl/build.gradle.kts b/features/roomdirectory/impl/build.gradle.kts index 6d05cad8e3..3fec2f0bb7 100644 --- a/features/roomdirectory/impl/build.gradle.kts +++ b/features/roomdirectory/impl/build.gradle.kts @@ -9,7 +9,6 @@ import extension.setupAnvil plugins { id("io.element.android-compose-library") - alias(libs.plugins.anvil) id("kotlin-parcelize") } 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 1044f58130..004ce9174b 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 @@ -14,6 +14,7 @@ import io.element.android.libraries.dateformatter.api.LastMessageTimestampFormat import io.element.android.libraries.designsystem.components.avatar.AvatarSize import io.element.android.libraries.eventformatter.api.RoomLastMessageFormatter import io.element.android.libraries.matrix.api.room.CurrentUserMembership +import io.element.android.libraries.matrix.api.room.isDm import io.element.android.libraries.matrix.api.roomlist.RoomSummary import io.element.android.libraries.matrix.ui.model.getAvatarData import io.element.android.libraries.matrix.ui.model.toInviteSender @@ -24,34 +25,35 @@ class RoomListRoomSummaryFactory @Inject constructor( private val lastMessageTimestampFormatter: LastMessageTimestampFormatter, private val roomLastMessageFormatter: RoomLastMessageFormatter, ) { - fun create(details: RoomSummary): RoomListRoomSummary { - val avatarData = details.getAvatarData(size = AvatarSize.RoomListItem) + fun create(roomSummary: RoomSummary): RoomListRoomSummary { + val roomInfo = roomSummary.info + val avatarData = roomInfo.getAvatarData(size = AvatarSize.RoomListItem) return RoomListRoomSummary( - id = details.roomId.value, - roomId = details.roomId, - name = details.name, - numberOfUnreadMessages = details.numUnreadMessages, - numberOfUnreadMentions = details.numUnreadMentions, - numberOfUnreadNotifications = details.numUnreadNotifications, - isMarkedUnread = details.isMarkedUnread, - timestamp = lastMessageTimestampFormatter.format(details.lastMessageTimestamp), - lastMessage = details.lastMessage?.let { message -> - roomLastMessageFormatter.format(message.event, details.isDm) + id = roomSummary.roomId.value, + roomId = roomSummary.roomId, + name = roomInfo.name, + numberOfUnreadMessages = roomInfo.numUnreadMessages, + numberOfUnreadMentions = roomInfo.numUnreadMentions, + numberOfUnreadNotifications = roomInfo.numUnreadNotifications, + isMarkedUnread = roomInfo.isMarkedUnread, + timestamp = lastMessageTimestampFormatter.format(roomSummary.lastMessageTimestamp), + lastMessage = roomSummary.lastMessage?.let { message -> + roomLastMessageFormatter.format(message.event, roomInfo.isDm) }.orEmpty(), avatarData = avatarData, - userDefinedNotificationMode = details.userDefinedNotificationMode, - hasRoomCall = details.hasRoomCall, - isDirect = details.isDirect, - isFavorite = details.isFavorite, - inviteSender = details.inviter?.toInviteSender(), - isDm = details.isDm, - canonicalAlias = details.canonicalAlias, - displayType = if (details.currentUserMembership == CurrentUserMembership.INVITED) { + userDefinedNotificationMode = roomInfo.userDefinedNotificationMode, + hasRoomCall = roomInfo.hasRoomCall, + isDirect = roomInfo.isDirect, + isFavorite = roomInfo.isFavorite, + inviteSender = roomInfo.inviter?.toInviteSender(), + isDm = roomInfo.isDm, + canonicalAlias = roomInfo.canonicalAlias, + displayType = if (roomInfo.currentUserMembership == CurrentUserMembership.INVITED) { RoomSummaryDisplayType.INVITE } else { RoomSummaryDisplayType.ROOM }, - heroes = details.heroes.map { user -> + heroes = roomInfo.heroes.map { user -> user.getAvatarData(size = AvatarSize.RoomListItem) }.toImmutableList(), ) 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 3494d46348..eaa905eb53 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 @@ -22,9 +22,9 @@ data class RoomListRoomSummary( val roomId: RoomId, val name: String?, val canonicalAlias: RoomAlias?, - val numberOfUnreadMessages: Int, - val numberOfUnreadMentions: Int, - val numberOfUnreadNotifications: Int, + val numberOfUnreadMessages: Long, + val numberOfUnreadMentions: Long, + val numberOfUnreadNotifications: Long, val isMarkedUnread: Boolean, val timestamp: String?, val lastMessage: CharSequence?, 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 9ee23d8f3f..894bc46377 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 @@ -119,9 +119,9 @@ internal fun anInviteSender( internal fun aRoomListRoomSummary( id: String = "!roomId:domain", name: String? = "Room name", - numberOfUnreadMessages: Int = 0, - numberOfUnreadMentions: Int = 0, - numberOfUnreadNotifications: Int = 0, + numberOfUnreadMessages: Long = 0, + numberOfUnreadMentions: Long = 0, + numberOfUnreadNotifications: Long = 0, isMarkedUnread: Boolean = false, lastMessage: String? = "Last message", timestamp: String? = lastMessage?.let { "88:88" }, diff --git a/features/roomlist/impl/src/test/kotlin/io/element/android/features/roomlist/impl/RoomListPresenterTest.kt b/features/roomlist/impl/src/test/kotlin/io/element/android/features/roomlist/impl/RoomListPresenterTest.kt index 91242df095..6dfd1b0a0a 100644 --- a/features/roomlist/impl/src/test/kotlin/io/element/android/features/roomlist/impl/RoomListPresenterTest.kt +++ b/features/roomlist/impl/src/test/kotlin/io/element/android/features/roomlist/impl/RoomListPresenterTest.kt @@ -396,7 +396,7 @@ class RoomListPresenterTest { val notificationSettingsService = FakeNotificationSettingsService() val roomListService = FakeRoomListService() roomListService.postAllRoomsLoadingState(RoomList.LoadingState.Loaded(1)) - roomListService.postAllRooms(listOf(aRoomSummary(notificationMode = userDefinedMode))) + roomListService.postAllRooms(listOf(aRoomSummary(userDefinedNotificationMode = userDefinedMode))) val matrixClient = FakeMatrixClient( roomListService = roomListService, notificationSettingsService = notificationSettingsService diff --git a/features/roomlist/impl/src/test/kotlin/io/element/android/features/roomlist/impl/model/RoomListRoomSummaryTest.kt b/features/roomlist/impl/src/test/kotlin/io/element/android/features/roomlist/impl/model/RoomListRoomSummaryTest.kt index 18c8e2b011..7e91fa59de 100644 --- a/features/roomlist/impl/src/test/kotlin/io/element/android/features/roomlist/impl/model/RoomListRoomSummaryTest.kt +++ b/features/roomlist/impl/src/test/kotlin/io/element/android/features/roomlist/impl/model/RoomListRoomSummaryTest.kt @@ -76,9 +76,9 @@ class RoomListRoomSummaryTest { } internal fun createRoomListRoomSummary( - numberOfUnreadMentions: Int = 0, - numberOfUnreadMessages: Int = 0, - numberOfUnreadNotifications: Int = 0, + numberOfUnreadMentions: Long = 0, + numberOfUnreadMessages: Long = 0, + numberOfUnreadNotifications: Long = 0, isMarkedUnread: Boolean = false, userDefinedNotificationMode: RoomNotificationMode? = null, isFavorite: Boolean = false, diff --git a/features/securebackup/impl/src/main/kotlin/io/element/android/features/securebackup/impl/reset/root/ResetIdentityRootView.kt b/features/securebackup/impl/src/main/kotlin/io/element/android/features/securebackup/impl/reset/root/ResetIdentityRootView.kt index 03b6d49bf5..56bcd3e4e5 100644 --- a/features/securebackup/impl/src/main/kotlin/io/element/android/features/securebackup/impl/reset/root/ResetIdentityRootView.kt +++ b/features/securebackup/impl/src/main/kotlin/io/element/android/features/securebackup/impl/reset/root/ResetIdentityRootView.kt @@ -31,7 +31,6 @@ import io.element.android.libraries.designsystem.preview.PreviewsDayNight import io.element.android.libraries.designsystem.theme.components.Button import io.element.android.libraries.designsystem.theme.components.Icon import io.element.android.libraries.designsystem.theme.components.Text -import io.element.android.libraries.ui.strings.CommonStrings import kotlinx.collections.immutable.persistentListOf @Composable @@ -50,7 +49,7 @@ fun ResetIdentityRootView( buttons = { Button( modifier = Modifier.fillMaxWidth(), - text = stringResource(id = CommonStrings.action_continue), + text = stringResource(id = R.string.screen_encryption_reset_action_continue_reset), onClick = { state.eventSink(ResetIdentityRootEvent.Continue) }, destructive = true, ) @@ -98,9 +97,9 @@ private fun Content() { iconComposable = { Icon( modifier = Modifier.size(20.dp), - imageVector = CompoundIcons.Close(), + imageVector = CompoundIcons.Info(), contentDescription = null, - tint = ElementTheme.colors.iconCriticalPrimary, + tint = ElementTheme.colors.iconSecondary, ) }, ), @@ -109,9 +108,9 @@ private fun Content() { iconComposable = { Icon( modifier = Modifier.size(20.dp), - imageVector = CompoundIcons.Close(), + imageVector = CompoundIcons.Info(), contentDescription = null, - tint = ElementTheme.colors.iconCriticalPrimary, + tint = ElementTheme.colors.iconSecondary, ) }, ), diff --git a/features/securebackup/impl/src/main/res/values/localazy.xml b/features/securebackup/impl/src/main/res/values/localazy.xml index ad78333012..00802442d7 100644 --- a/features/securebackup/impl/src/main/res/values/localazy.xml +++ b/features/securebackup/impl/src/main/res/values/localazy.xml @@ -18,7 +18,7 @@ "Reset the encryption for your account using another device" "Continue reset" "Your account details, contacts, preferences, and chat list will be kept" - "You will lose your existing message history unless it is stored on another device" + "You will lose any message history that’s stored only on the server" "You will need to verify all your existing devices and contacts again" "Only reset your identity if you don’t have access to another signed-in device and you’ve lost your recovery key." "Can\'t confirm? You’ll need to reset your identity." diff --git a/features/securebackup/impl/src/test/kotlin/io/element/android/features/securebackup/impl/reset/root/ResetIdentityRootViewTest.kt b/features/securebackup/impl/src/test/kotlin/io/element/android/features/securebackup/impl/reset/root/ResetIdentityRootViewTest.kt index 8bf2f8cdda..4314a5d6e4 100644 --- a/features/securebackup/impl/src/test/kotlin/io/element/android/features/securebackup/impl/reset/root/ResetIdentityRootViewTest.kt +++ b/features/securebackup/impl/src/test/kotlin/io/element/android/features/securebackup/impl/reset/root/ResetIdentityRootViewTest.kt @@ -60,7 +60,7 @@ class ResetIdentityRootViewTest { ResetIdentityRootState(displayConfirmationDialog = false, eventSink = eventsRecorder), ) - rule.clickOn(CommonStrings.action_continue) + rule.clickOn(R.string.screen_encryption_reset_action_continue_reset) eventsRecorder.assertSingle(ResetIdentityRootEvent.Continue) } diff --git a/features/verifysession/impl/build.gradle.kts b/features/verifysession/impl/build.gradle.kts index 27aeaa7bc3..8f5f6cae24 100644 --- a/features/verifysession/impl/build.gradle.kts +++ b/features/verifysession/impl/build.gradle.kts @@ -23,6 +23,8 @@ android { setupAnvil() dependencies { + implementation(projects.appconfig) + implementation(projects.libraries.androidutils) implementation(projects.libraries.core) implementation(projects.libraries.architecture) implementation(projects.libraries.matrix.api) diff --git a/features/verifysession/impl/src/main/kotlin/io/element/android/features/verifysession/impl/VerifySelfSessionNode.kt b/features/verifysession/impl/src/main/kotlin/io/element/android/features/verifysession/impl/VerifySelfSessionNode.kt index ec8745ddba..3eb33b0c8d 100644 --- a/features/verifysession/impl/src/main/kotlin/io/element/android/features/verifysession/impl/VerifySelfSessionNode.kt +++ b/features/verifysession/impl/src/main/kotlin/io/element/android/features/verifysession/impl/VerifySelfSessionNode.kt @@ -18,9 +18,11 @@ 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.appconfig.LearnMoreConfig import io.element.android.compound.theme.ElementTheme import io.element.android.features.logout.api.util.onSuccessLogout import io.element.android.features.verifysession.api.VerifySessionEntryPoint +import io.element.android.libraries.androidutils.browser.openUrlInChromeCustomTab import io.element.android.libraries.architecture.inputs import io.element.android.libraries.di.SessionScope @@ -36,6 +38,10 @@ class VerifySelfSessionNode @AssistedInject constructor( showDeviceVerifiedScreen = inputs().showDeviceVerifiedScreen, ) + private fun onLearnMoreClick(activity: Activity, dark: Boolean) { + activity.openUrlInChromeCustomTab(null, dark, LearnMoreConfig.ENCRYPTION_URL) + } + @Composable override fun View(modifier: Modifier) { val state = presenter.present() @@ -44,6 +50,9 @@ class VerifySelfSessionNode @AssistedInject constructor( VerifySelfSessionView( state = state, modifier = modifier, + onLearnMoreClick = { + onLearnMoreClick(activity, isDark) + }, onEnterRecoveryKey = callback::onEnterRecoveryKey, onResetKey = callback::onResetKey, onFinish = callback::onDone, diff --git a/features/verifysession/impl/src/main/kotlin/io/element/android/features/verifysession/impl/VerifySelfSessionState.kt b/features/verifysession/impl/src/main/kotlin/io/element/android/features/verifysession/impl/VerifySelfSessionState.kt index 8565d1a7d2..81062d57c7 100644 --- a/features/verifysession/impl/src/main/kotlin/io/element/android/features/verifysession/impl/VerifySelfSessionState.kt +++ b/features/verifysession/impl/src/main/kotlin/io/element/android/features/verifysession/impl/VerifySelfSessionState.kt @@ -23,6 +23,8 @@ data class VerifySelfSessionState( @Stable sealed interface VerificationStep { data object Loading : VerificationStep + + // FIXME canEnterRecoveryKey value is never read. data class Initial(val canEnterRecoveryKey: Boolean, val isLastDevice: Boolean = false) : VerificationStep data object Canceled : VerificationStep data object AwaitingOtherDeviceResponse : VerificationStep diff --git a/features/verifysession/impl/src/main/kotlin/io/element/android/features/verifysession/impl/VerifySelfSessionView.kt b/features/verifysession/impl/src/main/kotlin/io/element/android/features/verifysession/impl/VerifySelfSessionView.kt index 6616b075db..2364688c03 100644 --- a/features/verifysession/impl/src/main/kotlin/io/element/android/features/verifysession/impl/VerifySelfSessionView.kt +++ b/features/verifysession/impl/src/main/kotlin/io/element/android/features/verifysession/impl/VerifySelfSessionView.kt @@ -9,13 +9,13 @@ package io.element.android.features.verifysession.impl import androidx.activity.compose.BackHandler import androidx.compose.foundation.Image +import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.ColumnScope import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Spacer -import androidx.compose.foundation.layout.fillMaxHeight import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height @@ -64,6 +64,7 @@ import io.element.android.features.verifysession.impl.VerifySelfSessionState.Ver @Composable fun VerifySelfSessionView( state: VerifySelfSessionState, + onLearnMoreClick: () -> Unit, onEnterRecoveryKey: () -> Unit, onResetKey: () -> Unit, onFinish: () -> Unit, @@ -140,7 +141,10 @@ fun VerifySelfSessionView( ) } ) { - Content(flowState = verificationFlowStep) + Content( + flowState = verificationFlowStep, + onLearnMoreClick = onLearnMoreClick, + ) } } @@ -203,38 +207,68 @@ private fun HeaderContent(verificationFlowStep: FlowStep) { } @Composable -private fun Content(flowState: FlowStep) { - Column(Modifier.fillMaxHeight(), verticalArrangement = Arrangement.Center) { - if (flowState is FlowStep.Verifying) { +private fun Content( + flowState: FlowStep, + onLearnMoreClick: () -> Unit, +) { + when (flowState) { + is VerifySelfSessionState.VerificationStep.Initial -> { + ContentInitial(onLearnMoreClick) + } + is FlowStep.Verifying -> { ContentVerifying(flowState) } + else -> Unit + } +} + +@Composable +private fun ContentInitial( + onLearnMoreClick: () -> Unit, +) { + Row( + modifier = Modifier.fillMaxWidth(), + horizontalArrangement = Arrangement.Center, + ) { + Text( + modifier = Modifier + .clickable { onLearnMoreClick() } + .padding(vertical = 4.dp, horizontal = 16.dp), + text = stringResource(CommonStrings.action_learn_more), + style = ElementTheme.typography.fontBodyLgMedium + ) } } @Composable private fun ContentVerifying(verificationFlowStep: FlowStep.Verifying) { - when (verificationFlowStep.data) { - is SessionVerificationData.Decimals -> { - val text = verificationFlowStep.data.decimals.joinToString(separator = " - ") { it.toString() } - Text( - modifier = Modifier.fillMaxWidth(), - text = text, - style = ElementTheme.typography.fontHeadingLgBold, - color = MaterialTheme.colorScheme.primary, - textAlign = TextAlign.Center, - ) - } - is SessionVerificationData.Emojis -> { - // We want each row to have up to 4 emojis - val rows = verificationFlowStep.data.emojis.chunked(4) - Column( - modifier = Modifier.fillMaxWidth(), - verticalArrangement = Arrangement.spacedBy(40.dp), - ) { - rows.forEach { emojis -> - Row(modifier = Modifier.fillMaxWidth(), horizontalArrangement = Arrangement.SpaceEvenly) { - for (emoji in emojis) { - EmojiItemView(emoji = emoji, modifier = Modifier.widthIn(max = 60.dp)) + Box( + modifier = Modifier.fillMaxSize(), + contentAlignment = Alignment.Center + ) { + when (verificationFlowStep.data) { + is SessionVerificationData.Decimals -> { + val text = verificationFlowStep.data.decimals.joinToString(separator = " - ") { it.toString() } + Text( + modifier = Modifier.fillMaxWidth(), + text = text, + style = ElementTheme.typography.fontHeadingLgBold, + color = MaterialTheme.colorScheme.primary, + textAlign = TextAlign.Center, + ) + } + is SessionVerificationData.Emojis -> { + // We want each row to have up to 4 emojis + val rows = verificationFlowStep.data.emojis.chunked(4) + Column( + modifier = Modifier.fillMaxWidth(), + verticalArrangement = Arrangement.spacedBy(40.dp), + ) { + rows.forEach { emojis -> + Row(modifier = Modifier.fillMaxWidth(), horizontalArrangement = Arrangement.SpaceEvenly) { + for (emoji in emojis) { + EmojiItemView(emoji = emoji, modifier = Modifier.widthIn(max = 60.dp)) + } } } } @@ -292,14 +326,14 @@ private fun BottomMenu( text = stringResource(R.string.screen_identity_use_another_device), onClick = { eventSink(VerifySelfSessionViewEvents.RequestVerification) }, ) - OutlinedButton( + Button( modifier = Modifier.fillMaxWidth(), text = stringResource(R.string.screen_session_verification_enter_recovery_key), onClick = onEnterRecoveryKey, ) } // This option should always be displayed - TextButton( + OutlinedButton( modifier = Modifier.fillMaxWidth(), text = stringResource(R.string.screen_identity_confirmation_cannot_confirm), onClick = onResetKey, @@ -402,6 +436,7 @@ private fun BottomMenu( internal fun VerifySelfSessionViewPreview(@PreviewParameter(VerifySelfSessionStateProvider::class) state: VerifySelfSessionState) = ElementPreview { VerifySelfSessionView( state = state, + onLearnMoreClick = {}, onEnterRecoveryKey = {}, onResetKey = {}, onFinish = {}, diff --git a/features/verifysession/impl/src/test/kotlin/io/element/android/features/verifysession/impl/VerifySelfSessionPresenterTest.kt b/features/verifysession/impl/src/test/kotlin/io/element/android/features/verifysession/impl/VerifySelfSessionPresenterTest.kt index 0ff24d2254..188c895f5c 100644 --- a/features/verifysession/impl/src/test/kotlin/io/element/android/features/verifysession/impl/VerifySelfSessionPresenterTest.kt +++ b/features/verifysession/impl/src/test/kotlin/io/element/android/features/verifysession/impl/VerifySelfSessionPresenterTest.kt @@ -343,6 +343,7 @@ class VerifySelfSessionPresenterTest { skipItems(1) val initialItem = awaitItem() initialItem.eventSink(VerifySelfSessionViewEvents.SignOut) + assertThat(awaitItem().signOutAction.isLoading()).isTrue() val finalItem = awaitItem() assertThat(finalItem.signOutAction.isSuccess()).isTrue() assertThat(finalItem.signOutAction.dataOrNull()).isEqualTo("aUrl") diff --git a/features/verifysession/impl/src/test/kotlin/io/element/android/features/verifysession/impl/VerifySelfSessionViewTest.kt b/features/verifysession/impl/src/test/kotlin/io/element/android/features/verifysession/impl/VerifySelfSessionViewTest.kt index 425ad79313..dfe8aaf85d 100644 --- a/features/verifysession/impl/src/test/kotlin/io/element/android/features/verifysession/impl/VerifySelfSessionViewTest.kt +++ b/features/verifysession/impl/src/test/kotlin/io/element/android/features/verifysession/impl/VerifySelfSessionViewTest.kt @@ -146,6 +146,22 @@ class VerifySelfSessionViewTest { } } + @Config(qualifiers = "h1024dp") + @Test + fun `clicking on learn more invokes the expected callback`() { + val eventsRecorder = EventsRecorder(expectEvents = false) + ensureCalledOnce { callback -> + rule.setVerifySelfSessionView( + aVerifySelfSessionState( + verificationFlowStep = VerifySelfSessionState.VerificationStep.Initial(true), + eventSink = eventsRecorder + ), + onLearnMoreClick = callback, + ) + rule.clickOn(CommonStrings.action_learn_more) + } + } + @Test fun `clicking on they match emits the expected event`() { val eventsRecorder = EventsRecorder() @@ -222,6 +238,7 @@ class VerifySelfSessionViewTest { private fun AndroidComposeTestRule.setVerifySelfSessionView( state: VerifySelfSessionState, + onLearnMoreClick: () -> Unit = EnsureNeverCalled(), onEnterRecoveryKey: () -> Unit = EnsureNeverCalled(), onFinished: () -> Unit = EnsureNeverCalled(), onResetKey: () -> Unit = EnsureNeverCalled(), @@ -230,6 +247,7 @@ class VerifySelfSessionViewTest { setContent { VerifySelfSessionView( state = state, + onLearnMoreClick = onLearnMoreClick, onEnterRecoveryKey = onEnterRecoveryKey, onFinish = onFinished, onResetKey = onResetKey, diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index a0c239bc29..ee18e98f56 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -4,9 +4,9 @@ [versions] # Project android_gradle_plugin = "8.7.0" -kotlin = "1.9.25" +kotlin = "2.0.20" kotlinpoetKsp = "1.18.1" -ksp = "1.9.25-1.0.20" +ksp = "2.0.20-1.0.25" firebaseAppDistribution = "5.0.0" # AndroidX @@ -25,7 +25,7 @@ media3 = "1.4.1" camera = "1.3.4" # Compose -compose_bom = "2024.09.02" +compose_bom = "2024.09.03" composecompiler = "1.5.15" # Coroutines @@ -40,7 +40,7 @@ test_core = "1.6.1" #other coil = "2.7.0" datetime = "0.6.0" -dependencyAnalysis = "2.1.3" +dependencyAnalysis = "2.1.4" serialization_json = "1.6.3" showkase = "1.0.3" appyx = "1.4.0" @@ -62,6 +62,7 @@ kover = "0.8.3" [libraries] # Project android_gradle_plugin = { module = "com.android.tools.build:gradle", version.ref = "android_gradle_plugin" } +compose_compiler_plugin = { module = "org.jetbrains.kotlin:compose-compiler-gradle-plugin", version.ref = "kotlin" } # https://developer.android.com/studio/write/java8-support#library-desugaring-versions android_desugar = "com.android.tools:desugar_jdk_libs:2.1.2" anvil_gradle_plugin = { module = "dev.zacsweers.anvil:gradle-plugin", version.ref = "anvil" } @@ -103,7 +104,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.2.0" androidx_preference = "androidx.preference:preference:1.2.1" -androidx_webkit = "androidx.webkit:webkit:1.12.0" +androidx_webkit = "androidx.webkit:webkit:1.12.1" androidx_compose_bom = { module = "androidx.compose:compose-bom", version.ref = "compose_bom" } androidx_compose_material3 = { module = "androidx.compose.material3:material3" } @@ -143,7 +144,7 @@ test_corektx = { module = "androidx.test:core-ktx", version.ref = "test_core" } test_arch_core = "androidx.arch.core:core-testing:2.2.0" test_junit = "junit:junit:4.13.2" test_runner = "androidx.test:runner:1.6.2" -test_mockk = "io.mockk:mockk:1.13.12" +test_mockk = "io.mockk:mockk:1.13.13" test_konsist = "com.lemonappdev:konsist:0.16.1" test_turbine = "app.cash.turbine:turbine:1.1.0" test_truth = "com.google.truth:truth:1.4.4" @@ -189,13 +190,13 @@ kotlinpoet = "com.squareup:kotlinpoet:1.18.1" zxing_cpp = "io.github.zxing-cpp:android:2.2.0" # Analytics -posthog = "com.posthog:posthog-android:3.8.0" +posthog = "com.posthog:posthog-android:3.8.1" sentry = "io.sentry:sentry-android:7.14.0" # main branch can be tested replacing the version with main-SNAPSHOT matrix_analytics_events = "com.github.matrix-org:matrix-analytics-events:0.25.0" # Emojibase -matrix_emojibase_bindings = "io.element.android:emojibase-bindings:1.1.3" +matrix_emojibase_bindings = "io.element.android:emojibase-bindings:1.3.3" sigpwned_emoji4j = "com.sigpwned:emoji4j-core:15.1.2" # Di @@ -238,3 +239,4 @@ firebaseAppDistribution = { id = "com.google.firebase.appdistribution", version. knit = { id = "org.jetbrains.kotlinx.knit", version = "0.5.0" } sonarqube = "org.sonarqube:5.1.0.4882" licensee = "app.cash.licensee:1.11.0" +compose-compiler = { id = "org.jetbrains.kotlin.plugin.compose", version.ref = "kotlin" } diff --git a/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/theme/components/LinearProgressIndicator.kt b/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/theme/components/LinearProgressIndicator.kt index 8f7f3be3bc..55f9b410a8 100644 --- a/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/theme/components/LinearProgressIndicator.kt +++ b/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/theme/components/LinearProgressIndicator.kt @@ -16,6 +16,7 @@ import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.StrokeCap import androidx.compose.ui.platform.LocalInspectionMode import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.Dp import androidx.compose.ui.unit.dp import io.element.android.libraries.designsystem.preview.ElementThemedPreview import io.element.android.libraries.designsystem.preview.PreviewGroup @@ -24,6 +25,7 @@ import io.element.android.libraries.designsystem.preview.PreviewGroup fun LinearProgressIndicator( progress: () -> Float, modifier: Modifier = Modifier, + gapSize: Dp = 0.dp, color: Color = ProgressIndicatorDefaults.linearColor, trackColor: Color = ProgressIndicatorDefaults.linearTrackColor, strokeCap: StrokeCap = ProgressIndicatorDefaults.LinearStrokeCap, @@ -31,9 +33,11 @@ fun LinearProgressIndicator( androidx.compose.material3.LinearProgressIndicator( modifier = modifier, progress = progress, + gapSize = gapSize, color = color, trackColor = trackColor, strokeCap = strokeCap, + drawStopIndicator = {}, ) } @@ -41,6 +45,7 @@ fun LinearProgressIndicator( fun LinearProgressIndicator( modifier: Modifier = Modifier, color: Color = ProgressIndicatorDefaults.linearColor, + gapSize: Dp = 0.dp, trackColor: Color = ProgressIndicatorDefaults.linearTrackColor, strokeCap: StrokeCap = ProgressIndicatorDefaults.LinearStrokeCap, ) { @@ -49,14 +54,17 @@ fun LinearProgressIndicator( androidx.compose.material3.LinearProgressIndicator( modifier = modifier, progress = { 0.75F }, + gapSize = gapSize, color = color, trackColor = trackColor, strokeCap = strokeCap, + drawStopIndicator = {}, ) } else { androidx.compose.material3.LinearProgressIndicator( modifier = modifier, color = color, + gapSize = gapSize, trackColor = trackColor, strokeCap = strokeCap, ) diff --git a/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/theme/components/bottomsheet/CustomSheetState.kt b/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/theme/components/bottomsheet/CustomSheetState.kt index ac02787c3f..694674621a 100644 --- a/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/theme/components/bottomsheet/CustomSheetState.kt +++ b/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/theme/components/bottomsheet/CustomSheetState.kt @@ -7,7 +7,6 @@ package io.element.android.libraries.designsystem.theme.components.bottomsheet -import androidx.compose.animation.core.DecayAnimationSpec import androidx.compose.animation.core.SpringSpec import androidx.compose.animation.core.exponentialDecay import androidx.compose.foundation.ExperimentalFoundationApi @@ -296,13 +295,9 @@ internal object AnchoredDraggableDefaults { /** * The default animation used by [AnchoredDraggableState]. */ - @get:ExperimentalMaterial3Api - @Suppress("OPT_IN_MARKER_ON_WRONG_TARGET") @ExperimentalMaterial3Api val SnapAnimationSpec = SpringSpec() - @get:ExperimentalMaterial3Api - @Suppress("OPT_IN_MARKER_ON_WRONG_TARGET") @ExperimentalMaterial3Api val DecayAnimationSpec = exponentialDecay() } diff --git a/libraries/featureflag/api/src/main/kotlin/io/element/android/libraries/featureflag/api/FeatureFlags.kt b/libraries/featureflag/api/src/main/kotlin/io/element/android/libraries/featureflag/api/FeatureFlags.kt index 3f2e1b389b..9f5b985435 100644 --- a/libraries/featureflag/api/src/main/kotlin/io/element/android/libraries/featureflag/api/FeatureFlags.kt +++ b/libraries/featureflag/api/src/main/kotlin/io/element/android/libraries/featureflag/api/FeatureFlags.kt @@ -9,7 +9,6 @@ package io.element.android.libraries.featureflag.api import io.element.android.appconfig.OnBoardingConfig import io.element.android.libraries.core.meta.BuildMeta -import io.element.android.libraries.core.meta.BuildType /** * To enable or disable a FeatureFlags, change the `defaultValue` value. @@ -93,13 +92,7 @@ enum class FeatureFlags( key = "feature.qrCodeLogin", title = "Enable login using QR code", description = "Allow the user to login using the QR code flow", - defaultValue = { buildMeta -> - when (buildMeta.buildType) { - // TODO remove once the feature is ready to publish - BuildType.RELEASE -> false - else -> OnBoardingConfig.CAN_LOGIN_WITH_QR_CODE - } - }, + defaultValue = { OnBoardingConfig.CAN_LOGIN_WITH_QR_CODE }, isFinished = false, ), IncomingShare( @@ -132,4 +125,17 @@ enum class FeatureFlags( defaultValue = { false }, isFinished = false, ), + IdentityPinningViolationNotifications( + key = "feature.identityPinningViolationNotifications", + title = "Identity pinning violation notifications", + description = null, + defaultValue = { buildMeta -> + when (buildMeta.buildType) { + // Do not enable this feature in release builds + BuildType.RELEASE -> false + else -> true + } + }, + isFinished = false, + ), } 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 6dacb03dfb..ea26e29719 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 @@ -38,6 +38,8 @@ import kotlinx.collections.immutable.ImmutableList import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.StateFlow +import kotlinx.coroutines.flow.distinctUntilChanged +import kotlinx.coroutines.flow.map import java.io.Closeable import java.util.Optional @@ -94,7 +96,13 @@ interface MatrixClient : Closeable { suspend fun getAccountManagementUrl(action: AccountManagementAction?): Result suspend fun uploadMedia(mimeType: String, data: ByteArray, progressCallback: ProgressCallback?): Result fun roomMembershipObserver(): RoomMembershipObserver - fun getRoomInfoFlow(roomId: RoomId): Flow> + + /** + * Get a room summary flow for a given room ID or alias. + * The flow will emit a new value whenever the room summary is updated. + * The flow will emit Optional.empty item if the room is not found. + */ + fun getRoomSummaryFlow(roomIdOrAlias: RoomIdOrAlias): Flow> fun isMe(userId: UserId?) = userId == sessionId @@ -142,3 +150,14 @@ interface MatrixClient : Closeable { fun canDeactivateAccount(): Boolean suspend fun deactivateAccount(password: String, eraseData: Boolean): Result } + +/** + * Get a room info flow for a given room ID or alias. + * The flow will emit a new value whenever the room info is updated. + * The flow will emit Optional.empty item if the room is not found. + */ +fun MatrixClient.getRoomInfoFlow(roomIdOrAlias: RoomIdOrAlias): Flow> { + return getRoomSummaryFlow(roomIdOrAlias) + .map { roomSummary -> roomSummary.map { it.info } } + .distinctUntilChanged() +} diff --git a/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/room/MatrixRoomInfo.kt b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/room/MatrixRoomInfo.kt index b83c2c98d6..6105a59c38 100644 --- a/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/room/MatrixRoomInfo.kt +++ b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/room/MatrixRoomInfo.kt @@ -33,6 +33,13 @@ data class MatrixRoomInfo( val canonicalAlias: RoomAlias?, val alternativeAliases: ImmutableList, val currentUserMembership: CurrentUserMembership, + /** + * Member who invited the current user to a room that's in the invited + * state. + * + * Can be missing if the room membership invite event is missing from the + * store. + */ val inviter: RoomMember?, val activeMembersCount: Long, val invitedMembersCount: Long, @@ -43,7 +50,26 @@ data class MatrixRoomInfo( val userDefinedNotificationMode: RoomNotificationMode?, val hasRoomCall: Boolean, val activeRoomCallParticipants: ImmutableList, + val isMarkedUnread: Boolean, + /** + * "Interesting" messages received in that room, independently of the + * notification settings. + */ + val numUnreadMessages: Long, + /** + * Events that will notify the user, according to their + * notification settings. + */ + val numUnreadNotifications: Long, + /** + * Events causing mentions/highlights for the user, according to their + * notification settings. + */ + val numUnreadMentions: Long, val heroes: ImmutableList, val pinnedEventIds: ImmutableList, val creator: UserId?, -) +) { + val aliases: List + get() = listOfNotNull(canonicalAlias) + alternativeAliases +} 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 0fd1ab4a34..9ba07f50d8 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 @@ -7,35 +7,14 @@ package io.element.android.libraries.matrix.api.roomlist -import io.element.android.libraries.matrix.api.core.RoomAlias -import io.element.android.libraries.matrix.api.core.RoomId -import io.element.android.libraries.matrix.api.room.CurrentUserMembership -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.MatrixRoomInfo import io.element.android.libraries.matrix.api.room.message.RoomMessage -import io.element.android.libraries.matrix.api.user.MatrixUser data class RoomSummary( - val roomId: RoomId, - val name: String?, - val canonicalAlias: RoomAlias?, - val alternativeAliases: List, - val isDirect: Boolean, - val avatarUrl: String?, + val info: MatrixRoomInfo, val lastMessage: RoomMessage?, - val numUnreadMessages: Int, - val numUnreadMentions: Int, - val numUnreadNotifications: Int, - val isMarkedUnread: Boolean, - val inviter: RoomMember?, - val userDefinedNotificationMode: RoomNotificationMode?, - val hasRoomCall: Boolean, - val isDm: Boolean, - val isFavorite: Boolean, - val currentUserMembership: CurrentUserMembership, - val heroes: List, ) { + val roomId = info.id val lastMessageTimestamp = lastMessage?.originServerTs - val aliases: List - get() = listOfNotNull(canonicalAlias) + alternativeAliases + val isOneToOne get() = info.activeMembersCount == 2L } 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 b47ac6fdc7..1abe47a362 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 @@ -32,7 +32,6 @@ import io.element.android.libraries.matrix.api.pusher.PushersService import io.element.android.libraries.matrix.api.room.CurrentUserMembership import io.element.android.libraries.matrix.api.room.InvitedRoom 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.RoomMembershipObserver import io.element.android.libraries.matrix.api.room.alias.ResolvedRoomAlias import io.element.android.libraries.matrix.api.room.preview.RoomPreview @@ -84,8 +83,8 @@ import kotlinx.coroutines.flow.buffer import kotlinx.coroutines.flow.distinctUntilChanged import kotlinx.coroutines.flow.filter import kotlinx.coroutines.flow.first -import kotlinx.coroutines.flow.flow import kotlinx.coroutines.flow.map +import kotlinx.coroutines.flow.mapNotNull import kotlinx.coroutines.flow.stateIn import kotlinx.coroutines.launch import kotlinx.coroutines.runBlocking @@ -105,8 +104,8 @@ import org.matrix.rustcomponents.sdk.use import timber.log.Timber import java.io.File import java.util.Optional +import kotlin.jvm.optionals.getOrNull import kotlin.time.Duration -import kotlin.time.Duration.Companion.INFINITE import kotlin.time.Duration.Companion.seconds import org.matrix.rustcomponents.sdk.CreateRoomParameters as RustCreateRoomParameters import org.matrix.rustcomponents.sdk.RoomPreset as RustRoomPreset @@ -262,21 +261,14 @@ class RustMatrixClient( * @param timeout the timeout to wait for the room to be available * @throws TimeoutCancellationException if the room is not available after the timeout */ - private suspend fun awaitJoinedRoom(roomIdOrAlias: RoomIdOrAlias, timeout: Duration): RoomSummary { - val predicate: (List) -> Boolean = when (roomIdOrAlias) { - is RoomIdOrAlias.Alias -> { roomSummaries: List -> - val found = roomSummaries.find { it.aliases.contains(roomIdOrAlias.roomAlias) } - found != null && found.currentUserMembership == CurrentUserMembership.JOINED - } - is RoomIdOrAlias.Id -> { roomSummaries: List -> - val found = roomSummaries.find { it.roomId == roomIdOrAlias.roomId } - found != null && found.currentUserMembership == CurrentUserMembership.JOINED - } - } + private suspend fun awaitJoinedRoom( + roomIdOrAlias: RoomIdOrAlias, + timeout: Duration + ): RoomSummary { return withTimeout(timeout) { - roomListService.allRooms.summaries - .filter(predicate) - .first() + getRoomSummaryFlow(roomIdOrAlias) + .mapNotNull { optionalRoomSummary -> optionalRoomSummary.getOrNull() } + .filter { roomSummary -> roomSummary.info.currentUserMembership == CurrentUserMembership.JOINED } .first() // Ensure that the room is ready .also { client.awaitRoomRemoteEcho(it.roomId.value) } @@ -568,20 +560,21 @@ class RustMatrixClient( override fun roomMembershipObserver(): RoomMembershipObserver = roomMembershipObserver - override fun getRoomInfoFlow(roomId: RoomId): Flow> { - return flow { - var room = getRoom(roomId) - if (room == null) { - emit(Optional.empty()) - awaitJoinedRoom(roomId.toRoomIdOrAlias(), INFINITE) - room = getRoom(roomId) + override fun getRoomSummaryFlow(roomIdOrAlias: RoomIdOrAlias): Flow> { + val predicate: (RoomSummary) -> Boolean = when (roomIdOrAlias) { + is RoomIdOrAlias.Alias -> { roomSummary -> + roomSummary.info.aliases.contains(roomIdOrAlias.roomAlias) } - room?.use { - room.roomInfoFlow - .map { roomInfo -> Optional.of(roomInfo) } - .collect(this) + is RoomIdOrAlias.Id -> { roomSummary -> + roomSummary.roomId == roomIdOrAlias.roomId } - }.distinctUntilChanged() + } + return roomListService.allRooms.summaries + .map { roomSummaries -> + val roomSummary = roomSummaries.firstOrNull(predicate) + Optional.ofNullable(roomSummary) + } + .distinctUntilChanged() } override suspend fun setAllSendQueuesEnabled(enabled: Boolean) = withContext(sessionDispatcher) { 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 c7ed6c1205..c6d60bdca5 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 @@ -53,6 +53,10 @@ class MatrixRoomInfoMapper { activeRoomCallParticipants = it.activeRoomCallParticipants.map(::UserId).toImmutableList(), heroes = it.elementHeroes().toImmutableList(), pinnedEventIds = it.pinnedEventIds.map(::EventId).toImmutableList(), + isMarkedUnread = it.isMarkedUnread, + numUnreadMessages = it.numUnreadMessages.toLong(), + numUnreadMentions = it.numUnreadMentions.toLong(), + numUnreadNotifications = it.numUnreadNotifications.toLong(), ) } } diff --git a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/roomlist/RoomListFactory.kt b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/roomlist/RoomListFactory.kt index 77e2de1f94..aa0fcfd285 100644 --- a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/roomlist/RoomListFactory.kt +++ b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/roomlist/RoomListFactory.kt @@ -31,7 +31,7 @@ internal class RoomListFactory( private val innerRoomListService: RoomListService, private val sessionCoroutineScope: CoroutineScope, ) { - private val roomSummaryDetailsFactory: RoomSummaryDetailsFactory = RoomSummaryDetailsFactory() + private val roomSummaryDetailsFactory: RoomSummaryFactory = RoomSummaryFactory() /** * Creates a room list that can be used to load more rooms and filter them dynamically. diff --git a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/roomlist/RoomListFilter.kt b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/roomlist/RoomListFilter.kt index b49c4138e8..88458d56bb 100644 --- a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/roomlist/RoomListFilter.kt +++ b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/roomlist/RoomListFilter.kt @@ -8,6 +8,7 @@ package io.element.android.libraries.matrix.impl.roomlist import io.element.android.libraries.matrix.api.room.CurrentUserMembership +import io.element.android.libraries.matrix.api.room.isDm import io.element.android.libraries.matrix.api.roomlist.RoomListFilter import io.element.android.libraries.matrix.api.roomlist.RoomSummary @@ -17,19 +18,19 @@ val RoomListFilter.predicate is RoomListFilter.Any -> { _: RoomSummary -> true } RoomListFilter.None -> { _: RoomSummary -> false } RoomListFilter.Category.Group -> { roomSummary: RoomSummary -> - !roomSummary.isDm && !roomSummary.isInvited() + !roomSummary.info.isDm && !roomSummary.isInvited() } RoomListFilter.Category.People -> { roomSummary: RoomSummary -> - roomSummary.isDm && !roomSummary.isInvited() + roomSummary.info.isDm && !roomSummary.isInvited() } RoomListFilter.Favorite -> { roomSummary: RoomSummary -> - roomSummary.isFavorite && !roomSummary.isInvited() + roomSummary.info.isFavorite && !roomSummary.isInvited() } RoomListFilter.Unread -> { roomSummary: RoomSummary -> - !roomSummary.isInvited() && (roomSummary.numUnreadNotifications > 0 || roomSummary.isMarkedUnread) + !roomSummary.isInvited() && (roomSummary.info.numUnreadNotifications > 0 || roomSummary.info.isMarkedUnread) } is RoomListFilter.NormalizedMatchRoomName -> { roomSummary: RoomSummary -> - roomSummary.name.orEmpty().contains(pattern, ignoreCase = true) + roomSummary.info.name.orEmpty().contains(pattern, ignoreCase = true) } RoomListFilter.Invite -> { roomSummary: RoomSummary -> roomSummary.isInvited() @@ -50,4 +51,4 @@ fun List.filter(filter: RoomListFilter): List { } } -private fun RoomSummary.isInvited() = currentUserMembership == CurrentUserMembership.INVITED +private fun RoomSummary.isInvited() = info.currentUserMembership == CurrentUserMembership.INVITED 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 deleted file mode 100644 index 92dbed82b6..0000000000 --- a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/roomlist/RoomSummaryDetailsFactory.kt +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Copyright 2023, 2024 New Vector Ltd. - * - * SPDX-License-Identifier: AGPL-3.0-only - * Please see LICENSE in the repository root for full details. - */ - -package io.element.android.libraries.matrix.impl.roomlist - -import io.element.android.libraries.matrix.api.core.RoomAlias -import io.element.android.libraries.matrix.api.core.RoomId -import io.element.android.libraries.matrix.api.room.isDm -import io.element.android.libraries.matrix.api.roomlist.RoomSummary -import io.element.android.libraries.matrix.impl.notificationsettings.RoomNotificationSettingsMapper -import io.element.android.libraries.matrix.impl.room.elementHeroes -import io.element.android.libraries.matrix.impl.room.map -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.RoomListItem -import org.matrix.rustcomponents.sdk.use - -class RoomSummaryDetailsFactory( - private val roomMessageFactory: RoomMessageFactory = RoomMessageFactory(), -) { - suspend fun create(roomListItem: RoomListItem): RoomSummary { - val roomInfo = roomListItem.roomInfo() - val latestRoomMessage = roomListItem.latestEvent().use { event -> - roomMessageFactory.create(event) - } - return RoomSummary( - roomId = RoomId(roomInfo.id), - name = roomInfo.displayName, - canonicalAlias = roomInfo.canonicalAlias?.let(::RoomAlias), - alternativeAliases = roomInfo.alternativeAliases.map(::RoomAlias), - isDirect = roomInfo.isDirect, - avatarUrl = roomInfo.avatarUrl, - numUnreadMentions = roomInfo.numUnreadMentions.toInt(), - numUnreadMessages = roomInfo.numUnreadMessages.toInt(), - numUnreadNotifications = roomInfo.numUnreadNotifications.toInt(), - isMarkedUnread = roomInfo.isMarkedUnread, - lastMessage = latestRoomMessage, - inviter = roomInfo.inviter?.let(RoomMemberMapper::map), - userDefinedNotificationMode = roomInfo.cachedUserDefinedNotificationMode?.let(RoomNotificationSettingsMapper::mapMode), - hasRoomCall = roomInfo.hasRoomCall, - isDm = isDm(isDirect = roomInfo.isDirect, activeMembersCount = roomInfo.activeMembersCount.toInt()), - isFavorite = roomInfo.isFavourite, - currentUserMembership = roomInfo.membership.map(), - heroes = roomInfo.elementHeroes(), - ) - } -} diff --git a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/roomlist/RoomSummaryFactory.kt b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/roomlist/RoomSummaryFactory.kt new file mode 100644 index 0000000000..8a92a6f881 --- /dev/null +++ b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/roomlist/RoomSummaryFactory.kt @@ -0,0 +1,30 @@ +/* + * Copyright 2023, 2024 New Vector Ltd. + * + * SPDX-License-Identifier: AGPL-3.0-only + * Please see LICENSE in the repository root for full details. + */ + +package io.element.android.libraries.matrix.impl.roomlist + +import io.element.android.libraries.matrix.api.roomlist.RoomSummary +import io.element.android.libraries.matrix.impl.room.MatrixRoomInfoMapper +import io.element.android.libraries.matrix.impl.room.message.RoomMessageFactory +import org.matrix.rustcomponents.sdk.RoomListItem +import org.matrix.rustcomponents.sdk.use + +class RoomSummaryFactory( + private val roomMessageFactory: RoomMessageFactory = RoomMessageFactory(), + private val roomInfoMapper: MatrixRoomInfoMapper = MatrixRoomInfoMapper(), +) { + suspend fun create(roomListItem: RoomListItem): RoomSummary { + val roomInfo = roomListItem.roomInfo().let(roomInfoMapper::map) + val latestRoomMessage = roomListItem.latestEvent().use { event -> + roomMessageFactory.create(event) + } + return RoomSummary( + info = roomInfo, + lastMessage = latestRoomMessage, + ) + } +} diff --git a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/roomlist/RoomSummaryListProcessor.kt b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/roomlist/RoomSummaryListProcessor.kt index a4addd52f6..5db2ac9b7c 100644 --- a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/roomlist/RoomSummaryListProcessor.kt +++ b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/roomlist/RoomSummaryListProcessor.kt @@ -23,9 +23,8 @@ class RoomSummaryListProcessor( private val roomSummaries: MutableSharedFlow>, private val roomListService: RoomListServiceInterface, private val coroutineContext: CoroutineContext, - private val roomSummaryDetailsFactory: RoomSummaryDetailsFactory = RoomSummaryDetailsFactory(), + private val roomSummaryDetailsFactory: RoomSummaryFactory = RoomSummaryFactory(), ) { - private val roomSummariesByIdentifier = HashMap() private val mutex = Mutex() suspend fun postUpdate(updates: List) { @@ -40,7 +39,7 @@ class RoomSummaryListProcessor( suspend fun rebuildRoomSummaries() { updateRoomSummaries { forEachIndexed { i, summary -> - val result = buildAndCacheRoomSummaryForIdentifier(summary.roomId.value) + val result = buildRoomSummaryForIdentifier(summary.roomId.value) if (result != null) { this[i] = result } @@ -97,23 +96,17 @@ class RoomSummaryListProcessor( } private suspend fun buildSummaryForRoomListEntry(entry: RoomListItem): RoomSummary { - return buildAndCacheRoomSummaryForRoomListItem(entry) + return buildRoomSummaryForRoomListItem(entry) } - private suspend fun buildAndCacheRoomSummaryForIdentifier(identifier: String): RoomSummary? { - val builtRoomSummary = roomListService.roomOrNull(identifier)?.use { roomListItem -> - buildAndCacheRoomSummaryForRoomListItem(roomListItem) + private suspend fun buildRoomSummaryForIdentifier(identifier: String): RoomSummary? { + return roomListService.roomOrNull(identifier)?.use { roomListItem -> + buildRoomSummaryForRoomListItem(roomListItem) } - if (builtRoomSummary == null) { - roomSummariesByIdentifier.remove(identifier) - } - return builtRoomSummary } - private suspend fun buildAndCacheRoomSummaryForRoomListItem(roomListItem: RoomListItem): RoomSummary { - val builtRoomSummary = roomSummaryDetailsFactory.create(roomListItem = roomListItem) - roomSummariesByIdentifier[builtRoomSummary.roomId.value] = builtRoomSummary - return builtRoomSummary + private suspend fun buildRoomSummaryForRoomListItem(roomListItem: RoomListItem): RoomSummary { + return roomSummaryDetailsFactory.create(roomListItem = roomListItem) } private suspend fun updateRoomSummaries(block: suspend MutableList.() -> Unit) = withContext(coroutineContext) { diff --git a/libraries/matrix/impl/src/test/kotlin/io/element/android/libraries/matrix/impl/room/MatrixRoomInfoMapperTest.kt b/libraries/matrix/impl/src/test/kotlin/io/element/android/libraries/matrix/impl/room/MatrixRoomInfoMapperTest.kt index c9e80f493d..d2fa714880 100644 --- a/libraries/matrix/impl/src/test/kotlin/io/element/android/libraries/matrix/impl/room/MatrixRoomInfoMapperTest.kt +++ b/libraries/matrix/impl/src/test/kotlin/io/element/android/libraries/matrix/impl/room/MatrixRoomInfoMapperTest.kt @@ -105,6 +105,10 @@ class MatrixRoomInfoMapperTest { ).toImmutableList(), pinnedEventIds = listOf(AN_EVENT_ID).toPersistentList(), creator = A_USER_ID, + isMarkedUnread = false, + numUnreadMessages = 12L, + numUnreadNotifications = 13L, + numUnreadMentions = 14L, ) ) } @@ -174,6 +178,10 @@ class MatrixRoomInfoMapperTest { heroes = emptyList().toImmutableList(), pinnedEventIds = emptyList().toPersistentList(), creator = null, + isMarkedUnread = true, + numUnreadMessages = 12L, + numUnreadNotifications = 13L, + numUnreadMentions = 14L, ) ) } diff --git a/libraries/matrix/impl/src/test/kotlin/io/element/android/libraries/matrix/impl/room/join/DefaultJoinRoomTest.kt b/libraries/matrix/impl/src/test/kotlin/io/element/android/libraries/matrix/impl/room/join/DefaultJoinRoomTest.kt index 5eefbefc47..8ab9d2aa73 100644 --- a/libraries/matrix/impl/src/test/kotlin/io/element/android/libraries/matrix/impl/room/join/DefaultJoinRoomTest.kt +++ b/libraries/matrix/impl/src/test/kotlin/io/element/android/libraries/matrix/impl/room/join/DefaultJoinRoomTest.kt @@ -19,7 +19,7 @@ import io.element.android.libraries.matrix.test.A_ROOM_ID import io.element.android.libraries.matrix.test.A_SERVER_LIST 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.aRoomSummaryFilled +import io.element.android.libraries.matrix.test.room.aRoomSummary import io.element.android.services.analytics.test.FakeAnalyticsService import io.element.android.tests.testutils.lambda.lambdaRecorder import io.element.android.tests.testutils.lambda.value @@ -29,7 +29,7 @@ import org.junit.Test class DefaultJoinRoomTest { @Test fun `when using roomId and there is no server names, the classic join room API is used`() = runTest { - val roomSummary = aRoomSummaryFilled() + val roomSummary = aRoomSummary() val joinRoomLambda = lambdaRecorder { _: RoomId -> Result.success(roomSummary) } val joinRoomByIdOrAliasLambda = lambdaRecorder { _: RoomIdOrAlias, _: List -> Result.success(roomSummary) } val roomResult = FakeMatrixRoom() @@ -64,7 +64,7 @@ class DefaultJoinRoomTest { @Test fun `when using roomId and server names are available, joinRoomByIdOrAlias API is used`() = runTest { - val roomSummary = aRoomSummaryFilled() + val roomSummary = aRoomSummary() val joinRoomLambda = lambdaRecorder { _: RoomId -> Result.success(roomSummary) } val joinRoomByIdOrAliasLambda = lambdaRecorder { _: RoomIdOrAlias, _: List -> Result.success(roomSummary) } val roomResult = FakeMatrixRoom() @@ -100,7 +100,7 @@ class DefaultJoinRoomTest { @Test fun `when using roomAlias, joinRoomByIdOrAlias API is used`() = runTest { - val roomSummary = aRoomSummaryFilled() + val roomSummary = aRoomSummary() val joinRoomLambda = lambdaRecorder { _: RoomId -> Result.success(roomSummary) } val joinRoomByIdOrAliasLambda = lambdaRecorder { _: RoomIdOrAlias, _: List -> Result.success(roomSummary) } val roomResult = FakeMatrixRoom() diff --git a/libraries/matrix/impl/src/test/kotlin/io/element/android/libraries/matrix/impl/roomlist/RoomListFilterTest.kt b/libraries/matrix/impl/src/test/kotlin/io/element/android/libraries/matrix/impl/roomlist/RoomListFilterTest.kt index 7c4e76e491..abe7e17bba 100644 --- a/libraries/matrix/impl/src/test/kotlin/io/element/android/libraries/matrix/impl/roomlist/RoomListFilterTest.kt +++ b/libraries/matrix/impl/src/test/kotlin/io/element/android/libraries/matrix/impl/roomlist/RoomListFilterTest.kt @@ -16,10 +16,11 @@ import org.junit.Test class RoomListFilterTest { private val regularRoom = aRoomSummary( - isDm = false + isDirect = false, ) private val dmRoom = aRoomSummary( - isDm = true + isDirect = true, + activeMembersCount = 2 ) private val favoriteRoom = aRoomSummary( isFavorite = true diff --git a/libraries/matrix/impl/src/test/kotlin/io/element/android/libraries/matrix/impl/roomlist/RoomSummaryListProcessorTest.kt b/libraries/matrix/impl/src/test/kotlin/io/element/android/libraries/matrix/impl/roomlist/RoomSummaryListProcessorTest.kt index 082ab2523d..be63a81bfe 100644 --- a/libraries/matrix/impl/src/test/kotlin/io/element/android/libraries/matrix/impl/roomlist/RoomSummaryListProcessorTest.kt +++ b/libraries/matrix/impl/src/test/kotlin/io/element/android/libraries/matrix/impl/roomlist/RoomSummaryListProcessorTest.kt @@ -15,7 +15,6 @@ import io.element.android.libraries.matrix.test.A_ROOM_ID import io.element.android.libraries.matrix.test.A_ROOM_ID_2 import io.element.android.libraries.matrix.test.A_ROOM_ID_3 import io.element.android.libraries.matrix.test.room.aRoomSummary -import io.element.android.libraries.matrix.test.room.aRoomSummaryFilled import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.test.StandardTestDispatcher import kotlinx.coroutines.test.TestScope @@ -40,7 +39,7 @@ class RoomSummaryListProcessorTest { @Test fun `PushBack adds a new entry at the end of the list`() = runTest { - summaries.value = listOf(aRoomSummaryFilled()) + summaries.value = listOf(aRoomSummary()) val processor = createProcessor() processor.postUpdate(listOf(RoomListEntriesUpdate.PushBack(FakeRustRoomListItem(A_ROOM_ID_2)))) @@ -50,7 +49,7 @@ class RoomSummaryListProcessorTest { @Test fun `PushFront inserts a new entry at the start of the list`() = runTest { - summaries.value = listOf(aRoomSummaryFilled()) + summaries.value = listOf(aRoomSummary()) val processor = createProcessor() processor.postUpdate(listOf(RoomListEntriesUpdate.PushFront(FakeRustRoomListItem(A_ROOM_ID_2)))) @@ -60,7 +59,7 @@ class RoomSummaryListProcessorTest { @Test fun `Set replaces an entry at some index`() = runTest { - summaries.value = listOf(aRoomSummaryFilled()) + summaries.value = listOf(aRoomSummary()) val processor = createProcessor() val index = 0 @@ -72,7 +71,7 @@ class RoomSummaryListProcessorTest { @Test fun `Insert inserts a new entry at the provided index`() = runTest { - summaries.value = listOf(aRoomSummaryFilled()) + summaries.value = listOf(aRoomSummary()) val processor = createProcessor() val index = 0 @@ -84,7 +83,10 @@ class RoomSummaryListProcessorTest { @Test fun `Remove removes an entry at some index`() = runTest { - summaries.value = listOf(aRoomSummaryFilled(roomId = A_ROOM_ID), aRoomSummaryFilled(A_ROOM_ID_2)) + summaries.value = listOf( + aRoomSummary(roomId = A_ROOM_ID), + aRoomSummary(A_ROOM_ID_2) + ) val processor = createProcessor() val index = 0 @@ -96,7 +98,10 @@ class RoomSummaryListProcessorTest { @Test fun `PopBack removes an entry at the end of the list`() = runTest { - summaries.value = listOf(aRoomSummaryFilled(roomId = A_ROOM_ID), aRoomSummaryFilled(A_ROOM_ID_2)) + summaries.value = listOf( + aRoomSummary(roomId = A_ROOM_ID), + aRoomSummary(A_ROOM_ID_2) + ) val processor = createProcessor() val index = 0 @@ -108,7 +113,10 @@ class RoomSummaryListProcessorTest { @Test fun `PopFront removes an entry at the start of the list`() = runTest { - summaries.value = listOf(aRoomSummaryFilled(roomId = A_ROOM_ID), aRoomSummaryFilled(A_ROOM_ID_2)) + summaries.value = listOf( + aRoomSummary(roomId = A_ROOM_ID), + aRoomSummary(A_ROOM_ID_2) + ) val processor = createProcessor() val index = 0 @@ -120,7 +128,10 @@ class RoomSummaryListProcessorTest { @Test fun `Clear removes all the entries`() = runTest { - summaries.value = listOf(aRoomSummaryFilled(roomId = A_ROOM_ID), aRoomSummaryFilled(A_ROOM_ID_2)) + summaries.value = listOf( + aRoomSummary(roomId = A_ROOM_ID), + aRoomSummary(A_ROOM_ID_2) + ) val processor = createProcessor() processor.postUpdate(listOf(RoomListEntriesUpdate.Clear)) @@ -130,7 +141,10 @@ class RoomSummaryListProcessorTest { @Test fun `Truncate removes all entries after the provided length`() = runTest { - summaries.value = listOf(aRoomSummaryFilled(roomId = A_ROOM_ID), aRoomSummaryFilled(A_ROOM_ID_2)) + summaries.value = listOf( + aRoomSummary(roomId = A_ROOM_ID), + aRoomSummary(A_ROOM_ID_2) + ) val processor = createProcessor() val index = 0 @@ -142,7 +156,10 @@ class RoomSummaryListProcessorTest { @Test fun `Reset removes all entries and add the provided ones`() = runTest { - summaries.value = listOf(aRoomSummaryFilled(roomId = A_ROOM_ID), aRoomSummaryFilled(A_ROOM_ID_2)) + summaries.value = listOf( + aRoomSummary(roomId = A_ROOM_ID), + aRoomSummary(A_ROOM_ID_2) + ) val processor = createProcessor() val index = 0 @@ -156,6 +173,6 @@ class RoomSummaryListProcessorTest { summaries, FakeRustRoomListService(), coroutineContext = StandardTestDispatcher(testScheduler), - roomSummaryDetailsFactory = RoomSummaryDetailsFactory(), + roomSummaryDetailsFactory = RoomSummaryFactory(), ) } 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 2d5e29f064..d784bba502 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 @@ -24,7 +24,6 @@ import io.element.android.libraries.matrix.api.oidc.AccountManagementAction import io.element.android.libraries.matrix.api.pusher.PushersService import io.element.android.libraries.matrix.api.room.InvitedRoom 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.RoomMembershipObserver import io.element.android.libraries.matrix.api.room.alias.ResolvedRoomAlias import io.element.android.libraries.matrix.api.room.preview.RoomPreview @@ -118,8 +117,8 @@ class FakeMatrixClient( var knockRoomLambda: (RoomId) -> Result = { Result.success(Unit) } - var getRoomInfoFlowLambda = { _: RoomId -> - flowOf>(Optional.empty()) + var getRoomSummaryFlowLambda = { _: RoomIdOrAlias -> + flowOf>(Optional.empty()) } var logoutLambda: (Boolean, Boolean) -> String? = { _, _ -> null @@ -316,7 +315,7 @@ class FakeMatrixClient( return Result.success(visitedRoomsId) } - override fun getRoomInfoFlow(roomId: RoomId) = getRoomInfoFlowLambda(roomId) + override fun getRoomSummaryFlow(roomIdOrAlias: RoomIdOrAlias) = getRoomSummaryFlowLambda(roomIdOrAlias) var setAllSendQueuesEnabledLambda = lambdaRecorder(ensureNeverCalled = true) { _: Boolean -> // no-op 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 ab0ad45cac..2190f89d13 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 @@ -24,7 +24,6 @@ import io.element.android.libraries.matrix.api.media.MediaUploadHandler import io.element.android.libraries.matrix.api.media.VideoInfo import io.element.android.libraries.matrix.api.notificationsettings.NotificationSettingsService import io.element.android.libraries.matrix.api.poll.PollKind -import io.element.android.libraries.matrix.api.room.CurrentUserMembership import io.element.android.libraries.matrix.api.room.IntentionalMention import io.element.android.libraries.matrix.api.room.MatrixRoom import io.element.android.libraries.matrix.api.room.MatrixRoomInfo @@ -32,7 +31,6 @@ import io.element.android.libraries.matrix.api.room.MatrixRoomMembersState import io.element.android.libraries.matrix.api.room.MatrixRoomNotificationSettingsState import io.element.android.libraries.matrix.api.room.MessageEventType 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.StateEventType import io.element.android.libraries.matrix.api.room.draft.ComposerDraft import io.element.android.libraries.matrix.api.room.location.AssetType @@ -40,21 +38,15 @@ import io.element.android.libraries.matrix.api.room.powerlevels.MatrixRoomPowerL import io.element.android.libraries.matrix.api.room.powerlevels.UserRoleChange import io.element.android.libraries.matrix.api.timeline.ReceiptType import io.element.android.libraries.matrix.api.timeline.Timeline -import io.element.android.libraries.matrix.api.user.MatrixUser import io.element.android.libraries.matrix.api.widget.MatrixWidgetDriver import io.element.android.libraries.matrix.api.widget.MatrixWidgetSettings -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_NAME import io.element.android.libraries.matrix.test.A_SESSION_ID import io.element.android.libraries.matrix.test.media.FakeMediaUploadHandler import io.element.android.libraries.matrix.test.notificationsettings.FakeNotificationSettingsService import io.element.android.libraries.matrix.test.timeline.FakeTimeline import io.element.android.tests.testutils.lambda.lambdaError import io.element.android.tests.testutils.simulateLongTask -import kotlinx.collections.immutable.ImmutableMap -import kotlinx.collections.immutable.persistentMapOf -import kotlinx.collections.immutable.toImmutableList import kotlinx.coroutines.delay import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.MutableSharedFlow @@ -527,62 +519,6 @@ class FakeMatrixRoom( } } -fun aRoomInfo( - id: RoomId = A_ROOM_ID, - name: String? = A_ROOM_NAME, - rawName: String? = name, - topic: String? = "A topic", - avatarUrl: String? = AN_AVATAR_URL, - isDirect: Boolean = false, - isPublic: Boolean = true, - isSpace: Boolean = false, - isTombstoned: Boolean = false, - isFavorite: Boolean = false, - canonicalAlias: RoomAlias? = null, - alternativeAliases: List = emptyList(), - currentUserMembership: CurrentUserMembership = CurrentUserMembership.JOINED, - inviter: RoomMember? = null, - activeMembersCount: Long = 1, - invitedMembersCount: Long = 0, - joinedMembersCount: Long = 1, - highlightCount: Long = 0, - notificationCount: Long = 0, - userDefinedNotificationMode: RoomNotificationMode? = null, - hasRoomCall: Boolean = false, - userPowerLevels: ImmutableMap = persistentMapOf(), - activeRoomCallParticipants: List = emptyList(), - heroes: List = emptyList(), - pinnedEventIds: List = emptyList(), - roomCreator: UserId? = null, -) = MatrixRoomInfo( - id = id, - name = name, - rawName = rawName, - topic = topic, - avatarUrl = avatarUrl, - isDirect = isDirect, - isPublic = isPublic, - isSpace = isSpace, - isTombstoned = isTombstoned, - isFavorite = isFavorite, - canonicalAlias = canonicalAlias, - alternativeAliases = alternativeAliases.toImmutableList(), - currentUserMembership = currentUserMembership, - inviter = inviter, - activeMembersCount = activeMembersCount, - invitedMembersCount = invitedMembersCount, - joinedMembersCount = joinedMembersCount, - highlightCount = highlightCount, - notificationCount = notificationCount, - userDefinedNotificationMode = userDefinedNotificationMode, - hasRoomCall = hasRoomCall, - userPowerLevels = userPowerLevels, - activeRoomCallParticipants = activeRoomCallParticipants.toImmutableList(), - heroes = heroes.toImmutableList(), - pinnedEventIds = pinnedEventIds.toImmutableList(), - creator = roomCreator, -) - fun defaultRoomPowerLevels() = MatrixRoomPowerLevels( ban = 50, invite = 0, diff --git a/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/room/RoomInfoFixture.kt b/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/room/RoomInfoFixture.kt new file mode 100644 index 0000000000..5aae1a3258 --- /dev/null +++ b/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/room/RoomInfoFixture.kt @@ -0,0 +1,90 @@ +/* + * Copyright 2024 New Vector Ltd. + * + * SPDX-License-Identifier: AGPL-3.0-only + * Please see LICENSE in the repository root for full details. + */ + +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.RoomAlias +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.CurrentUserMembership +import io.element.android.libraries.matrix.api.room.MatrixRoomInfo +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.user.MatrixUser +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_NAME +import io.element.android.libraries.matrix.test.A_ROOM_RAW_NAME +import io.element.android.libraries.matrix.test.A_ROOM_TOPIC +import kotlinx.collections.immutable.ImmutableMap +import kotlinx.collections.immutable.persistentMapOf +import kotlinx.collections.immutable.toImmutableList + +fun aRoomInfo( + id: RoomId = A_ROOM_ID, + name: String? = A_ROOM_NAME, + rawName: String? = A_ROOM_RAW_NAME, + topic: String? = A_ROOM_TOPIC, + avatarUrl: String? = AN_AVATAR_URL, + isDirect: Boolean = false, + isPublic: Boolean = true, + isSpace: Boolean = false, + isTombstoned: Boolean = false, + isFavorite: Boolean = false, + canonicalAlias: RoomAlias? = null, + alternativeAliases: List = emptyList(), + currentUserMembership: CurrentUserMembership = CurrentUserMembership.JOINED, + inviter: RoomMember? = null, + activeMembersCount: Long = 1, + invitedMembersCount: Long = 0, + joinedMembersCount: Long = 1, + highlightCount: Long = 0, + notificationCount: Long = 0, + userDefinedNotificationMode: RoomNotificationMode? = null, + hasRoomCall: Boolean = false, + userPowerLevels: ImmutableMap = persistentMapOf(), + activeRoomCallParticipants: List = emptyList(), + heroes: List = emptyList(), + pinnedEventIds: List = emptyList(), + roomCreator: UserId? = null, + isMarkedUnread: Boolean = false, + numUnreadMessages: Long = 0, + numUnreadNotifications: Long = 0, + numUnreadMentions: Long = 0, +) = MatrixRoomInfo( + id = id, + name = name, + rawName = rawName, + topic = topic, + avatarUrl = avatarUrl, + isDirect = isDirect, + isPublic = isPublic, + isSpace = isSpace, + isTombstoned = isTombstoned, + isFavorite = isFavorite, + canonicalAlias = canonicalAlias, + alternativeAliases = alternativeAliases.toImmutableList(), + currentUserMembership = currentUserMembership, + inviter = inviter, + activeMembersCount = activeMembersCount, + invitedMembersCount = invitedMembersCount, + joinedMembersCount = joinedMembersCount, + highlightCount = highlightCount, + notificationCount = notificationCount, + userDefinedNotificationMode = userDefinedNotificationMode, + hasRoomCall = hasRoomCall, + userPowerLevels = userPowerLevels, + activeRoomCallParticipants = activeRoomCallParticipants.toImmutableList(), + heroes = heroes.toImmutableList(), + pinnedEventIds = pinnedEventIds.toImmutableList(), + creator = roomCreator, + isMarkedUnread = isMarkedUnread, + numUnreadMessages = numUnreadMessages, + numUnreadNotifications = numUnreadNotifications, + numUnreadMentions = numUnreadMentions, +) 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 c0ac4b7bab..39e13cb619 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 @@ -12,6 +12,7 @@ import io.element.android.libraries.matrix.api.core.RoomAlias 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.CurrentUserMembership +import io.element.android.libraries.matrix.api.room.MatrixRoomInfo 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 @@ -21,69 +22,88 @@ import io.element.android.libraries.matrix.api.user.MatrixUser 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_ROOM_NAME +import io.element.android.libraries.matrix.test.A_ROOM_RAW_NAME +import io.element.android.libraries.matrix.test.A_ROOM_TOPIC import io.element.android.libraries.matrix.test.A_USER_ID import io.element.android.libraries.matrix.test.timeline.anEventTimelineItem +import kotlinx.collections.immutable.ImmutableMap +import kotlinx.collections.immutable.persistentMapOf +import kotlinx.collections.immutable.toPersistentList -fun aRoomSummaryFilled( - roomId: RoomId = A_ROOM_ID, - name: String = A_ROOM_NAME, - isDirect: Boolean = false, - avatarUrl: String? = null, +fun aRoomSummary( + info: MatrixRoomInfo = aRoomInfo(), lastMessage: RoomMessage? = aRoomMessage(), - numUnreadMentions: Int = 0, - numUnreadMessages: Int = 0, - notificationMode: RoomNotificationMode? = null, - currentUserMembership: CurrentUserMembership = CurrentUserMembership.JOINED, -) = aRoomSummary( - roomId = roomId, - name = name, - isDirect = isDirect, - avatarUrl = avatarUrl, +) = RoomSummary( + info = info, lastMessage = lastMessage, - numUnreadMentions = numUnreadMentions, - numUnreadMessages = numUnreadMessages, - notificationMode = notificationMode, - currentUserMembership = currentUserMembership, ) fun aRoomSummary( roomId: RoomId = A_ROOM_ID, name: String? = A_ROOM_NAME, - isDirect: Boolean = false, + rawName: String? = A_ROOM_RAW_NAME, + topic: String? = A_ROOM_TOPIC, avatarUrl: String? = null, - lastMessage: RoomMessage? = aRoomMessage(), - numUnreadMentions: Int = 0, - numUnreadMessages: Int = 0, - numUnreadNotifications: Int = 0, - isMarkedUnread: Boolean = false, - notificationMode: RoomNotificationMode? = null, - inviter: RoomMember? = null, + isDirect: Boolean = false, + isPublic: Boolean = true, + isSpace: Boolean = false, + isTombstoned: Boolean = false, + isFavorite: Boolean = false, canonicalAlias: RoomAlias? = null, alternativeAliases: List = emptyList(), - hasRoomCall: Boolean = false, - isDm: Boolean = false, - isFavorite: Boolean = false, currentUserMembership: CurrentUserMembership = CurrentUserMembership.JOINED, + inviter: RoomMember? = null, + activeMembersCount: Long = 1, + invitedMembersCount: Long = 0, + joinedMembersCount: Long = 1, + highlightCount: Long = 0, + notificationCount: Long = 0, + userDefinedNotificationMode: RoomNotificationMode? = null, + hasRoomCall: Boolean = false, + userPowerLevels: ImmutableMap = persistentMapOf(), + activeRoomCallParticipants: List = emptyList(), heroes: List = emptyList(), + pinnedEventIds: List = emptyList(), + roomCreator: UserId? = null, + isMarkedUnread: Boolean = false, + numUnreadMessages: Long = 0, + numUnreadNotifications: Long = 0, + numUnreadMentions: Long = 0, + lastMessage: RoomMessage? = aRoomMessage(), ) = RoomSummary( - roomId = roomId, - name = name, - isDirect = isDirect, - avatarUrl = avatarUrl, + info = MatrixRoomInfo( + id = roomId, + name = name, + rawName = rawName, + topic = topic, + avatarUrl = avatarUrl, + isDirect = isDirect, + isPublic = isPublic, + isSpace = isSpace, + isTombstoned = isTombstoned, + isFavorite = isFavorite, + canonicalAlias = canonicalAlias, + alternativeAliases = alternativeAliases.toPersistentList(), + currentUserMembership = currentUserMembership, + inviter = inviter, + activeMembersCount = activeMembersCount, + invitedMembersCount = invitedMembersCount, + joinedMembersCount = joinedMembersCount, + userPowerLevels = userPowerLevels, + highlightCount = highlightCount, + notificationCount = notificationCount, + userDefinedNotificationMode = userDefinedNotificationMode, + hasRoomCall = hasRoomCall, + activeRoomCallParticipants = activeRoomCallParticipants.toPersistentList(), + heroes = heroes.toPersistentList(), + pinnedEventIds = pinnedEventIds.toPersistentList(), + creator = roomCreator, + isMarkedUnread = isMarkedUnread, + numUnreadMessages = numUnreadMessages, + numUnreadNotifications = numUnreadNotifications, + numUnreadMentions = numUnreadMentions, + ), lastMessage = lastMessage, - numUnreadMentions = numUnreadMentions, - numUnreadMessages = numUnreadMessages, - numUnreadNotifications = numUnreadNotifications, - isMarkedUnread = isMarkedUnread, - userDefinedNotificationMode = notificationMode, - inviter = inviter, - canonicalAlias = canonicalAlias, - alternativeAliases = alternativeAliases, - hasRoomCall = hasRoomCall, - isDm = isDm, - isFavorite = isFavorite, - currentUserMembership = currentUserMembership, - heroes = heroes, ) fun aRoomMessage( diff --git a/libraries/matrixui/src/main/kotlin/io/element/android/libraries/matrix/ui/components/RoomSummaryDetailsProvider.kt b/libraries/matrixui/src/main/kotlin/io/element/android/libraries/matrix/ui/components/RoomSummaryDetailsProvider.kt deleted file mode 100644 index 6bc8af0591..0000000000 --- a/libraries/matrixui/src/main/kotlin/io/element/android/libraries/matrix/ui/components/RoomSummaryDetailsProvider.kt +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Copyright 2024 New Vector Ltd. - * - * SPDX-License-Identifier: AGPL-3.0-only - * Please see LICENSE in the repository root for full details. - */ - -package io.element.android.libraries.matrix.ui.components - -import androidx.compose.ui.tooling.preview.PreviewParameterProvider -import io.element.android.libraries.matrix.api.core.RoomAlias -import io.element.android.libraries.matrix.api.core.RoomId -import io.element.android.libraries.matrix.api.room.CurrentUserMembership -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 -import io.element.android.libraries.matrix.api.user.MatrixUser - -open class RoomSummaryDetailsProvider : PreviewParameterProvider { - override val values: Sequence - get() = sequenceOf( - aRoomSummaryDetails(), - aRoomSummaryDetails(name = null), - ) -} - -fun aRoomSummaryDetails( - roomId: RoomId = RoomId("!room:domain"), - name: String? = "roomName", - canonicalAlias: RoomAlias? = null, - alternativeAliases: List = emptyList(), - isDirect: Boolean = true, - avatarUrl: String? = null, - lastMessage: RoomMessage? = null, - inviter: RoomMember? = null, - notificationMode: RoomNotificationMode? = null, - hasRoomCall: Boolean = false, - isDm: Boolean = false, - numUnreadMentions: Int = 0, - numUnreadMessages: Int = 0, - numUnreadNotifications: Int = 0, - isMarkedUnread: Boolean = false, - isFavorite: Boolean = false, - currentUserMembership: CurrentUserMembership = CurrentUserMembership.JOINED, - heroes: List = emptyList(), -) = RoomSummary( - roomId = roomId, - name = name, - canonicalAlias = canonicalAlias, - alternativeAliases = alternativeAliases, - isDirect = isDirect, - avatarUrl = avatarUrl, - lastMessage = lastMessage, - inviter = inviter, - userDefinedNotificationMode = notificationMode, - hasRoomCall = hasRoomCall, - isDm = isDm, - numUnreadMentions = numUnreadMentions, - numUnreadMessages = numUnreadMessages, - numUnreadNotifications = numUnreadNotifications, - isMarkedUnread = isMarkedUnread, - isFavorite = isFavorite, - currentUserMembership = currentUserMembership, - heroes = heroes, -) diff --git a/libraries/matrixui/src/main/kotlin/io/element/android/libraries/matrix/ui/components/SelectRoomInfoProvider.kt b/libraries/matrixui/src/main/kotlin/io/element/android/libraries/matrix/ui/components/SelectRoomInfoProvider.kt new file mode 100644 index 0000000000..d61dc09b03 --- /dev/null +++ b/libraries/matrixui/src/main/kotlin/io/element/android/libraries/matrix/ui/components/SelectRoomInfoProvider.kt @@ -0,0 +1,39 @@ +/* + * Copyright 2024 New Vector Ltd. + * + * SPDX-License-Identifier: AGPL-3.0-only + * Please see LICENSE in the repository root for full details. + */ + +package io.element.android.libraries.matrix.ui.components + +import androidx.compose.ui.tooling.preview.PreviewParameterProvider +import io.element.android.libraries.matrix.api.core.RoomAlias +import io.element.android.libraries.matrix.api.core.RoomId +import io.element.android.libraries.matrix.api.user.MatrixUser +import io.element.android.libraries.matrix.ui.model.SelectRoomInfo +import kotlinx.collections.immutable.ImmutableList +import kotlinx.collections.immutable.persistentListOf + +class SelectRoomInfoProvider : PreviewParameterProvider { + override val values: Sequence + get() = sequenceOf( + aSelectRoomInfo(roomId = RoomId("!room1:domain")), + aSelectRoomInfo(roomId = RoomId("!room2:domain"), name = "Room with a name"), + aSelectRoomInfo(roomId = RoomId("!room3:domain"), name = "Room with a name and alias", canonicalAlias = RoomAlias("#alias:domain")), + ) +} + +fun aSelectRoomInfo( + roomId: RoomId, + name: String? = null, + canonicalAlias: RoomAlias? = null, + avatarUrl: String? = null, + heroes: ImmutableList = persistentListOf(), +) = SelectRoomInfo( + roomId = roomId, + name = name, + canonicalAlias = canonicalAlias, + avatarUrl = avatarUrl, + heroes = heroes, +) 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 eecefd2a45..fb9fab7c97 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 @@ -34,15 +34,15 @@ import io.element.android.libraries.designsystem.preview.PreviewsDayNight 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.roomlist.RoomSummary +import io.element.android.libraries.matrix.ui.model.SelectRoomInfo import io.element.android.libraries.matrix.ui.model.getAvatarData import io.element.android.libraries.ui.strings.CommonStrings import kotlinx.collections.immutable.toImmutableList @Composable fun SelectedRoom( - roomSummary: RoomSummary, - onRemoveRoom: (RoomSummary) -> Unit, + roomInfo: SelectRoomInfo, + onRemoveRoom: (SelectRoomInfo) -> Unit, modifier: Modifier = Modifier, ) { Box( @@ -53,14 +53,12 @@ fun SelectedRoom( horizontalAlignment = Alignment.CenterHorizontally, ) { CompositeAvatar( - avatarData = roomSummary.getAvatarData(size = AvatarSize.SelectedRoom), - heroes = roomSummary.heroes.map { user -> - user.getAvatarData(size = AvatarSize.SelectedRoom) - }.toImmutableList() + avatarData = roomInfo.getAvatarData(AvatarSize.SelectedRoom), + heroes = roomInfo.heroes.map { it.getAvatarData(AvatarSize.SelectedRoom) }.toImmutableList(), ) Text( // If name is null, we do not have space to render "No room name", so just use `#` here. - text = roomSummary.name ?: "#", + text = roomInfo.name ?: "#", overflow = TextOverflow.Ellipsis, maxLines = 1, style = MaterialTheme.typography.bodyLarge, @@ -69,14 +67,14 @@ fun SelectedRoom( Surface( color = MaterialTheme.colorScheme.primary, modifier = Modifier - .clip(CircleShape) - .size(20.dp) - .align(Alignment.TopEnd) - .clickable( - indication = ripple(), - interactionSource = remember { MutableInteractionSource() }, - onClick = { onRemoveRoom(roomSummary) } - ), + .clip(CircleShape) + .size(20.dp) + .align(Alignment.TopEnd) + .clickable( + indication = ripple(), + interactionSource = remember { MutableInteractionSource() }, + onClick = { onRemoveRoom(roomInfo) } + ), ) { Icon( imageVector = CompoundIcons.Close(), @@ -91,10 +89,10 @@ fun SelectedRoom( @PreviewsDayNight @Composable internal fun SelectedRoomPreview( - @PreviewParameter(RoomSummaryDetailsProvider::class) roomSummary: RoomSummary + @PreviewParameter(SelectRoomInfoProvider::class) roomInfo: SelectRoomInfo ) = ElementPreview { SelectedRoom( - roomSummary = roomSummary, + roomInfo = roomInfo, onRemoveRoom = {}, ) } diff --git a/libraries/matrixui/src/main/kotlin/io/element/android/libraries/matrix/ui/media/AvatarDataFetcherFactory.kt b/libraries/matrixui/src/main/kotlin/io/element/android/libraries/matrix/ui/media/AvatarDataFetcherFactory.kt index 93e41525db..1092ee9ebc 100644 --- a/libraries/matrixui/src/main/kotlin/io/element/android/libraries/matrix/ui/media/AvatarDataFetcherFactory.kt +++ b/libraries/matrixui/src/main/kotlin/io/element/android/libraries/matrix/ui/media/AvatarDataFetcherFactory.kt @@ -7,7 +7,6 @@ package io.element.android.libraries.matrix.ui.media -import android.content.Context import coil.ImageLoader import coil.fetch.Fetcher import coil.request.Options @@ -15,7 +14,6 @@ import io.element.android.libraries.designsystem.components.avatar.AvatarData import io.element.android.libraries.matrix.api.MatrixClient internal class AvatarDataFetcherFactory( - private val context: Context, private val client: MatrixClient ) : Fetcher.Factory { override fun create( @@ -24,7 +22,6 @@ internal class AvatarDataFetcherFactory( imageLoader: ImageLoader ): Fetcher { return CoilMediaFetcher( - scalingFunction = { context.resources.displayMetrics.density * it }, mediaLoader = client.mediaLoader, mediaData = data.toMediaRequestData(), options = options diff --git a/libraries/matrixui/src/main/kotlin/io/element/android/libraries/matrix/ui/media/AvatatarDataExt.kt b/libraries/matrixui/src/main/kotlin/io/element/android/libraries/matrix/ui/media/AvatatarDataExt.kt index b49d482870..a648bcad3e 100644 --- a/libraries/matrixui/src/main/kotlin/io/element/android/libraries/matrix/ui/media/AvatatarDataExt.kt +++ b/libraries/matrixui/src/main/kotlin/io/element/android/libraries/matrix/ui/media/AvatatarDataExt.kt @@ -9,11 +9,25 @@ package io.element.android.libraries.matrix.ui.media import io.element.android.libraries.designsystem.components.avatar.AvatarData import io.element.android.libraries.matrix.api.media.MediaSource -import kotlin.math.roundToLong + +/** + * The size in pixel of the thumbnail to generate for the avatar. + * This is not the size of the avatar displayed in the UI but the size to get from the servers. + * Servers SHOULD produce thumbnails with the following dimensions and methods: + * + * 32x32, crop + * 96x96, crop + * 320x240, scale + * 640x480, scale + * 800x600, scale + * + * Let's always use the same size so coil caching works properly. + */ +const val AVATAR_THUMBNAIL_SIZE_IN_PIXEL = 240L internal fun AvatarData.toMediaRequestData(): MediaRequestData { return MediaRequestData( source = url?.let { MediaSource(it) }, - kind = MediaRequestData.Kind.Thumbnail(size.dp.value.roundToLong()) + kind = MediaRequestData.Kind.Thumbnail(AVATAR_THUMBNAIL_SIZE_IN_PIXEL) ) } diff --git a/libraries/matrixui/src/main/kotlin/io/element/android/libraries/matrix/ui/media/CoilMediaFetcher.kt b/libraries/matrixui/src/main/kotlin/io/element/android/libraries/matrix/ui/media/CoilMediaFetcher.kt index f6a3e5a3d2..3021845a80 100644 --- a/libraries/matrixui/src/main/kotlin/io/element/android/libraries/matrix/ui/media/CoilMediaFetcher.kt +++ b/libraries/matrixui/src/main/kotlin/io/element/android/libraries/matrix/ui/media/CoilMediaFetcher.kt @@ -20,10 +20,8 @@ import okio.Buffer import okio.Path.Companion.toOkioPath import timber.log.Timber import java.nio.ByteBuffer -import kotlin.math.roundToLong internal class CoilMediaFetcher( - private val scalingFunction: (Float) -> Float, private val mediaLoader: MatrixMediaLoader, private val mediaData: MediaRequestData, private val options: Options @@ -74,8 +72,8 @@ internal class CoilMediaFetcher( private suspend fun fetchThumbnail(mediaSource: MediaSource, kind: MediaRequestData.Kind.Thumbnail, options: Options): FetchResult? { return mediaLoader.loadMediaThumbnail( source = mediaSource, - width = scalingFunction(kind.width.toFloat()).roundToLong(), - height = scalingFunction(kind.height.toFloat()).roundToLong(), + width = kind.width, + height = kind.height, ).map { byteArray -> byteArray.asSourceResult(options) }.onFailure { diff --git a/libraries/matrixui/src/main/kotlin/io/element/android/libraries/matrix/ui/media/ImageLoaderFactories.kt b/libraries/matrixui/src/main/kotlin/io/element/android/libraries/matrix/ui/media/ImageLoaderFactories.kt index 124daf00c1..6414cf3988 100644 --- a/libraries/matrixui/src/main/kotlin/io/element/android/libraries/matrix/ui/media/ImageLoaderFactories.kt +++ b/libraries/matrixui/src/main/kotlin/io/element/android/libraries/matrix/ui/media/ImageLoaderFactories.kt @@ -43,8 +43,8 @@ class DefaultLoggedInImageLoaderFactory @Inject constructor( } add(AvatarDataKeyer()) add(MediaRequestDataKeyer()) - add(AvatarDataFetcherFactory(context, matrixClient)) - add(MediaRequestDataFetcherFactory(context, matrixClient)) + add(AvatarDataFetcherFactory(matrixClient)) + add(MediaRequestDataFetcherFactory(matrixClient)) } .build() } diff --git a/libraries/matrixui/src/main/kotlin/io/element/android/libraries/matrix/ui/media/MediaRequestDataFetcherFactory.kt b/libraries/matrixui/src/main/kotlin/io/element/android/libraries/matrix/ui/media/MediaRequestDataFetcherFactory.kt index 63e48cfb13..4de4705260 100644 --- a/libraries/matrixui/src/main/kotlin/io/element/android/libraries/matrix/ui/media/MediaRequestDataFetcherFactory.kt +++ b/libraries/matrixui/src/main/kotlin/io/element/android/libraries/matrix/ui/media/MediaRequestDataFetcherFactory.kt @@ -7,14 +7,12 @@ package io.element.android.libraries.matrix.ui.media -import android.content.Context import coil.ImageLoader import coil.fetch.Fetcher import coil.request.Options import io.element.android.libraries.matrix.api.MatrixClient internal class MediaRequestDataFetcherFactory( - private val context: Context, private val client: MatrixClient ) : Fetcher.Factory { override fun create( @@ -23,7 +21,6 @@ internal class MediaRequestDataFetcherFactory( imageLoader: ImageLoader ): Fetcher { return CoilMediaFetcher( - scalingFunction = { context.resources.displayMetrics.density * it }, mediaLoader = client.mediaLoader, mediaData = data, options = options diff --git a/libraries/matrixui/src/main/kotlin/io/element/android/libraries/matrix/ui/model/RoomSummaryExtension.kt b/libraries/matrixui/src/main/kotlin/io/element/android/libraries/matrix/ui/model/RoomInfoExtension.kt similarity index 73% rename from libraries/matrixui/src/main/kotlin/io/element/android/libraries/matrix/ui/model/RoomSummaryExtension.kt rename to libraries/matrixui/src/main/kotlin/io/element/android/libraries/matrix/ui/model/RoomInfoExtension.kt index a6954af232..e876a1da05 100644 --- a/libraries/matrixui/src/main/kotlin/io/element/android/libraries/matrix/ui/model/RoomSummaryExtension.kt +++ b/libraries/matrixui/src/main/kotlin/io/element/android/libraries/matrix/ui/model/RoomInfoExtension.kt @@ -9,10 +9,10 @@ package io.element.android.libraries.matrix.ui.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.roomlist.RoomSummary +import io.element.android.libraries.matrix.api.room.MatrixRoomInfo -fun RoomSummary.getAvatarData(size: AvatarSize) = AvatarData( - id = roomId.value, +fun MatrixRoomInfo.getAvatarData(size: AvatarSize) = AvatarData( + id = id.value, name = name, url = avatarUrl, size = size, diff --git a/libraries/matrixui/src/main/kotlin/io/element/android/libraries/matrix/ui/model/SelectRoomInfo.kt b/libraries/matrixui/src/main/kotlin/io/element/android/libraries/matrix/ui/model/SelectRoomInfo.kt new file mode 100644 index 0000000000..503e7b8471 --- /dev/null +++ b/libraries/matrixui/src/main/kotlin/io/element/android/libraries/matrix/ui/model/SelectRoomInfo.kt @@ -0,0 +1,39 @@ +/* + * Copyright 2024 New Vector Ltd. + * + * SPDX-License-Identifier: AGPL-3.0-only + * Please see LICENSE in the repository root for full details. + */ + +package io.element.android.libraries.matrix.ui.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.RoomAlias +import io.element.android.libraries.matrix.api.core.RoomId +import io.element.android.libraries.matrix.api.roomlist.RoomSummary +import io.element.android.libraries.matrix.api.user.MatrixUser +import kotlinx.collections.immutable.ImmutableList + +data class SelectRoomInfo( + val roomId: RoomId, + val name: String?, + val canonicalAlias: RoomAlias?, + val avatarUrl: String?, + val heroes: ImmutableList, +) { + fun getAvatarData(size: AvatarSize) = AvatarData( + id = roomId.value, + name = name, + url = avatarUrl, + size = size, + ) +} + +fun RoomSummary.toSelectRoomInfo() = SelectRoomInfo( + roomId = roomId, + name = info.name, + avatarUrl = info.avatarUrl, + heroes = info.heroes, + canonicalAlias = info.canonicalAlias, +) diff --git a/libraries/mediapickers/api/build.gradle.kts b/libraries/mediapickers/api/build.gradle.kts index 24a556d10f..edb9e9263b 100644 --- a/libraries/mediapickers/api/build.gradle.kts +++ b/libraries/mediapickers/api/build.gradle.kts @@ -1,3 +1,5 @@ +import extension.setupAnvil + /* * Copyright 2023, 2024 New Vector Ltd. * @@ -7,9 +9,10 @@ plugins { id("io.element.android-compose-library") - alias(libs.plugins.anvil) } +setupAnvil() + android { namespace = "io.element.android.libraries.mediapickers.api" diff --git a/libraries/mediapickers/test/build.gradle.kts b/libraries/mediapickers/test/build.gradle.kts index 6316465538..689fc0d8eb 100644 --- a/libraries/mediapickers/test/build.gradle.kts +++ b/libraries/mediapickers/test/build.gradle.kts @@ -1,3 +1,5 @@ +import extension.setupAnvil + /* * Copyright 2023, 2024 New Vector Ltd. * @@ -7,9 +9,10 @@ plugins { id("io.element.android-compose-library") - alias(libs.plugins.anvil) } +setupAnvil() + android { namespace = "io.element.android.libraries.mediapickers.test" diff --git a/libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/notifications/DefaultNotificationBitmapLoader.kt b/libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/notifications/DefaultNotificationBitmapLoader.kt index 6039f7d1fb..70f97890e2 100644 --- a/libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/notifications/DefaultNotificationBitmapLoader.kt +++ b/libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/notifications/DefaultNotificationBitmapLoader.kt @@ -19,6 +19,7 @@ import com.squareup.anvil.annotations.ContributesBinding import io.element.android.libraries.di.AppScope import io.element.android.libraries.di.ApplicationContext import io.element.android.libraries.matrix.api.media.MediaSource +import io.element.android.libraries.matrix.ui.media.AVATAR_THUMBNAIL_SIZE_IN_PIXEL import io.element.android.libraries.matrix.ui.media.MediaRequestData import io.element.android.libraries.push.api.notifications.NotificationBitmapLoader import io.element.android.services.toolbox.api.sdk.BuildVersionSdkIntProvider @@ -45,7 +46,7 @@ class DefaultNotificationBitmapLoader @Inject constructor( private suspend fun loadRoomBitmap(path: String, imageLoader: ImageLoader): Bitmap? { return try { val imageRequest = ImageRequest.Builder(context) - .data(MediaRequestData(MediaSource(path), MediaRequestData.Kind.Thumbnail(1024))) + .data(MediaRequestData(MediaSource(path), MediaRequestData.Kind.Thumbnail(AVATAR_THUMBNAIL_SIZE_IN_PIXEL))) .transformations(CircleCropTransformation()) .build() val result = imageLoader.execute(imageRequest) @@ -73,7 +74,7 @@ class DefaultNotificationBitmapLoader @Inject constructor( private suspend fun loadUserIcon(path: String, imageLoader: ImageLoader): IconCompat? { return try { val imageRequest = ImageRequest.Builder(context) - .data(MediaRequestData(MediaSource(path), MediaRequestData.Kind.Thumbnail(1024))) + .data(MediaRequestData(MediaSource(path), MediaRequestData.Kind.Thumbnail(AVATAR_THUMBNAIL_SIZE_IN_PIXEL))) .transformations(CircleCropTransformation()) .build() val result = imageLoader.execute(imageRequest) diff --git a/libraries/push/impl/src/test/kotlin/io/element/android/libraries/push/impl/notifications/DefaultRoomGroupMessageCreatorTest.kt b/libraries/push/impl/src/test/kotlin/io/element/android/libraries/push/impl/notifications/DefaultRoomGroupMessageCreatorTest.kt index dbb60296b1..d0255aa452 100644 --- a/libraries/push/impl/src/test/kotlin/io/element/android/libraries/push/impl/notifications/DefaultRoomGroupMessageCreatorTest.kt +++ b/libraries/push/impl/src/test/kotlin/io/element/android/libraries/push/impl/notifications/DefaultRoomGroupMessageCreatorTest.kt @@ -15,6 +15,7 @@ import io.element.android.libraries.matrix.api.media.MediaSource import io.element.android.libraries.matrix.test.A_ROOM_ID import io.element.android.libraries.matrix.test.A_TIMESTAMP import io.element.android.libraries.matrix.ui.components.aMatrixUser +import io.element.android.libraries.matrix.ui.media.AVATAR_THUMBNAIL_SIZE_IN_PIXEL import io.element.android.libraries.matrix.ui.media.MediaRequestData import io.element.android.libraries.push.impl.notifications.factories.createNotificationCreator import io.element.android.libraries.push.impl.notifications.fixtures.aNotifiableMessageEvent @@ -84,7 +85,7 @@ class DefaultRoomGroupMessageCreatorTest { expectedCoilRequests = listOf( MediaRequestData( source = MediaSource(url = A_ROOM_AVATAR), - kind = MediaRequestData.Kind.Thumbnail(1024) + kind = MediaRequestData.Kind.Thumbnail(AVATAR_THUMBNAIL_SIZE_IN_PIXEL) ) ) ) @@ -98,15 +99,15 @@ class DefaultRoomGroupMessageCreatorTest { expectedCoilRequests = listOf( MediaRequestData( source = MediaSource(url = A_USER_AVATAR_1), - kind = MediaRequestData.Kind.Thumbnail(1024) + kind = MediaRequestData.Kind.Thumbnail(AVATAR_THUMBNAIL_SIZE_IN_PIXEL) ), MediaRequestData( source = MediaSource(url = A_USER_AVATAR_2), - kind = MediaRequestData.Kind.Thumbnail(1024) + kind = MediaRequestData.Kind.Thumbnail(AVATAR_THUMBNAIL_SIZE_IN_PIXEL) ), MediaRequestData( source = MediaSource(url = A_ROOM_AVATAR), - kind = MediaRequestData.Kind.Thumbnail(1024) + kind = MediaRequestData.Kind.Thumbnail(AVATAR_THUMBNAIL_SIZE_IN_PIXEL) ), ) ) diff --git a/libraries/pushproviders/unifiedpush/src/test/kotlin/io/element/android/libraries/pushproviders/unifiedpush/FakeUnifiedPushNewGatewayHandler.kt b/libraries/pushproviders/unifiedpush/src/test/kotlin/io/element/android/libraries/pushproviders/unifiedpush/FakeUnifiedPushNewGatewayHandler.kt index b5083e9da5..838addbca3 100644 --- a/libraries/pushproviders/unifiedpush/src/test/kotlin/io/element/android/libraries/pushproviders/unifiedpush/FakeUnifiedPushNewGatewayHandler.kt +++ b/libraries/pushproviders/unifiedpush/src/test/kotlin/io/element/android/libraries/pushproviders/unifiedpush/FakeUnifiedPushNewGatewayHandler.kt @@ -10,7 +10,7 @@ package io.element.android.libraries.pushproviders.unifiedpush import io.element.android.tests.testutils.lambda.lambdaError class FakeUnifiedPushNewGatewayHandler( - private val handleResult: suspend (String, String, String) -> Result = { _, _, _ -> lambdaError() }, + private val handleResult: (String, String, String) -> Result = { _, _, _ -> lambdaError() }, ) : UnifiedPushNewGatewayHandler { override suspend fun handle(endpoint: String, pushGateway: String, clientSecret: String): Result { return handleResult(endpoint, pushGateway, clientSecret) diff --git a/libraries/roomselect/impl/src/main/kotlin/io/element/android/libraries/roomselect/impl/RoomSelectEvents.kt b/libraries/roomselect/impl/src/main/kotlin/io/element/android/libraries/roomselect/impl/RoomSelectEvents.kt index 35954d4851..8661e2aa75 100644 --- a/libraries/roomselect/impl/src/main/kotlin/io/element/android/libraries/roomselect/impl/RoomSelectEvents.kt +++ b/libraries/roomselect/impl/src/main/kotlin/io/element/android/libraries/roomselect/impl/RoomSelectEvents.kt @@ -7,10 +7,10 @@ package io.element.android.libraries.roomselect.impl -import io.element.android.libraries.matrix.api.roomlist.RoomSummary +import io.element.android.libraries.matrix.ui.model.SelectRoomInfo sealed interface RoomSelectEvents { - data class SetSelectedRoom(val room: RoomSummary) : RoomSelectEvents + data class SetSelectedRoom(val room: SelectRoomInfo) : RoomSelectEvents // TODO remove to restore multi-selection data object RemoveSelectedRoom : RoomSelectEvents diff --git a/libraries/roomselect/impl/src/main/kotlin/io/element/android/libraries/roomselect/impl/RoomSelectPresenter.kt b/libraries/roomselect/impl/src/main/kotlin/io/element/android/libraries/roomselect/impl/RoomSelectPresenter.kt index 74911c3f03..47c59142ca 100644 --- a/libraries/roomselect/impl/src/main/kotlin/io/element/android/libraries/roomselect/impl/RoomSelectPresenter.kt +++ b/libraries/roomselect/impl/src/main/kotlin/io/element/android/libraries/roomselect/impl/RoomSelectPresenter.kt @@ -9,6 +9,7 @@ package io.element.android.libraries.roomselect.impl import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect +import androidx.compose.runtime.State import androidx.compose.runtime.collectAsState import androidx.compose.runtime.derivedStateOf import androidx.compose.runtime.getValue @@ -20,8 +21,9 @@ import dagger.assisted.AssistedFactory import dagger.assisted.AssistedInject import io.element.android.libraries.architecture.Presenter import io.element.android.libraries.designsystem.theme.components.SearchBarResultState -import io.element.android.libraries.matrix.api.roomlist.RoomSummary +import io.element.android.libraries.matrix.ui.model.SelectRoomInfo import io.element.android.libraries.roomselect.api.RoomSelectMode +import kotlinx.collections.immutable.ImmutableList import kotlinx.collections.immutable.persistentListOf import kotlinx.collections.immutable.toImmutableList @@ -36,7 +38,7 @@ class RoomSelectPresenter @AssistedInject constructor( @Composable override fun present(): RoomSelectState { - var selectedRooms by remember { mutableStateOf(persistentListOf()) } + var selectedRooms by remember { mutableStateOf(persistentListOf()) } var searchQuery by remember { mutableStateOf("") } var isSearchActive by remember { mutableStateOf(false) } @@ -48,9 +50,9 @@ class RoomSelectPresenter @AssistedInject constructor( dataSource.setSearchQuery(searchQuery) } - val roomSummaryDetailsList by dataSource.roomSummaries.collectAsState(initial = persistentListOf()) + val roomSummaryDetailsList by dataSource.roomInfoList.collectAsState(initial = persistentListOf()) - val searchResults by remember { + val searchResults by remember>>> { derivedStateOf { when { roomSummaryDetailsList.isNotEmpty() -> SearchBarResultState.Results(roomSummaryDetailsList.toImmutableList()) diff --git a/libraries/roomselect/impl/src/main/kotlin/io/element/android/libraries/roomselect/impl/RoomSelectSearchDataSource.kt b/libraries/roomselect/impl/src/main/kotlin/io/element/android/libraries/roomselect/impl/RoomSelectSearchDataSource.kt index 4500456d54..a684985893 100644 --- a/libraries/roomselect/impl/src/main/kotlin/io/element/android/libraries/roomselect/impl/RoomSelectSearchDataSource.kt +++ b/libraries/roomselect/impl/src/main/kotlin/io/element/android/libraries/roomselect/impl/RoomSelectSearchDataSource.kt @@ -12,8 +12,9 @@ import io.element.android.libraries.matrix.api.room.CurrentUserMembership import io.element.android.libraries.matrix.api.roomlist.RoomList import io.element.android.libraries.matrix.api.roomlist.RoomListFilter import io.element.android.libraries.matrix.api.roomlist.RoomListService -import io.element.android.libraries.matrix.api.roomlist.RoomSummary import io.element.android.libraries.matrix.api.roomlist.loadAllIncrementally +import io.element.android.libraries.matrix.ui.model.SelectRoomInfo +import io.element.android.libraries.matrix.ui.model.toSelectRoomInfo import kotlinx.collections.immutable.PersistentList import kotlinx.collections.immutable.toPersistentList import kotlinx.coroutines.coroutineScope @@ -38,11 +39,12 @@ class RoomSelectSearchDataSource @Inject constructor( source = RoomList.Source.All, ) - val roomSummaries: Flow> = roomList.filteredSummaries + val roomInfoList: Flow> = roomList.filteredSummaries .map { roomSummaries -> roomSummaries - .filter { it.currentUserMembership == CurrentUserMembership.JOINED } + .filter { it.info.currentUserMembership == CurrentUserMembership.JOINED } .distinctBy { it.roomId } // This should be removed once we're sure no duplicate Rooms can be received + .map { roomSummary -> roomSummary.toSelectRoomInfo() } .toPersistentList() } .flowOn(coroutineDispatchers.computation) diff --git a/libraries/roomselect/impl/src/main/kotlin/io/element/android/libraries/roomselect/impl/RoomSelectState.kt b/libraries/roomselect/impl/src/main/kotlin/io/element/android/libraries/roomselect/impl/RoomSelectState.kt index 5037a1ca19..9c2d4d9893 100644 --- a/libraries/roomselect/impl/src/main/kotlin/io/element/android/libraries/roomselect/impl/RoomSelectState.kt +++ b/libraries/roomselect/impl/src/main/kotlin/io/element/android/libraries/roomselect/impl/RoomSelectState.kt @@ -8,15 +8,15 @@ package io.element.android.libraries.roomselect.impl import io.element.android.libraries.designsystem.theme.components.SearchBarResultState -import io.element.android.libraries.matrix.api.roomlist.RoomSummary +import io.element.android.libraries.matrix.ui.model.SelectRoomInfo import io.element.android.libraries.roomselect.api.RoomSelectMode import kotlinx.collections.immutable.ImmutableList data class RoomSelectState( val mode: RoomSelectMode, - val resultState: SearchBarResultState>, + val resultState: SearchBarResultState>, val query: String, val isSearchActive: Boolean, - val selectedRooms: ImmutableList, + val selectedRooms: ImmutableList, val eventSink: (RoomSelectEvents) -> Unit ) 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 e9a1bfc158..70d69ac814 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 @@ -11,8 +11,8 @@ import androidx.compose.ui.tooling.preview.PreviewParameterProvider import io.element.android.libraries.designsystem.theme.components.SearchBarResultState import io.element.android.libraries.matrix.api.core.RoomAlias import io.element.android.libraries.matrix.api.core.RoomId -import io.element.android.libraries.matrix.api.roomlist.RoomSummary -import io.element.android.libraries.matrix.ui.components.aRoomSummaryDetails +import io.element.android.libraries.matrix.ui.components.aSelectRoomInfo +import io.element.android.libraries.matrix.ui.model.SelectRoomInfo import io.element.android.libraries.roomselect.api.RoomSelectMode import kotlinx.collections.immutable.ImmutableList import kotlinx.collections.immutable.persistentListOf @@ -32,7 +32,7 @@ open class RoomSelectStateProvider : PreviewParameterProvider { resultState = SearchBarResultState.Results(aRoomSelectRoomList()), query = "Test", isSearchActive = true, - selectedRooms = persistentListOf(aRoomSummaryDetails(roomId = RoomId("!room2:domain"))) + selectedRooms = aRoomSelectRoomList().subList(0, 1), ), aRoomSelectState( mode = RoomSelectMode.Share, @@ -43,10 +43,10 @@ open class RoomSelectStateProvider : PreviewParameterProvider { private fun aRoomSelectState( mode: RoomSelectMode = RoomSelectMode.Forward, - resultState: SearchBarResultState> = SearchBarResultState.Initial(), + resultState: SearchBarResultState> = SearchBarResultState.Initial(), query: String = "", isSearchActive: Boolean = false, - selectedRooms: ImmutableList = persistentListOf(), + selectedRooms: ImmutableList = persistentListOf(), ) = RoomSelectState( mode = mode, resultState = resultState, @@ -57,14 +57,16 @@ private fun aRoomSelectState( ) private fun aRoomSelectRoomList() = persistentListOf( - aRoomSummaryDetails(), - aRoomSummaryDetails( + aSelectRoomInfo( + roomId = RoomId("!room1:domain"), + name = "Room with name", + ), + aSelectRoomInfo( roomId = RoomId("!room2:domain"), name = "Room with alias", canonicalAlias = RoomAlias("#alias:example.org"), ), - aRoomSummaryDetails( + aSelectRoomInfo( roomId = RoomId("!room3:domain"), - name = null, ), ) 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 643cb00b85..3d1d22c505 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 @@ -47,8 +47,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.core.RoomId -import io.element.android.libraries.matrix.api.roomlist.RoomSummary import io.element.android.libraries.matrix.ui.components.SelectedRoom +import io.element.android.libraries.matrix.ui.model.SelectRoomInfo import io.element.android.libraries.matrix.ui.model.getAvatarData import io.element.android.libraries.roomselect.api.RoomSelectMode import io.element.android.libraries.ui.strings.CommonStrings @@ -65,13 +65,13 @@ fun RoomSelectView( modifier: Modifier = Modifier, ) { @Suppress("UNUSED_PARAMETER") - fun onRoomRemoved(roomSummary: RoomSummary) { + fun onRoomRemoved(roomInfo: SelectRoomInfo) { // TODO toggle selection when multi-selection is enabled state.eventSink(RoomSelectEvents.RemoveSelectedRoom) } @Composable - fun SelectedRoomsHelper(isForwarding: Boolean, selectedRooms: ImmutableList) { + fun SelectedRoomsHelper(isForwarding: Boolean, selectedRooms: ImmutableList) { if (isForwarding) return SelectedRooms( selectedRooms = selectedRooms, @@ -185,8 +185,8 @@ fun RoomSelectView( @Composable private fun SelectedRooms( - selectedRooms: ImmutableList, - onRemoveRoom: (RoomSummary) -> Unit, + selectedRooms: ImmutableList, + onRemoveRoom: (SelectRoomInfo) -> Unit, modifier: Modifier = Modifier, ) { LazyRow( @@ -194,29 +194,29 @@ private fun SelectedRooms( contentPadding = PaddingValues(horizontal = 16.dp), horizontalArrangement = Arrangement.spacedBy(32.dp) ) { - items(selectedRooms, key = { it.roomId.value }) { roomSummary -> - SelectedRoom(roomSummary = roomSummary, onRemoveRoom = onRemoveRoom) + items(selectedRooms, key = { it.roomId.value }) { selectRoomInfo -> + SelectedRoom(roomInfo = selectRoomInfo, onRemoveRoom = onRemoveRoom) } } } @Composable private fun RoomSummaryView( - summary: RoomSummary, + roomInfo: SelectRoomInfo, isSelected: Boolean, - onSelection: (RoomSummary) -> Unit, + onSelection: (SelectRoomInfo) -> Unit, ) { Row( modifier = Modifier - .clickable { onSelection(summary) } + .clickable { onSelection(roomInfo) } .fillMaxWidth() .padding(start = 16.dp, end = 4.dp) .heightIn(56.dp), verticalAlignment = Alignment.CenterVertically ) { CompositeAvatar( - avatarData = summary.getAvatarData(size = AvatarSize.RoomSelectRoomListItem), - heroes = summary.heroes.map { user -> + avatarData = roomInfo.getAvatarData(size = AvatarSize.RoomSelectRoomListItem), + heroes = roomInfo.heroes.map { user -> user.getAvatarData(size = AvatarSize.RoomSelectRoomListItem) }.toPersistentList() ) @@ -228,14 +228,14 @@ private fun RoomSummaryView( // Name Text( style = ElementTheme.typography.fontBodyLgRegular, - text = summary.name ?: stringResource(id = CommonStrings.common_no_room_name), - fontStyle = FontStyle.Italic.takeIf { summary.name == null }, + text = roomInfo.name ?: stringResource(id = CommonStrings.common_no_room_name), + fontStyle = FontStyle.Italic.takeIf { roomInfo.name == null }, color = ElementTheme.colors.textPrimary, maxLines = 1, overflow = TextOverflow.Ellipsis ) // Alias - summary.canonicalAlias?.let { alias -> + roomInfo.canonicalAlias?.let { alias -> Text( text = alias.value, color = ElementTheme.colors.textSecondary, @@ -245,7 +245,7 @@ private fun RoomSummaryView( ) } } - RadioButton(selected = isSelected, onClick = { onSelection(summary) }) + RadioButton(selected = isSelected, onClick = { onSelection(roomInfo) }) } } diff --git a/libraries/roomselect/impl/src/test/kotlin/io/element/android/libraries/roomselect/impl/RoomSelectPresenterTest.kt b/libraries/roomselect/impl/src/test/kotlin/io/element/android/libraries/roomselect/impl/RoomSelectPresenterTest.kt index ff94e32a5f..17936f8e00 100644 --- a/libraries/roomselect/impl/src/test/kotlin/io/element/android/libraries/roomselect/impl/RoomSelectPresenterTest.kt +++ b/libraries/roomselect/impl/src/test/kotlin/io/element/android/libraries/roomselect/impl/RoomSelectPresenterTest.kt @@ -16,6 +16,7 @@ import io.element.android.libraries.matrix.api.roomlist.RoomListFilter import io.element.android.libraries.matrix.api.roomlist.RoomListService import io.element.android.libraries.matrix.test.room.aRoomSummary import io.element.android.libraries.matrix.test.roomlist.FakeRoomListService +import io.element.android.libraries.matrix.ui.model.toSelectRoomInfo import io.element.android.libraries.roomselect.api.RoomSelectMode import io.element.android.tests.testutils.WarmUpRule import io.element.android.tests.testutils.testCoroutineDispatchers @@ -58,8 +59,9 @@ class RoomSelectPresenterTest { @Test fun `present - update query`() = runTest { + val roomSummary = aRoomSummary() val roomListService = FakeRoomListService().apply { - postAllRooms(listOf(aRoomSummary())) + postAllRooms(listOf(roomSummary)) } val presenter = createRoomSelectPresenter( roomListService = roomListService @@ -68,19 +70,10 @@ class RoomSelectPresenterTest { presenter.present() }.test { val initialState = awaitItem() - val expectedRoomSummary = aRoomSummary() + val expectedRoomInfo = roomSummary.toSelectRoomInfo() // Do not compare the lambda because they will be different. So copy the lambda from expectedRoomSummary to result - val result = (awaitItem().resultState as SearchBarResultState.Results).results.map { roomSummary -> - roomSummary.copy( - lastMessage = roomSummary.lastMessage!!.copy( - event = roomSummary.lastMessage!!.event.copy( - debugInfoProvider = expectedRoomSummary.lastMessage!!.event.debugInfoProvider, - messageShieldProvider = expectedRoomSummary.lastMessage!!.event.messageShieldProvider, - ) - ), - ) - } - assertThat(result).isEqualTo(listOf(expectedRoomSummary)) + val result = (awaitItem().resultState as SearchBarResultState.Results).results + assertThat(result).isEqualTo(listOf(expectedRoomInfo)) initialState.eventSink(RoomSelectEvents.ToggleSearchActive) skipItems(1) initialState.eventSink(RoomSelectEvents.UpdateQuery("string not contained")) @@ -99,8 +92,9 @@ class RoomSelectPresenterTest { @Test fun `present - select and remove a room`() = runTest { + val roomSummary = aRoomSummary() val roomListService = FakeRoomListService().apply { - postAllRooms(listOf(aRoomSummary())) + postAllRooms(listOf(roomSummary)) } val presenter = createRoomSelectPresenter( roomListService = roomListService, @@ -109,9 +103,9 @@ class RoomSelectPresenterTest { presenter.present() }.test { val initialState = awaitItem() - val summary = aRoomSummary() - initialState.eventSink(RoomSelectEvents.SetSelectedRoom(summary)) - assertThat(awaitItem().selectedRooms).isEqualTo(persistentListOf(summary)) + val roomInfo = roomSummary.toSelectRoomInfo() + initialState.eventSink(RoomSelectEvents.SetSelectedRoom(roomInfo)) + assertThat(awaitItem().selectedRooms).isEqualTo(persistentListOf(roomInfo)) initialState.eventSink(RoomSelectEvents.RemoveSelectedRoom) assertThat(awaitItem().selectedRooms).isEmpty() cancel() diff --git a/libraries/textcomposer/impl/src/main/kotlin/io/element/android/libraries/textcomposer/mentions/ResolvedSuggestion.kt b/libraries/textcomposer/impl/src/main/kotlin/io/element/android/libraries/textcomposer/mentions/ResolvedSuggestion.kt index a0b44fb70c..6763d58ec0 100644 --- a/libraries/textcomposer/impl/src/main/kotlin/io/element/android/libraries/textcomposer/mentions/ResolvedSuggestion.kt +++ b/libraries/textcomposer/impl/src/main/kotlin/io/element/android/libraries/textcomposer/mentions/ResolvedSuggestion.kt @@ -8,13 +8,27 @@ package io.element.android.libraries.textcomposer.mentions 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.RoomAlias +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.roomlist.RoomSummary @Immutable sealed interface ResolvedSuggestion { data object AtRoom : ResolvedSuggestion data class Member(val roomMember: RoomMember) : ResolvedSuggestion - data class Alias(val roomAlias: RoomAlias, val roomSummary: RoomSummary) : ResolvedSuggestion + data class Alias( + val roomAlias: RoomAlias, + val roomId: RoomId, + val roomName: String?, + val roomAvatarUrl: String?, + ) : ResolvedSuggestion { + fun getAvatarData(size: AvatarSize) = AvatarData( + id = roomId.value, + name = roomName, + url = roomAvatarUrl, + size = size, + ) + } } diff --git a/libraries/textcomposer/impl/src/test/kotlin/io/element/android/libraries/textcomposer/impl/model/MarkdownTextEditorStateTest.kt b/libraries/textcomposer/impl/src/test/kotlin/io/element/android/libraries/textcomposer/impl/model/MarkdownTextEditorStateTest.kt index 29c0813a22..c0a9612eab 100644 --- a/libraries/textcomposer/impl/src/test/kotlin/io/element/android/libraries/textcomposer/impl/model/MarkdownTextEditorStateTest.kt +++ b/libraries/textcomposer/impl/src/test/kotlin/io/element/android/libraries/textcomposer/impl/model/MarkdownTextEditorStateTest.kt @@ -16,10 +16,10 @@ import io.element.android.libraries.matrix.api.core.toRoomIdOrAlias import io.element.android.libraries.matrix.api.permalink.PermalinkData import io.element.android.libraries.matrix.api.room.IntentionalMention import io.element.android.libraries.matrix.test.A_ROOM_ALIAS +import io.element.android.libraries.matrix.test.A_ROOM_ID import io.element.android.libraries.matrix.test.permalink.FakePermalinkBuilder import io.element.android.libraries.matrix.test.permalink.FakePermalinkParser import io.element.android.libraries.matrix.test.room.aRoomMember -import io.element.android.libraries.matrix.test.room.aRoomSummary import io.element.android.libraries.textcomposer.mentions.MentionSpan import io.element.android.libraries.textcomposer.mentions.MentionSpanProvider import io.element.android.libraries.textcomposer.mentions.ResolvedSuggestion @@ -34,7 +34,7 @@ class MarkdownTextEditorStateTest { @Test fun `insertMention - room alias - getMentions return empty list`() { val state = MarkdownTextEditorState(initialText = "Hello @", initialFocus = true) - val suggestion = ResolvedSuggestion.Alias(A_ROOM_ALIAS, aRoomSummary(canonicalAlias = A_ROOM_ALIAS)) + val suggestion = aRoomAliasSuggestion() val permalinkBuilder = FakePermalinkBuilder() val mentionSpanProvider = aMentionSpanProvider() state.insertSuggestion(suggestion, mentionSpanProvider, permalinkBuilder) @@ -46,7 +46,7 @@ class MarkdownTextEditorStateTest { val state = MarkdownTextEditorState(initialText = "Hello #", initialFocus = true).apply { currentSuggestion = Suggestion(start = 6, end = 7, type = SuggestionType.Room, text = "") } - val suggestion = ResolvedSuggestion.Alias(A_ROOM_ALIAS, aRoomSummary(canonicalAlias = A_ROOM_ALIAS)) + val suggestion = aRoomAliasSuggestion() val permalinkParser = FakePermalinkParser(result = { PermalinkData.RoomLink(A_ROOM_ALIAS.toRoomIdOrAlias()) }) val permalinkBuilder = FakePermalinkBuilder(permalinkForRoomAliasLambda = { Result.failure(IllegalStateException("Failed")) }) val mentionSpanProvider = aMentionSpanProvider(permalinkParser = permalinkParser) @@ -58,7 +58,7 @@ class MarkdownTextEditorStateTest { val state = MarkdownTextEditorState(initialText = "Hello #", initialFocus = true).apply { currentSuggestion = Suggestion(start = 6, end = 7, type = SuggestionType.Room, text = "") } - val suggestion = ResolvedSuggestion.Alias(A_ROOM_ALIAS, aRoomSummary(canonicalAlias = A_ROOM_ALIAS)) + val suggestion = aRoomAliasSuggestion() val permalinkParser = FakePermalinkParser(result = { PermalinkData.RoomLink(A_ROOM_ALIAS.toRoomIdOrAlias()) }) val permalinkBuilder = FakePermalinkBuilder(permalinkForRoomAliasLambda = { Result.success("https://matrix.to/#/${A_ROOM_ALIAS.value}") }) val mentionSpanProvider = aMentionSpanProvider(permalinkParser = permalinkParser) @@ -202,4 +202,13 @@ class MarkdownTextEditorStateTest { } } } + + private fun aRoomAliasSuggestion(): ResolvedSuggestion.Alias { + return ResolvedSuggestion.Alias( + roomAlias = A_ROOM_ALIAS, + roomId = A_ROOM_ID, + roomName = null, + roomAvatarUrl = null + ) + } } diff --git a/plugins/build.gradle.kts b/plugins/build.gradle.kts index 33d7bb0bd6..2380b204ce 100644 --- a/plugins/build.gradle.kts +++ b/plugins/build.gradle.kts @@ -24,4 +24,5 @@ dependencies { implementation(libs.autonomousapps.dependencyanalysis.plugin) implementation(libs.anvil.gradle.plugin) implementation(libs.ksp.gradle.plugin) + implementation(libs.compose.compiler.plugin) } diff --git a/plugins/src/main/kotlin/Versions.kt b/plugins/src/main/kotlin/Versions.kt index 71a5c65c8b..9204101960 100644 --- a/plugins/src/main/kotlin/Versions.kt +++ b/plugins/src/main/kotlin/Versions.kt @@ -42,12 +42,12 @@ import org.gradle.jvm.toolchain.JavaLanguageVersion // Note: 2 digits max for each value private const val versionMajor = 0 -private const val versionMinor = 6 +private const val versionMinor = 7 // 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 = 5 +private const val versionPatch = 0 object Versions { val versionCode = 4_000_000 + versionMajor * 1_00_00 + versionMinor * 1_00 + versionPatch diff --git a/plugins/src/main/kotlin/extension/CommonExtension.kt b/plugins/src/main/kotlin/extension/CommonExtension.kt index 32e27b516e..4f3f23d707 100644 --- a/plugins/src/main/kotlin/extension/CommonExtension.kt +++ b/plugins/src/main/kotlin/extension/CommonExtension.kt @@ -10,7 +10,6 @@ package extension import Versions import com.android.build.api.dsl.CommonExtension import isEnterpriseBuild -import org.gradle.accessors.dm.LibrariesForLibs import org.gradle.api.Project import java.io.File @@ -44,21 +43,18 @@ fun CommonExtension<*, *, *, *, *, *>.androidConfig(project: Project) { } checkDependencies = false abortOnError = true + ignoreTestSources = true ignoreTestFixturesSources = true checkGeneratedSources = false } } -fun CommonExtension<*, *, *, *, *, *>.composeConfig(libs: LibrariesForLibs) { +fun CommonExtension<*, *, *, *, *, *>.composeConfig() { buildFeatures { compose = true } - composeOptions { - kotlinCompilerExtensionVersion = libs.versions.composecompiler.get() - } - packaging { resources.excludes.apply { add("META-INF/AL2.0") 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 6773164f46..967e4fd707 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 @@ -19,11 +19,12 @@ plugins { id("com.android.application") id("kotlin-android") id("com.autonomousapps.dependency-analysis") + id("org.jetbrains.kotlin.plugin.compose") } android { androidConfig(project) - composeConfig(libs) + composeConfig() compileOptions { isCoreLibraryDesugaringEnabled = true } 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 5c6c6a3589..b4d7fe650a 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 @@ -19,11 +19,12 @@ plugins { id("com.android.library") id("kotlin-android") id("com.autonomousapps.dependency-analysis") + id("org.jetbrains.kotlin.plugin.compose") } android { androidConfig(project) - composeConfig(libs) + composeConfig() compileOptions { isCoreLibraryDesugaringEnabled = true } diff --git a/tests/testutils/src/main/kotlin/io/element/android/tests/testutils/lambda/LambdaRecorder.kt b/tests/testutils/src/main/kotlin/io/element/android/tests/testutils/lambda/LambdaRecorder.kt index c4e5222060..2fa38e04c1 100644 --- a/tests/testutils/src/main/kotlin/io/element/android/tests/testutils/lambda/LambdaRecorder.kt +++ b/tests/testutils/src/main/kotlin/io/element/android/tests/testutils/lambda/LambdaRecorder.kt @@ -7,6 +7,8 @@ package io.element.android.tests.testutils.lambda +import kotlinx.coroutines.runBlocking + /** * A recorder that can be used to record the parameters of lambda invocation. */ @@ -93,21 +95,21 @@ inline fun lambdaAnyRecorder( class LambdaNoParamRecorder(ensureNeverCalled: Boolean, val block: () -> R) : LambdaRecorder(ensureNeverCalled), () -> R { override fun invoke(): R { onInvoke() - return block() + return runBlocking { block() } } } class LambdaOneParamRecorder(ensureNeverCalled: Boolean, val block: (T) -> R) : LambdaRecorder(ensureNeverCalled), (T) -> R { override fun invoke(p: T): R { onInvoke(p) - return block(p) + return runBlocking { block(p) } } } class LambdaTwoParamsRecorder(ensureNeverCalled: Boolean, val block: (T1, T2) -> R) : LambdaRecorder(ensureNeverCalled), (T1, T2) -> R { override fun invoke(p1: T1, p2: T2): R { onInvoke(p1, p2) - return block(p1, p2) + return runBlocking { block(p1, p2) } } } @@ -116,7 +118,7 @@ class LambdaThreeParamsRecorder(ensureNeverCalled: B ), (T1, T2, T3) -> R { override fun invoke(p1: T1, p2: T2, p3: T3): R { onInvoke(p1, p2, p3) - return block(p1, p2, p3) + return runBlocking { block(p1, p2, p3) } } } @@ -125,16 +127,19 @@ class LambdaFourParamsRecorder(ensureNeverCal ), (T1, T2, T3, T4) -> R { override fun invoke(p1: T1, p2: T2, p3: T3, p4: T4): R { onInvoke(p1, p2, p3, p4) - return block(p1, p2, p3, p4) + return runBlocking { block(p1, p2, p3, p4) } } } -class LambdaFiveParamsRecorder(ensureNeverCalled: Boolean, val block: (T1, T2, T3, T4, T5) -> R) : LambdaRecorder( +class LambdaFiveParamsRecorder( + ensureNeverCalled: Boolean, + val block: (T1, T2, T3, T4, T5) -> R, +) : LambdaRecorder( ensureNeverCalled ), (T1, T2, T3, T4, T5) -> R { override fun invoke(p1: T1, p2: T2, p3: T3, p4: T4, p5: T5): R { onInvoke(p1, p2, p3, p4, p5) - return block(p1, p2, p3, p4, p5) + return runBlocking { block(p1, p2, p3, p4, p5) } } } @@ -144,7 +149,7 @@ class LambdaSixParamsRecorder( ) : LambdaRecorder(ensureNeverCalled), (T1, T2, T3, T4, T5, T6) -> R { override fun invoke(p1: T1, p2: T2, p3: T3, p4: T4, p5: T5, p6: T6): R { onInvoke(p1, p2, p3, p4, p5, p6) - return block(p1, p2, p3, p4, p5, p6) + return runBlocking { block(p1, p2, p3, p4, p5, p6) } } } @@ -154,7 +159,7 @@ class LambdaSevenParamsRecorder R { override fun invoke(p1: T1, p2: T2, p3: T3, p4: T4, p5: T5, p6: T6, p7: T7): R { onInvoke(p1, p2, p3, p4, p5, p6, p7) - return block(p1, p2, p3, p4, p5, p6, p7) + return runBlocking { block(p1, p2, p3, p4, p5, p6, p7) } } } @@ -164,7 +169,7 @@ class LambdaEightParamsRecorder R { override fun invoke(p1: T1, p2: T2, p3: T3, p4: T4, p5: T5, p6: T6, p7: T7, p8: T8): R { onInvoke(p1, p2, p3, p4, p5, p6, p7, p8) - return block(p1, p2, p3, p4, p5, p6, p7, p8) + return runBlocking { block(p1, p2, p3, p4, p5, p6, p7, p8) } } } @@ -174,7 +179,7 @@ class LambdaNineParamsRecorder R { override fun invoke(p1: T1, p2: T2, p3: T3, p4: T4, p5: T5, p6: T6, p7: T7, p8: T8, p9: T9): R { onInvoke(p1, p2, p3, p4, p5, p6, p7, p8, p9) - return block(p1, p2, p3, p4, p5, p6, p7, p8, p9) + return runBlocking { block(p1, p2, p3, p4, p5, p6, p7, p8, p9) } } } diff --git a/tests/uitests/src/test/snapshots/images/features.login.impl.screens.createaccount_CreateAccountView_Day_1_en.png b/tests/uitests/src/test/snapshots/images/features.login.impl.screens.createaccount_CreateAccountView_Day_1_en.png index 2bb913bca2..ebe9ca2f39 100644 --- a/tests/uitests/src/test/snapshots/images/features.login.impl.screens.createaccount_CreateAccountView_Day_1_en.png +++ b/tests/uitests/src/test/snapshots/images/features.login.impl.screens.createaccount_CreateAccountView_Day_1_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:934ec16ccbbefabc0f86842e2b9adc2c2c03e3194ce9adae41a5032633083a4e -size 13805 +oid sha256:fa90a8f2579ea170bbd5d3a13ea859da53ddd999694b7730b4c0aa3daef192a2 +size 13769 diff --git a/tests/uitests/src/test/snapshots/images/features.login.impl.screens.createaccount_CreateAccountView_Night_1_en.png b/tests/uitests/src/test/snapshots/images/features.login.impl.screens.createaccount_CreateAccountView_Night_1_en.png index a88acd4565..ecd3fa6368 100644 --- a/tests/uitests/src/test/snapshots/images/features.login.impl.screens.createaccount_CreateAccountView_Night_1_en.png +++ b/tests/uitests/src/test/snapshots/images/features.login.impl.screens.createaccount_CreateAccountView_Night_1_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:096f78196c22e626b24dc98bea6b5831fbaab76388b2a002562e4bf4dfbc9506 -size 13394 +oid sha256:705f53f174aeaa0173b618adbb718d86b7d1a25767aa2801866a154f365acf9a +size 13361 diff --git a/tests/uitests/src/test/snapshots/images/features.login.impl.screens.qrcode.intro_QrCodeIntroView_Day_0_en.png b/tests/uitests/src/test/snapshots/images/features.login.impl.screens.qrcode.intro_QrCodeIntroView_Day_0_en.png index 1517bc5b18..21ab27c511 100644 --- a/tests/uitests/src/test/snapshots/images/features.login.impl.screens.qrcode.intro_QrCodeIntroView_Day_0_en.png +++ b/tests/uitests/src/test/snapshots/images/features.login.impl.screens.qrcode.intro_QrCodeIntroView_Day_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:c20777e79d65269c7e330c56bdd591ad771c97fb0fa8b74e18e45ffa8aa3525b -size 42436 +oid sha256:021982f9575de9946f905c348f3be4cd12e58550fc2ba6f7e86d44f72c35a254 +size 50081 diff --git a/tests/uitests/src/test/snapshots/images/features.login.impl.screens.qrcode.intro_QrCodeIntroView_Day_1_en.png b/tests/uitests/src/test/snapshots/images/features.login.impl.screens.qrcode.intro_QrCodeIntroView_Day_1_en.png index 5873bdab62..074ce8fb9e 100644 --- a/tests/uitests/src/test/snapshots/images/features.login.impl.screens.qrcode.intro_QrCodeIntroView_Day_1_en.png +++ b/tests/uitests/src/test/snapshots/images/features.login.impl.screens.qrcode.intro_QrCodeIntroView_Day_1_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:b1a76c6c3e57652e16c3e5fa9168ea24cc16e55806ba972228397146fe0fdbb3 -size 42356 +oid sha256:2f30cfd5af7247c188851213b122e78e51bf38f0b8c94870776c081b4d69f9e0 +size 48509 diff --git a/tests/uitests/src/test/snapshots/images/features.login.impl.screens.qrcode.intro_QrCodeIntroView_Night_0_en.png b/tests/uitests/src/test/snapshots/images/features.login.impl.screens.qrcode.intro_QrCodeIntroView_Night_0_en.png index bdd1dcc323..32c359384b 100644 --- a/tests/uitests/src/test/snapshots/images/features.login.impl.screens.qrcode.intro_QrCodeIntroView_Night_0_en.png +++ b/tests/uitests/src/test/snapshots/images/features.login.impl.screens.qrcode.intro_QrCodeIntroView_Night_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:fab7adfa1fedf07847a39f374b1a0fb8c41b0a2d2862b9dc35cd26f1a30c8c32 -size 41045 +oid sha256:4b16db86e6aa5ba64d4f4539120d28588ce9e5daf3aef30b275d47f00ec55776 +size 48634 diff --git a/tests/uitests/src/test/snapshots/images/features.login.impl.screens.qrcode.intro_QrCodeIntroView_Night_1_en.png b/tests/uitests/src/test/snapshots/images/features.login.impl.screens.qrcode.intro_QrCodeIntroView_Night_1_en.png index f8d32fb22a..de297410b0 100644 --- a/tests/uitests/src/test/snapshots/images/features.login.impl.screens.qrcode.intro_QrCodeIntroView_Night_1_en.png +++ b/tests/uitests/src/test/snapshots/images/features.login.impl.screens.qrcode.intro_QrCodeIntroView_Night_1_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:b7bc76f3dc71082e683707659aad62e63965e0ceee5845d1a540c976513187ae -size 40079 +oid sha256:ef3187936592091492d4d4d349954000722a8e764d9baa35ea987b49d5bd4b8a +size 46145 diff --git a/tests/uitests/src/test/snapshots/images/features.logout.impl_LogoutView_Day_2_en.png b/tests/uitests/src/test/snapshots/images/features.logout.impl_LogoutView_Day_2_en.png index a6ed70d4ac..7806dd678f 100644 --- a/tests/uitests/src/test/snapshots/images/features.logout.impl_LogoutView_Day_2_en.png +++ b/tests/uitests/src/test/snapshots/images/features.logout.impl_LogoutView_Day_2_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:1b1a146b7de0270396cd56cd61d614d3792498249e7d1c3e48dd9f5d62cdab3a -size 27704 +oid sha256:ca20f0fc7b05412b5bf27250b1afb3057598980e398b5d157ecd86a194727deb +size 27627 diff --git a/tests/uitests/src/test/snapshots/images/features.logout.impl_LogoutView_Night_2_en.png b/tests/uitests/src/test/snapshots/images/features.logout.impl_LogoutView_Night_2_en.png index 4d9040f483..03b5ed32c0 100644 --- a/tests/uitests/src/test/snapshots/images/features.logout.impl_LogoutView_Night_2_en.png +++ b/tests/uitests/src/test/snapshots/images/features.logout.impl_LogoutView_Night_2_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:8a8fe1667c9e76c21bdaf2c388100bee608eab48ce994968e434cda28a837439 -size 26721 +oid sha256:1b388d8c8e3a2b4b4d1d4aac5da7bf23b1f94a7ea58deb0850b10c2bccfe11aa +size 26652 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.messagecomposer.suggestions_SuggestionsPickerView_Day_0_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.messagecomposer.suggestions_SuggestionsPickerView_Day_0_en.png index d648e7b34a..052885e97e 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl.messagecomposer.suggestions_SuggestionsPickerView_Day_0_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.messagecomposer.suggestions_SuggestionsPickerView_Day_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:7d984f18fc4abf9fe56afc74f094aaacfb6926642b37d2d5fc11568707e3f331 -size 22296 +oid sha256:19f6f6dcdf49e9ffd2fbb0ea81c3fe0374faf79cecccc812ea1e1d8c05578671 +size 22344 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.messagecomposer.suggestions_SuggestionsPickerView_Night_0_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.messagecomposer.suggestions_SuggestionsPickerView_Night_0_en.png index 39aed8f6a0..1e43118d49 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl.messagecomposer.suggestions_SuggestionsPickerView_Night_0_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.messagecomposer.suggestions_SuggestionsPickerView_Night_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:853541fe1bf56895ed286791d68e13d6f07bd8a5a1fbdaafe5354f10a916f5c0 -size 22620 +oid sha256:12266ee1fc3477aec0f47e731294ccd2f93ecf4a3a1fada6cf4cb8ba6f7430ac +size 22661 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.customreaction_EmojiPicker_Day_0_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.customreaction_EmojiPicker_Day_0_en.png index c876ecf0e4..29b1a5cb41 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.customreaction_EmojiPicker_Day_0_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.customreaction_EmojiPicker_Day_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:9bc9d7caab8a956190b9b893c8c563f464edc6a4a2fd337d919cce7ae4f1b6e8 -size 231301 +oid sha256:ddbe76235df4343660750e42512a431d10911442db54a2441fcb204ee4a6eb38 +size 230808 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.customreaction_EmojiPicker_Night_0_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.customreaction_EmojiPicker_Night_0_en.png index 43fb60a147..6aa56907d4 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.customreaction_EmojiPicker_Night_0_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.customreaction_EmojiPicker_Night_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:57506329b66b64b6c118c9b04fe76ad343b5181b7d4640fe8b86adf24ef8687a -size 234070 +oid sha256:bcc7cc69fdcae48da59f2bec88950aad996b869813d7f569bb205235efbd2731 +size 233656 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.event_TimelineItemPollView_Day_0_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.event_TimelineItemPollView_Day_0_en.png index 1713eec87a..47722c0807 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.event_TimelineItemPollView_Day_0_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.event_TimelineItemPollView_Day_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:c319670ffe1f12885625bd03c83979e8657f61675393aaa943e756f2a052b465 -size 47105 +oid sha256:0db7953caa01f68e2e9b182b58cdd4d02bdf6912ddae64a36fec0636092575b6 +size 46825 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.event_TimelineItemPollView_Day_1_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.event_TimelineItemPollView_Day_1_en.png index bb19caa5e8..2655007ace 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.event_TimelineItemPollView_Day_1_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.event_TimelineItemPollView_Day_1_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:7c433b062b5b0cf86b5b246e5669641612931f027904216d5f96ae561464e221 -size 49292 +oid sha256:01606eff6666f83cef3290e0d986453a6b2b22061a90a60e8db675438ff1eb03 +size 49037 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.event_TimelineItemPollView_Day_2_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.event_TimelineItemPollView_Day_2_en.png index 635b871722..2d0a6aa749 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.event_TimelineItemPollView_Day_2_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.event_TimelineItemPollView_Day_2_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:c98ae539d549ef2ece48d6f7dab5525889a237947af17e79c68e8d2490fd7bfb -size 49371 +oid sha256:37695b5ff4b53d50c0d2b278f9a41f961a98a2e9fed25ed239914963c3387314 +size 49142 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.event_TimelineItemPollView_Day_3_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.event_TimelineItemPollView_Day_3_en.png index 9f04d057d0..7fbae24358 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.event_TimelineItemPollView_Day_3_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.event_TimelineItemPollView_Day_3_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:9679b97fd0e0756ad13344bac23363eed20ffc3a49a5297303ab2ad991f5a8b9 -size 49431 +oid sha256:2b9fb692a5035151c4e2c4975f07c1b51b366065bf8c4a4f25a678bbeb832035 +size 49209 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.event_TimelineItemPollView_Night_0_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.event_TimelineItemPollView_Night_0_en.png index b74c2d0998..94e34de7a1 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.event_TimelineItemPollView_Night_0_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.event_TimelineItemPollView_Night_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:62cf5c40a74693f2596535870e97a1d884b7abd7f602861f5d16cec11de45c1d -size 45948 +oid sha256:ba9520116a974c22c709fec9b90f7053664a4938e6a96f3b21fe340717c33a54 +size 45692 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.event_TimelineItemPollView_Night_1_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.event_TimelineItemPollView_Night_1_en.png index d83c049a67..1f62dcf570 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.event_TimelineItemPollView_Night_1_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.event_TimelineItemPollView_Night_1_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:5cb81653962abed6ee75efb93d8693e0c899fece3bbc00ec9855a97c3ecc730a -size 48141 +oid sha256:249df92cc411ad26af2700546e2fca7c0621ff4e6aa9747edb1ba6e2e47d52fa +size 47889 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.event_TimelineItemPollView_Night_2_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.event_TimelineItemPollView_Night_2_en.png index d078b0dcfe..11cfce1e3b 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.event_TimelineItemPollView_Night_2_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.event_TimelineItemPollView_Night_2_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:bea1dc185eb3324df0a7a3bc2afec44e922a08492f0ebea394bdcfd949dab57e -size 48143 +oid sha256:7f2e4dd94801ee28848ed04bf3c4846631359873e150e433a397c305b0a33dde +size 47887 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.event_TimelineItemPollView_Night_3_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.event_TimelineItemPollView_Night_3_en.png index efe5329e3d..2a903d5c0c 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.event_TimelineItemPollView_Night_3_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.event_TimelineItemPollView_Night_3_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:4457dbc7e3c5fc7f30eaf962c707e62aaffb4534d1602c8c6fa796c516e91138 -size 48220 +oid sha256:e9a67a0384cb8af35f0154d2f3ec9099a792b6b9ca9c5abc17e1653dfc643016 +size 47967 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.virtual_TimelineLoadingMoreIndicator_Day_0_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.virtual_TimelineLoadingMoreIndicator_Day_0_en.png index 91f45eb287..177719d8c2 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.virtual_TimelineLoadingMoreIndicator_Day_0_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.virtual_TimelineLoadingMoreIndicator_Day_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:105c12dfc6f165a996b5cf3bba1d6183636e779aabc3b216dbe6f2c60b13b7c6 -size 5361 +oid sha256:3078f28f9f43885231d4408434cb0e98a0127afbee852918752df25c32cabe80 +size 5339 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.virtual_TimelineLoadingMoreIndicator_Night_0_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.virtual_TimelineLoadingMoreIndicator_Night_0_en.png index 98a4ef217f..650a8580fb 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.virtual_TimelineLoadingMoreIndicator_Night_0_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.virtual_TimelineLoadingMoreIndicator_Night_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:2e7240f809ed2d07a09478b26ea8f775ecea10d1e482fc1a7b0b8013ecc1b1e3 -size 5322 +oid sha256:3f0bb30e487d02e4c21b6e85cf0354b9d3a926d321fec7e6ab70426e52365b0b +size 5294 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventTimestampBelow_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventTimestampBelow_en.png index 63ae407543..e384e2f1c5 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventTimestampBelow_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventTimestampBelow_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:18ad7597add50647e32a4825538b1c84c2cc6cac1bf804302e10d6fb74891980 -size 52851 +oid sha256:5846bf42b05878c92d080a75ddb5f6285f74f23acd8676dd7937f60729eeb775 +size 52521 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline_TimelineView_Day_11_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline_TimelineView_Day_11_en.png index 72ad865b50..d88b601369 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline_TimelineView_Day_11_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline_TimelineView_Day_11_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:d24ca3b8db59b11b6bc225919a11694a143b41b8147b24b599c22cecf46e5de1 -size 85599 +oid sha256:a803637685f21736b75d08735031674ae3e407d02631f1fb713a68ec9cdb60af +size 85225 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline_TimelineView_Night_11_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline_TimelineView_Night_11_en.png index 5f5979e70d..b5feaa4561 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline_TimelineView_Night_11_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline_TimelineView_Night_11_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:2d5cfb60d3c069df4ade7489fc7e4a7caa883fe26da32c164c0150681719d4bf -size 86642 +oid sha256:a9dc71aa3c2ef36e67296ef94b83f84646a263599cabb71d0c9d0ad7c5b1b8c1 +size 86338 diff --git a/tests/uitests/src/test/snapshots/images/features.poll.api.pollcontent_PollAnswerViewDisclosedNotSelected_Day_0_en.png b/tests/uitests/src/test/snapshots/images/features.poll.api.pollcontent_PollAnswerViewDisclosedNotSelected_Day_0_en.png index 0c5d4253cc..2209424357 100644 --- a/tests/uitests/src/test/snapshots/images/features.poll.api.pollcontent_PollAnswerViewDisclosedNotSelected_Day_0_en.png +++ b/tests/uitests/src/test/snapshots/images/features.poll.api.pollcontent_PollAnswerViewDisclosedNotSelected_Day_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:ec5ffbdd20642afb545cb434c56e6257ba9ec0319864a76f35dc3536119d7778 -size 21711 +oid sha256:ca67b2bf4a3e0d654d4ed3186e5d70dbe82448ee2028b7a30b9c780e5332b294 +size 21622 diff --git a/tests/uitests/src/test/snapshots/images/features.poll.api.pollcontent_PollAnswerViewDisclosedNotSelected_Night_0_en.png b/tests/uitests/src/test/snapshots/images/features.poll.api.pollcontent_PollAnswerViewDisclosedNotSelected_Night_0_en.png index aa06ef7b41..31937d60bb 100644 --- a/tests/uitests/src/test/snapshots/images/features.poll.api.pollcontent_PollAnswerViewDisclosedNotSelected_Night_0_en.png +++ b/tests/uitests/src/test/snapshots/images/features.poll.api.pollcontent_PollAnswerViewDisclosedNotSelected_Night_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:538cfce84577e22223351336a21e5ff4fdf7165678ea7e9df61e7f426165a227 -size 21355 +oid sha256:6e359f9178a033fea29952aad2892e3416ef6b4b7924ca085963140d35ff4d22 +size 21268 diff --git a/tests/uitests/src/test/snapshots/images/features.poll.api.pollcontent_PollAnswerViewDisclosedSelected_Day_0_en.png b/tests/uitests/src/test/snapshots/images/features.poll.api.pollcontent_PollAnswerViewDisclosedSelected_Day_0_en.png index 68a4f66d2f..054061a5c8 100644 --- a/tests/uitests/src/test/snapshots/images/features.poll.api.pollcontent_PollAnswerViewDisclosedSelected_Day_0_en.png +++ b/tests/uitests/src/test/snapshots/images/features.poll.api.pollcontent_PollAnswerViewDisclosedSelected_Day_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:af4a9572a809d23f9604461cb39d6008a0974451e48e730d52d3e4d58d82a632 -size 21556 +oid sha256:fc6bc3a1bed25b08233701dc3931a9c5057c17fd811b36ebcb8fcbe78f89fec7 +size 21466 diff --git a/tests/uitests/src/test/snapshots/images/features.poll.api.pollcontent_PollAnswerViewDisclosedSelected_Night_0_en.png b/tests/uitests/src/test/snapshots/images/features.poll.api.pollcontent_PollAnswerViewDisclosedSelected_Night_0_en.png index 8cf153cd8d..58d00585e9 100644 --- a/tests/uitests/src/test/snapshots/images/features.poll.api.pollcontent_PollAnswerViewDisclosedSelected_Night_0_en.png +++ b/tests/uitests/src/test/snapshots/images/features.poll.api.pollcontent_PollAnswerViewDisclosedSelected_Night_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:dc441b1ef2ba4d581a81cb437e930fa981f0d8a78a504328e382529a9c45dc73 -size 21103 +oid sha256:7c5581a46a24bfd40fb4284cf6c77c1955c74830d134d379caf863704e3654e7 +size 21018 diff --git a/tests/uitests/src/test/snapshots/images/features.poll.api.pollcontent_PollAnswerViewEndedSelected_Day_0_en.png b/tests/uitests/src/test/snapshots/images/features.poll.api.pollcontent_PollAnswerViewEndedSelected_Day_0_en.png index 9f73781f39..59eed4a5cc 100644 --- a/tests/uitests/src/test/snapshots/images/features.poll.api.pollcontent_PollAnswerViewEndedSelected_Day_0_en.png +++ b/tests/uitests/src/test/snapshots/images/features.poll.api.pollcontent_PollAnswerViewEndedSelected_Day_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:06d1c63a1f73de93f7caa869dbb379a6f87c48c22b86bd51513819064a9ed411 -size 21617 +oid sha256:8a2a1910e21509ebbaf5117e2abdef0dee6bb301afeeae821d0240a72e5ef721 +size 21538 diff --git a/tests/uitests/src/test/snapshots/images/features.poll.api.pollcontent_PollAnswerViewEndedSelected_Night_0_en.png b/tests/uitests/src/test/snapshots/images/features.poll.api.pollcontent_PollAnswerViewEndedSelected_Night_0_en.png index e047f40fdf..9afe1b7630 100644 --- a/tests/uitests/src/test/snapshots/images/features.poll.api.pollcontent_PollAnswerViewEndedSelected_Night_0_en.png +++ b/tests/uitests/src/test/snapshots/images/features.poll.api.pollcontent_PollAnswerViewEndedSelected_Night_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:16162a704e8934543a657fb35beb58c353e56477112a7e031f5cdcced8b1863f -size 21196 +oid sha256:4051a95ba6a727fe0f688bd56e14739ddc617b9b3466b80c6bc60c90f91f4a4b +size 21123 diff --git a/tests/uitests/src/test/snapshots/images/features.poll.api.pollcontent_PollAnswerViewEndedWinnerNotSelected_Day_0_en.png b/tests/uitests/src/test/snapshots/images/features.poll.api.pollcontent_PollAnswerViewEndedWinnerNotSelected_Day_0_en.png index 929feb56cb..f3372cda75 100644 --- a/tests/uitests/src/test/snapshots/images/features.poll.api.pollcontent_PollAnswerViewEndedWinnerNotSelected_Day_0_en.png +++ b/tests/uitests/src/test/snapshots/images/features.poll.api.pollcontent_PollAnswerViewEndedWinnerNotSelected_Day_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:b9e1a60f0f414e191a11790da8776e90d980d3cc031ad0ddc907361357ee087a -size 21961 +oid sha256:c6775a6973259a21d6fa47666bbe134786795c4518b55ca2a7bd8aa84348258c +size 21870 diff --git a/tests/uitests/src/test/snapshots/images/features.poll.api.pollcontent_PollAnswerViewEndedWinnerNotSelected_Night_0_en.png b/tests/uitests/src/test/snapshots/images/features.poll.api.pollcontent_PollAnswerViewEndedWinnerNotSelected_Night_0_en.png index 2d9ee1efc5..c5ccdf3def 100644 --- a/tests/uitests/src/test/snapshots/images/features.poll.api.pollcontent_PollAnswerViewEndedWinnerNotSelected_Night_0_en.png +++ b/tests/uitests/src/test/snapshots/images/features.poll.api.pollcontent_PollAnswerViewEndedWinnerNotSelected_Night_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:dcab73fbb97dc8c288806ed72ee4f407e8df80ceaf990e211bb50b0bd20a193e -size 21308 +oid sha256:3fec8262afb8861cb2d8f00417171553335cbe12bfae9f78c022c29f44efba08 +size 21235 diff --git a/tests/uitests/src/test/snapshots/images/features.poll.api.pollcontent_PollAnswerViewEndedWinnerSelected_Day_0_en.png b/tests/uitests/src/test/snapshots/images/features.poll.api.pollcontent_PollAnswerViewEndedWinnerSelected_Day_0_en.png index 95dacc79b1..0a39b8d197 100644 --- a/tests/uitests/src/test/snapshots/images/features.poll.api.pollcontent_PollAnswerViewEndedWinnerSelected_Day_0_en.png +++ b/tests/uitests/src/test/snapshots/images/features.poll.api.pollcontent_PollAnswerViewEndedWinnerSelected_Day_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:f7930defd180a6ebdf6fdc303d3c02c3530459418d62c3ab319ef675572ffa12 -size 21931 +oid sha256:bacadedeeba30f2cbe00a85071ae5d8ea1e29dcbf6f4173b916d86cf5a7b0054 +size 21837 diff --git a/tests/uitests/src/test/snapshots/images/features.poll.api.pollcontent_PollAnswerViewEndedWinnerSelected_Night_0_en.png b/tests/uitests/src/test/snapshots/images/features.poll.api.pollcontent_PollAnswerViewEndedWinnerSelected_Night_0_en.png index afa2f78ef2..57c802e70f 100644 --- a/tests/uitests/src/test/snapshots/images/features.poll.api.pollcontent_PollAnswerViewEndedWinnerSelected_Night_0_en.png +++ b/tests/uitests/src/test/snapshots/images/features.poll.api.pollcontent_PollAnswerViewEndedWinnerSelected_Night_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:b1f750f39615e494e1426dd40a85ebd8bd646835105c9122e28d06b50f2a749f -size 21283 +oid sha256:4149eaded704dad502586c1677d4ec8ad69741877a26d41e6b9c92e0ccaac938 +size 21209 diff --git a/tests/uitests/src/test/snapshots/images/features.poll.api.pollcontent_PollAnswerViewUndisclosedNotSelected_Day_0_en.png b/tests/uitests/src/test/snapshots/images/features.poll.api.pollcontent_PollAnswerViewUndisclosedNotSelected_Day_0_en.png index eca53e5b84..b36cb7af61 100644 --- a/tests/uitests/src/test/snapshots/images/features.poll.api.pollcontent_PollAnswerViewUndisclosedNotSelected_Day_0_en.png +++ b/tests/uitests/src/test/snapshots/images/features.poll.api.pollcontent_PollAnswerViewUndisclosedNotSelected_Day_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:331fce2ac998f57171fbf241734ab15ba7fd1d03e7b489792230c687fdf56f87 -size 19683 +oid sha256:a46dfd4eee3d73afdd565295fedb75e5ff9be6b382120dae867218d54d95a382 +size 19623 diff --git a/tests/uitests/src/test/snapshots/images/features.poll.api.pollcontent_PollAnswerViewUndisclosedNotSelected_Night_0_en.png b/tests/uitests/src/test/snapshots/images/features.poll.api.pollcontent_PollAnswerViewUndisclosedNotSelected_Night_0_en.png index f97b4587aa..70c00ed688 100644 --- a/tests/uitests/src/test/snapshots/images/features.poll.api.pollcontent_PollAnswerViewUndisclosedNotSelected_Night_0_en.png +++ b/tests/uitests/src/test/snapshots/images/features.poll.api.pollcontent_PollAnswerViewUndisclosedNotSelected_Night_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:0d6edc0f4ef868638c8467f5faf0052f8b62b37159a2a981ef5a812c7e24d74d -size 19398 +oid sha256:227c4abaff48d7c9eb6c5d3c6bef5eafd743a28a824cba0579ea3943e8bb4c04 +size 19326 diff --git a/tests/uitests/src/test/snapshots/images/features.poll.api.pollcontent_PollAnswerViewUndisclosedSelected_Day_0_en.png b/tests/uitests/src/test/snapshots/images/features.poll.api.pollcontent_PollAnswerViewUndisclosedSelected_Day_0_en.png index 7a8ba60448..3a41810850 100644 --- a/tests/uitests/src/test/snapshots/images/features.poll.api.pollcontent_PollAnswerViewUndisclosedSelected_Day_0_en.png +++ b/tests/uitests/src/test/snapshots/images/features.poll.api.pollcontent_PollAnswerViewUndisclosedSelected_Day_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:d712aa52a23d731818ee6df552c971ebe1aba1489c260b957c18c776b1ee5753 -size 19475 +oid sha256:0252970cedc7df470d12e7458d2bf2428e2e843124696e644542d7ac409005aa +size 19454 diff --git a/tests/uitests/src/test/snapshots/images/features.poll.api.pollcontent_PollAnswerViewUndisclosedSelected_Night_0_en.png b/tests/uitests/src/test/snapshots/images/features.poll.api.pollcontent_PollAnswerViewUndisclosedSelected_Night_0_en.png index c8e672914e..0d02eff715 100644 --- a/tests/uitests/src/test/snapshots/images/features.poll.api.pollcontent_PollAnswerViewUndisclosedSelected_Night_0_en.png +++ b/tests/uitests/src/test/snapshots/images/features.poll.api.pollcontent_PollAnswerViewUndisclosedSelected_Night_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:4c3abf423995c3e612af7231822f145d3cb04f49a954b947990cbdd460fd8ac7 -size 19099 +oid sha256:e402c49b2434f244bf36b5f09b5a550e20280d18627b9624eca135d5288b6d4b +size 19093 diff --git a/tests/uitests/src/test/snapshots/images/features.poll.api.pollcontent_PollContentViewCreatorEditable_Day_0_en.png b/tests/uitests/src/test/snapshots/images/features.poll.api.pollcontent_PollContentViewCreatorEditable_Day_0_en.png index 3d1c0e564b..7519dc652e 100644 --- a/tests/uitests/src/test/snapshots/images/features.poll.api.pollcontent_PollContentViewCreatorEditable_Day_0_en.png +++ b/tests/uitests/src/test/snapshots/images/features.poll.api.pollcontent_PollContentViewCreatorEditable_Day_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:f903b6071355ac5c45b9fc58933b94ab0341b1724cc99378db7d59bc8b7d81b4 -size 49434 +oid sha256:758747be120863a6f2f88b257ee277c83d7445a41d71ed664a6d7920cfb011f3 +size 49252 diff --git a/tests/uitests/src/test/snapshots/images/features.poll.api.pollcontent_PollContentViewCreatorEditable_Night_0_en.png b/tests/uitests/src/test/snapshots/images/features.poll.api.pollcontent_PollContentViewCreatorEditable_Night_0_en.png index b2d427d9f8..0322c5b34d 100644 --- a/tests/uitests/src/test/snapshots/images/features.poll.api.pollcontent_PollContentViewCreatorEditable_Night_0_en.png +++ b/tests/uitests/src/test/snapshots/images/features.poll.api.pollcontent_PollContentViewCreatorEditable_Night_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:6cdb0d60e622128f17b3b84c4f1722a5638dc7fb25ec0ed063a6d8148fd23419 -size 48169 +oid sha256:7d60ccff326a07c50e60e28f1158ea701226b92663befc25a68cac27e9e394be +size 47947 diff --git a/tests/uitests/src/test/snapshots/images/features.poll.api.pollcontent_PollContentViewCreatorEnded_Day_0_en.png b/tests/uitests/src/test/snapshots/images/features.poll.api.pollcontent_PollContentViewCreatorEnded_Day_0_en.png index d4853bda91..374113b566 100644 --- a/tests/uitests/src/test/snapshots/images/features.poll.api.pollcontent_PollContentViewCreatorEnded_Day_0_en.png +++ b/tests/uitests/src/test/snapshots/images/features.poll.api.pollcontent_PollContentViewCreatorEnded_Day_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:1a33919bf3b6936a05cab67554ae9bfefc15d7e731b81526c90f9cd072be8204 -size 47512 +oid sha256:7d4d192e27e8f705f1049e63e6cd9759830526e43132502033fd198d9216346a +size 47244 diff --git a/tests/uitests/src/test/snapshots/images/features.poll.api.pollcontent_PollContentViewCreatorEnded_Night_0_en.png b/tests/uitests/src/test/snapshots/images/features.poll.api.pollcontent_PollContentViewCreatorEnded_Night_0_en.png index 38ed7482a5..53fea58d96 100644 --- a/tests/uitests/src/test/snapshots/images/features.poll.api.pollcontent_PollContentViewCreatorEnded_Night_0_en.png +++ b/tests/uitests/src/test/snapshots/images/features.poll.api.pollcontent_PollContentViewCreatorEnded_Night_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:467953c093f401d388528805530769ea8c224d8692c0bc6ab81a23a0c48d0e8d -size 46126 +oid sha256:58b7377a27c180c531168e48819e903554f1d85525626ab4b6d79dab7f322c43 +size 45889 diff --git a/tests/uitests/src/test/snapshots/images/features.poll.api.pollcontent_PollContentViewCreator_Day_0_en.png b/tests/uitests/src/test/snapshots/images/features.poll.api.pollcontent_PollContentViewCreator_Day_0_en.png index 635b871722..2d0a6aa749 100644 --- a/tests/uitests/src/test/snapshots/images/features.poll.api.pollcontent_PollContentViewCreator_Day_0_en.png +++ b/tests/uitests/src/test/snapshots/images/features.poll.api.pollcontent_PollContentViewCreator_Day_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:c98ae539d549ef2ece48d6f7dab5525889a237947af17e79c68e8d2490fd7bfb -size 49371 +oid sha256:37695b5ff4b53d50c0d2b278f9a41f961a98a2e9fed25ed239914963c3387314 +size 49142 diff --git a/tests/uitests/src/test/snapshots/images/features.poll.api.pollcontent_PollContentViewCreator_Night_0_en.png b/tests/uitests/src/test/snapshots/images/features.poll.api.pollcontent_PollContentViewCreator_Night_0_en.png index d078b0dcfe..11cfce1e3b 100644 --- a/tests/uitests/src/test/snapshots/images/features.poll.api.pollcontent_PollContentViewCreator_Night_0_en.png +++ b/tests/uitests/src/test/snapshots/images/features.poll.api.pollcontent_PollContentViewCreator_Night_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:bea1dc185eb3324df0a7a3bc2afec44e922a08492f0ebea394bdcfd949dab57e -size 48143 +oid sha256:7f2e4dd94801ee28848ed04bf3c4846631359873e150e433a397c305b0a33dde +size 47887 diff --git a/tests/uitests/src/test/snapshots/images/features.poll.api.pollcontent_PollContentViewDisclosed_Day_0_en.png b/tests/uitests/src/test/snapshots/images/features.poll.api.pollcontent_PollContentViewDisclosed_Day_0_en.png index 1713eec87a..47722c0807 100644 --- a/tests/uitests/src/test/snapshots/images/features.poll.api.pollcontent_PollContentViewDisclosed_Day_0_en.png +++ b/tests/uitests/src/test/snapshots/images/features.poll.api.pollcontent_PollContentViewDisclosed_Day_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:c319670ffe1f12885625bd03c83979e8657f61675393aaa943e756f2a052b465 -size 47105 +oid sha256:0db7953caa01f68e2e9b182b58cdd4d02bdf6912ddae64a36fec0636092575b6 +size 46825 diff --git a/tests/uitests/src/test/snapshots/images/features.poll.api.pollcontent_PollContentViewDisclosed_Night_0_en.png b/tests/uitests/src/test/snapshots/images/features.poll.api.pollcontent_PollContentViewDisclosed_Night_0_en.png index b74c2d0998..94e34de7a1 100644 --- a/tests/uitests/src/test/snapshots/images/features.poll.api.pollcontent_PollContentViewDisclosed_Night_0_en.png +++ b/tests/uitests/src/test/snapshots/images/features.poll.api.pollcontent_PollContentViewDisclosed_Night_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:62cf5c40a74693f2596535870e97a1d884b7abd7f602861f5d16cec11de45c1d -size 45948 +oid sha256:ba9520116a974c22c709fec9b90f7053664a4938e6a96f3b21fe340717c33a54 +size 45692 diff --git a/tests/uitests/src/test/snapshots/images/features.poll.api.pollcontent_PollContentViewEnded_Day_0_en.png b/tests/uitests/src/test/snapshots/images/features.poll.api.pollcontent_PollContentViewEnded_Day_0_en.png index d4853bda91..374113b566 100644 --- a/tests/uitests/src/test/snapshots/images/features.poll.api.pollcontent_PollContentViewEnded_Day_0_en.png +++ b/tests/uitests/src/test/snapshots/images/features.poll.api.pollcontent_PollContentViewEnded_Day_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:1a33919bf3b6936a05cab67554ae9bfefc15d7e731b81526c90f9cd072be8204 -size 47512 +oid sha256:7d4d192e27e8f705f1049e63e6cd9759830526e43132502033fd198d9216346a +size 47244 diff --git a/tests/uitests/src/test/snapshots/images/features.poll.api.pollcontent_PollContentViewEnded_Night_0_en.png b/tests/uitests/src/test/snapshots/images/features.poll.api.pollcontent_PollContentViewEnded_Night_0_en.png index 38ed7482a5..53fea58d96 100644 --- a/tests/uitests/src/test/snapshots/images/features.poll.api.pollcontent_PollContentViewEnded_Night_0_en.png +++ b/tests/uitests/src/test/snapshots/images/features.poll.api.pollcontent_PollContentViewEnded_Night_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:467953c093f401d388528805530769ea8c224d8692c0bc6ab81a23a0c48d0e8d -size 46126 +oid sha256:58b7377a27c180c531168e48819e903554f1d85525626ab4b6d79dab7f322c43 +size 45889 diff --git a/tests/uitests/src/test/snapshots/images/features.poll.api.pollcontent_PollContentViewUndisclosed_Day_0_en.png b/tests/uitests/src/test/snapshots/images/features.poll.api.pollcontent_PollContentViewUndisclosed_Day_0_en.png index c9607e1328..b3845a0dff 100644 --- a/tests/uitests/src/test/snapshots/images/features.poll.api.pollcontent_PollContentViewUndisclosed_Day_0_en.png +++ b/tests/uitests/src/test/snapshots/images/features.poll.api.pollcontent_PollContentViewUndisclosed_Day_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:3cd3f2023425aebe2e0d74b8e2e52b8f59c3d36d8f9dd193e9ee573c24b80bfb -size 44903 +oid sha256:87f388477415d917cbba86ad6c9a4439f75b129fd8586e81362f14a1d5270337 +size 44705 diff --git a/tests/uitests/src/test/snapshots/images/features.poll.api.pollcontent_PollContentViewUndisclosed_Night_0_en.png b/tests/uitests/src/test/snapshots/images/features.poll.api.pollcontent_PollContentViewUndisclosed_Night_0_en.png index b2e9409371..dc2b993507 100644 --- a/tests/uitests/src/test/snapshots/images/features.poll.api.pollcontent_PollContentViewUndisclosed_Night_0_en.png +++ b/tests/uitests/src/test/snapshots/images/features.poll.api.pollcontent_PollContentViewUndisclosed_Night_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:26f6c5cb1b6b09ea8a520e2c39c9e545be7c5e11839cb0f6b558948166d5b5d8 -size 43436 +oid sha256:a5fff6d8fc2f673d9a8de5f93dcabb84249c9db6badaff560f3ee2d74195981a +size 43239 diff --git a/tests/uitests/src/test/snapshots/images/features.poll.impl.history_PollHistoryView_Day_0_en.png b/tests/uitests/src/test/snapshots/images/features.poll.impl.history_PollHistoryView_Day_0_en.png index ce714bad3f..ac5893ce75 100644 --- a/tests/uitests/src/test/snapshots/images/features.poll.impl.history_PollHistoryView_Day_0_en.png +++ b/tests/uitests/src/test/snapshots/images/features.poll.impl.history_PollHistoryView_Day_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:fe511f10181ec9c56a7b2fbc284abfa87299f2d6bbaa61339acd6bf8a38bcb23 -size 57450 +oid sha256:da5c63531826c6f691b5d305cfef633421d6a8ca1dd112876c0e731e7989f20b +size 57145 diff --git a/tests/uitests/src/test/snapshots/images/features.poll.impl.history_PollHistoryView_Day_1_en.png b/tests/uitests/src/test/snapshots/images/features.poll.impl.history_PollHistoryView_Day_1_en.png index 7bae89aef5..533591f3d0 100644 --- a/tests/uitests/src/test/snapshots/images/features.poll.impl.history_PollHistoryView_Day_1_en.png +++ b/tests/uitests/src/test/snapshots/images/features.poll.impl.history_PollHistoryView_Day_1_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:67f1442e1bc22eab1be8dcd232dc0212494a0b0c68f29b64baf2bb142b037c80 -size 61270 +oid sha256:9946e1797e8470c7ad2525d64c696231b9a2eff203a92da77f395ebf47265b98 +size 60975 diff --git a/tests/uitests/src/test/snapshots/images/features.poll.impl.history_PollHistoryView_Night_0_en.png b/tests/uitests/src/test/snapshots/images/features.poll.impl.history_PollHistoryView_Night_0_en.png index a23fe258bc..cd0cb25645 100644 --- a/tests/uitests/src/test/snapshots/images/features.poll.impl.history_PollHistoryView_Night_0_en.png +++ b/tests/uitests/src/test/snapshots/images/features.poll.impl.history_PollHistoryView_Night_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:2bc6228d08938f793a505a8c3ab67cca036a4596f04f0ceb2abbb913117bf32d -size 55737 +oid sha256:8796b64a1159a5dab48640eb431a81324e3cfbe3ec16530e3e011ef3d1e66297 +size 55447 diff --git a/tests/uitests/src/test/snapshots/images/features.poll.impl.history_PollHistoryView_Night_1_en.png b/tests/uitests/src/test/snapshots/images/features.poll.impl.history_PollHistoryView_Night_1_en.png index cc7f7878e4..ccdf930f43 100644 --- a/tests/uitests/src/test/snapshots/images/features.poll.impl.history_PollHistoryView_Night_1_en.png +++ b/tests/uitests/src/test/snapshots/images/features.poll.impl.history_PollHistoryView_Night_1_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:2d090bf0b426d2aab896caec7dc6a51be37df3cd464cbce3447e641cbf922b32 -size 59501 +oid sha256:33a2ce240c280320741fab065d97bf5d04f70143c0c3b0515711685258f75ea9 +size 59221 diff --git a/tests/uitests/src/test/snapshots/images/features.roomdetails.impl.members_RoomMemberListViewBanned_Day_1_en.png b/tests/uitests/src/test/snapshots/images/features.roomdetails.impl.members_RoomMemberListViewBanned_Day_1_en.png index 10c82df294..0c9549e7ec 100644 --- a/tests/uitests/src/test/snapshots/images/features.roomdetails.impl.members_RoomMemberListViewBanned_Day_1_en.png +++ b/tests/uitests/src/test/snapshots/images/features.roomdetails.impl.members_RoomMemberListViewBanned_Day_1_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:858ed6bf83404f532a1ff258837ccef1fae650401d23dc5aaaf59c6dcefa7618 -size 33112 +oid sha256:726bf0c0beae74cfecd3c813335de763687642baf87c77d81d93ed9c9e536f0a +size 33028 diff --git a/tests/uitests/src/test/snapshots/images/features.roomdetails.impl.members_RoomMemberListViewBanned_Night_1_en.png b/tests/uitests/src/test/snapshots/images/features.roomdetails.impl.members_RoomMemberListViewBanned_Night_1_en.png index 63899b0d93..c05799f818 100644 --- a/tests/uitests/src/test/snapshots/images/features.roomdetails.impl.members_RoomMemberListViewBanned_Night_1_en.png +++ b/tests/uitests/src/test/snapshots/images/features.roomdetails.impl.members_RoomMemberListViewBanned_Night_1_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:03d537d678449cc51c47d8ba6b10af12d2afd5a259e4bbea4747e2462977e054 -size 32505 +oid sha256:d71db0947e09666739ca5e3c01a7c6b711a430d2a40e00cb55cd474cb42535c9 +size 32417 diff --git a/tests/uitests/src/test/snapshots/images/features.roomdetails.impl.members_RoomMemberListView_Day_1_en.png b/tests/uitests/src/test/snapshots/images/features.roomdetails.impl.members_RoomMemberListView_Day_1_en.png index 166e5e8f37..64ecba6dde 100644 --- a/tests/uitests/src/test/snapshots/images/features.roomdetails.impl.members_RoomMemberListView_Day_1_en.png +++ b/tests/uitests/src/test/snapshots/images/features.roomdetails.impl.members_RoomMemberListView_Day_1_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:7cd3c371ab57cf0a7ec16aa654c81b8f51c41307d9754a93a6cc3e31dcfacbb5 -size 11975 +oid sha256:9f01dff35fb317a29f898879c6a7bda6b23ecc2daaaebe80abfc089b448f99a1 +size 11891 diff --git a/tests/uitests/src/test/snapshots/images/features.roomdetails.impl.members_RoomMemberListView_Day_2_en.png b/tests/uitests/src/test/snapshots/images/features.roomdetails.impl.members_RoomMemberListView_Day_2_en.png index 1c02b115f0..64c0627f63 100644 --- a/tests/uitests/src/test/snapshots/images/features.roomdetails.impl.members_RoomMemberListView_Day_2_en.png +++ b/tests/uitests/src/test/snapshots/images/features.roomdetails.impl.members_RoomMemberListView_Day_2_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:a45ef2be8869629427e1cef559a0bf7f997f0dee452f440adbbf230caa709645 -size 12936 +oid sha256:a5197977035f27da4e4fb4d732ac52006d72b517261567d2efd6738a39270f22 +size 12849 diff --git a/tests/uitests/src/test/snapshots/images/features.roomdetails.impl.members_RoomMemberListView_Day_3_en.png b/tests/uitests/src/test/snapshots/images/features.roomdetails.impl.members_RoomMemberListView_Day_3_en.png index 166e5e8f37..64ecba6dde 100644 --- a/tests/uitests/src/test/snapshots/images/features.roomdetails.impl.members_RoomMemberListView_Day_3_en.png +++ b/tests/uitests/src/test/snapshots/images/features.roomdetails.impl.members_RoomMemberListView_Day_3_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:7cd3c371ab57cf0a7ec16aa654c81b8f51c41307d9754a93a6cc3e31dcfacbb5 -size 11975 +oid sha256:9f01dff35fb317a29f898879c6a7bda6b23ecc2daaaebe80abfc089b448f99a1 +size 11891 diff --git a/tests/uitests/src/test/snapshots/images/features.roomdetails.impl.members_RoomMemberListView_Night_1_en.png b/tests/uitests/src/test/snapshots/images/features.roomdetails.impl.members_RoomMemberListView_Night_1_en.png index 82ac8503af..fddbe32336 100644 --- a/tests/uitests/src/test/snapshots/images/features.roomdetails.impl.members_RoomMemberListView_Night_1_en.png +++ b/tests/uitests/src/test/snapshots/images/features.roomdetails.impl.members_RoomMemberListView_Night_1_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:84718c07de3b94fdd5978a93c35be6ded506ede2a416adf84302de19e664768b -size 11266 +oid sha256:0a0aedac7a6fb0ed7d178e98bbe546a7176c111953f8d02c107e92d4fbdb6a9b +size 11179 diff --git a/tests/uitests/src/test/snapshots/images/features.roomdetails.impl.members_RoomMemberListView_Night_2_en.png b/tests/uitests/src/test/snapshots/images/features.roomdetails.impl.members_RoomMemberListView_Night_2_en.png index adf6375108..7073c1fb27 100644 --- a/tests/uitests/src/test/snapshots/images/features.roomdetails.impl.members_RoomMemberListView_Night_2_en.png +++ b/tests/uitests/src/test/snapshots/images/features.roomdetails.impl.members_RoomMemberListView_Night_2_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:2d334828907b99fb9f047ef1636b87346079eb14027f577c65f3ffd0cdd4c1b8 -size 12149 +oid sha256:6138ec110a891f52f492d3377825708a7151d42d1f391a996ddc10a7f2624806 +size 12065 diff --git a/tests/uitests/src/test/snapshots/images/features.roomdetails.impl.members_RoomMemberListView_Night_3_en.png b/tests/uitests/src/test/snapshots/images/features.roomdetails.impl.members_RoomMemberListView_Night_3_en.png index 82ac8503af..fddbe32336 100644 --- a/tests/uitests/src/test/snapshots/images/features.roomdetails.impl.members_RoomMemberListView_Night_3_en.png +++ b/tests/uitests/src/test/snapshots/images/features.roomdetails.impl.members_RoomMemberListView_Night_3_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:84718c07de3b94fdd5978a93c35be6ded506ede2a416adf84302de19e664768b -size 11266 +oid sha256:0a0aedac7a6fb0ed7d178e98bbe546a7176c111953f8d02c107e92d4fbdb6a9b +size 11179 diff --git a/tests/uitests/src/test/snapshots/images/features.securebackup.impl.reset.root_ResetIdentityRootView_Day_0_en.png b/tests/uitests/src/test/snapshots/images/features.securebackup.impl.reset.root_ResetIdentityRootView_Day_0_en.png index 8deeaa73aa..207ef5d163 100644 --- a/tests/uitests/src/test/snapshots/images/features.securebackup.impl.reset.root_ResetIdentityRootView_Day_0_en.png +++ b/tests/uitests/src/test/snapshots/images/features.securebackup.impl.reset.root_ResetIdentityRootView_Day_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:ad503075a2ff0e5fcd544c66a1a1b186abc2d05126facc397e0d812cd2206fc5 -size 71628 +oid sha256:4a3d734e3d2a572344ab26b042cf249afc56c7eff2d1454565ddc75e54faaced +size 69147 diff --git a/tests/uitests/src/test/snapshots/images/features.securebackup.impl.reset.root_ResetIdentityRootView_Day_1_en.png b/tests/uitests/src/test/snapshots/images/features.securebackup.impl.reset.root_ResetIdentityRootView_Day_1_en.png index 2bfe4aa3f8..755be0c696 100644 --- a/tests/uitests/src/test/snapshots/images/features.securebackup.impl.reset.root_ResetIdentityRootView_Day_1_en.png +++ b/tests/uitests/src/test/snapshots/images/features.securebackup.impl.reset.root_ResetIdentityRootView_Day_1_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:669a2f51c4276c4582e624dda9779d008a01452f0f2a1331f9fbb2b7bbbb38de -size 58159 +oid sha256:0a41f758a358792131a03f7015710fe28c9e8fecb49cafa72fe4b0a0a21bbf9d +size 58206 diff --git a/tests/uitests/src/test/snapshots/images/features.securebackup.impl.reset.root_ResetIdentityRootView_Night_0_en.png b/tests/uitests/src/test/snapshots/images/features.securebackup.impl.reset.root_ResetIdentityRootView_Night_0_en.png index 34fab3c874..63c2e51c20 100644 --- a/tests/uitests/src/test/snapshots/images/features.securebackup.impl.reset.root_ResetIdentityRootView_Night_0_en.png +++ b/tests/uitests/src/test/snapshots/images/features.securebackup.impl.reset.root_ResetIdentityRootView_Night_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:9a8c8d8ed03e7f85a0954bd06ac70336994dfaaec318c1d7f2c386f062e6c1e9 -size 70136 +oid sha256:676c85998a4b76894de1cbf470e18876abc791cc56a8322db9e1d24e32adfd56 +size 67963 diff --git a/tests/uitests/src/test/snapshots/images/features.securebackup.impl.reset.root_ResetIdentityRootView_Night_1_en.png b/tests/uitests/src/test/snapshots/images/features.securebackup.impl.reset.root_ResetIdentityRootView_Night_1_en.png index 8d0e213225..6def117bd5 100644 --- a/tests/uitests/src/test/snapshots/images/features.securebackup.impl.reset.root_ResetIdentityRootView_Night_1_en.png +++ b/tests/uitests/src/test/snapshots/images/features.securebackup.impl.reset.root_ResetIdentityRootView_Night_1_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:d2ffe911b13cbedf16829ed0b449f291d291f64d87917b827836a97204fe8c65 -size 56167 +oid sha256:a3f8388e77e222255f9bcd04c81094a88d57176f588feb476146035f56c0054c +size 56116 diff --git a/tests/uitests/src/test/snapshots/images/features.verifysession.impl_VerifySelfSessionView_Day_0_en.png b/tests/uitests/src/test/snapshots/images/features.verifysession.impl_VerifySelfSessionView_Day_0_en.png index a9e9a08cb0..1f400226c9 100644 --- a/tests/uitests/src/test/snapshots/images/features.verifysession.impl_VerifySelfSessionView_Day_0_en.png +++ b/tests/uitests/src/test/snapshots/images/features.verifysession.impl_VerifySelfSessionView_Day_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:e9513b48683bec56a8892bcc4f953117547bc570acd20dda760fb60904532449 -size 31501 +oid sha256:ea4aeceb9e0d72642c9be0d8dd1abc7a3b82bd05ce05a07aa95bec4e0b2a9df0 +size 34612 diff --git a/tests/uitests/src/test/snapshots/images/features.verifysession.impl_VerifySelfSessionView_Day_10_en.png b/tests/uitests/src/test/snapshots/images/features.verifysession.impl_VerifySelfSessionView_Day_10_en.png index 6886d562a6..cb409b37ee 100644 --- a/tests/uitests/src/test/snapshots/images/features.verifysession.impl_VerifySelfSessionView_Day_10_en.png +++ b/tests/uitests/src/test/snapshots/images/features.verifysession.impl_VerifySelfSessionView_Day_10_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:4e5ecf84200d3c3f1e213552568bb8c1893975403363bfe9856414208ff7d84b -size 32678 +oid sha256:4a6896e2fc99b34d37dbc7494c21990d31aa6fb99500d61764b7d04afcffca74 +size 33690 diff --git a/tests/uitests/src/test/snapshots/images/features.verifysession.impl_VerifySelfSessionView_Day_7_en.png b/tests/uitests/src/test/snapshots/images/features.verifysession.impl_VerifySelfSessionView_Day_7_en.png index a9e9a08cb0..1f400226c9 100644 --- a/tests/uitests/src/test/snapshots/images/features.verifysession.impl_VerifySelfSessionView_Day_7_en.png +++ b/tests/uitests/src/test/snapshots/images/features.verifysession.impl_VerifySelfSessionView_Day_7_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:e9513b48683bec56a8892bcc4f953117547bc570acd20dda760fb60904532449 -size 31501 +oid sha256:ea4aeceb9e0d72642c9be0d8dd1abc7a3b82bd05ce05a07aa95bec4e0b2a9df0 +size 34612 diff --git a/tests/uitests/src/test/snapshots/images/features.verifysession.impl_VerifySelfSessionView_Day_8_en.png b/tests/uitests/src/test/snapshots/images/features.verifysession.impl_VerifySelfSessionView_Day_8_en.png index f4e3c9cccc..1adae97357 100644 --- a/tests/uitests/src/test/snapshots/images/features.verifysession.impl_VerifySelfSessionView_Day_8_en.png +++ b/tests/uitests/src/test/snapshots/images/features.verifysession.impl_VerifySelfSessionView_Day_8_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:05f503995e71fd66a03efc1b675eacf3bf4f90d1b07e73e171ebb78014862ed6 -size 26020 +oid sha256:84627a80338301f58e1fc877a587ff602c86dff848684d9ba56a49dde4bf2d9d +size 29801 diff --git a/tests/uitests/src/test/snapshots/images/features.verifysession.impl_VerifySelfSessionView_Night_0_en.png b/tests/uitests/src/test/snapshots/images/features.verifysession.impl_VerifySelfSessionView_Night_0_en.png index 6e064ec573..8ef345dda6 100644 --- a/tests/uitests/src/test/snapshots/images/features.verifysession.impl_VerifySelfSessionView_Night_0_en.png +++ b/tests/uitests/src/test/snapshots/images/features.verifysession.impl_VerifySelfSessionView_Night_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:8ed7b8e3bdda766f21419bec8f60497b3e4d18f54ec41a65160be363e165073b -size 30567 +oid sha256:70adb44af338740cbc2f2297ca172d35563133d163bcfafbfe09295a4aa644c8 +size 33568 diff --git a/tests/uitests/src/test/snapshots/images/features.verifysession.impl_VerifySelfSessionView_Night_10_en.png b/tests/uitests/src/test/snapshots/images/features.verifysession.impl_VerifySelfSessionView_Night_10_en.png index a45cc3dd48..349bd5a1dd 100644 --- a/tests/uitests/src/test/snapshots/images/features.verifysession.impl_VerifySelfSessionView_Night_10_en.png +++ b/tests/uitests/src/test/snapshots/images/features.verifysession.impl_VerifySelfSessionView_Night_10_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:f633d654de29a28d32308039e9b78b72da948de605fcecf4b61ba3aab6068866 -size 31180 +oid sha256:2cb5f4af03cdab9e432b790c8f5346358659d7338f1aecc6449f816b765d3b36 +size 32191 diff --git a/tests/uitests/src/test/snapshots/images/features.verifysession.impl_VerifySelfSessionView_Night_7_en.png b/tests/uitests/src/test/snapshots/images/features.verifysession.impl_VerifySelfSessionView_Night_7_en.png index 6e064ec573..8ef345dda6 100644 --- a/tests/uitests/src/test/snapshots/images/features.verifysession.impl_VerifySelfSessionView_Night_7_en.png +++ b/tests/uitests/src/test/snapshots/images/features.verifysession.impl_VerifySelfSessionView_Night_7_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:8ed7b8e3bdda766f21419bec8f60497b3e4d18f54ec41a65160be363e165073b -size 30567 +oid sha256:70adb44af338740cbc2f2297ca172d35563133d163bcfafbfe09295a4aa644c8 +size 33568 diff --git a/tests/uitests/src/test/snapshots/images/features.verifysession.impl_VerifySelfSessionView_Night_8_en.png b/tests/uitests/src/test/snapshots/images/features.verifysession.impl_VerifySelfSessionView_Night_8_en.png index 913427e07b..c576a7f580 100644 --- a/tests/uitests/src/test/snapshots/images/features.verifysession.impl_VerifySelfSessionView_Night_8_en.png +++ b/tests/uitests/src/test/snapshots/images/features.verifysession.impl_VerifySelfSessionView_Night_8_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:72d7a54da8502a7e70d0e6b1bcf8c6e2e0d2e78d328f73b7edacec58a2bf99b2 -size 25377 +oid sha256:65709ff3ec7a5a495370dfc58cdec1898d07e0f6eea8b41caa1ae40579fce817 +size 28896 diff --git a/tests/uitests/src/test/snapshots/images/libraries.designsystem.theme.components_LinearProgressIndicator_Progress Indicators_en.png b/tests/uitests/src/test/snapshots/images/libraries.designsystem.theme.components_LinearProgressIndicator_Progress Indicators_en.png index 7bda781f02..4653a6d9c6 100644 --- a/tests/uitests/src/test/snapshots/images/libraries.designsystem.theme.components_LinearProgressIndicator_Progress Indicators_en.png +++ b/tests/uitests/src/test/snapshots/images/libraries.designsystem.theme.components_LinearProgressIndicator_Progress Indicators_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:33ac700ed52cf80b0be545593964522486eb1160123a9258471e7732ef9a47ed -size 4931 +oid sha256:b85763d04fea3acd3861ca1134a7741cb7232b992ae834de808664ab29a148ce +size 4626 diff --git a/tests/uitests/src/test/snapshots/images/libraries.matrix.ui.components_SelectedRoom_Day_0_en.png b/tests/uitests/src/test/snapshots/images/libraries.matrix.ui.components_SelectedRoom_Day_0_en.png index f9218b3c49..77aac9c808 100644 --- a/tests/uitests/src/test/snapshots/images/libraries.matrix.ui.components_SelectedRoom_Day_0_en.png +++ b/tests/uitests/src/test/snapshots/images/libraries.matrix.ui.components_SelectedRoom_Day_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:b6dbc970789b59a9bc7db1257a6c60b9b33b7eb7747a30482802659303582323 -size 7340 +oid sha256:cbae54843c22fdcb012d926191bc01e638ba38dc55eb4b24c9e3ad9e9a9d103a +size 6807 diff --git a/tests/uitests/src/test/snapshots/images/libraries.matrix.ui.components_SelectedRoom_Day_1_en.png b/tests/uitests/src/test/snapshots/images/libraries.matrix.ui.components_SelectedRoom_Day_1_en.png index f5560ca34e..bec8cbbc61 100644 --- a/tests/uitests/src/test/snapshots/images/libraries.matrix.ui.components_SelectedRoom_Day_1_en.png +++ b/tests/uitests/src/test/snapshots/images/libraries.matrix.ui.components_SelectedRoom_Day_1_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:42e59e3add65ddc468cb23d9b2bfd460d39c37b72a09deb12298a0bb28d362dc -size 6752 +oid sha256:764de9f67cabfe22be6ad3021a8418d3677f709fce95c019cd66820e66359980 +size 7804 diff --git a/tests/uitests/src/test/snapshots/images/libraries.matrix.ui.components_SelectedRoom_Day_2_en.png b/tests/uitests/src/test/snapshots/images/libraries.matrix.ui.components_SelectedRoom_Day_2_en.png new file mode 100644 index 0000000000..01208664c2 --- /dev/null +++ b/tests/uitests/src/test/snapshots/images/libraries.matrix.ui.components_SelectedRoom_Day_2_en.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:ecdfbc386e865be164e34ef963330be1c8548e8d3a505f64321d6496a072896b +size 7670 diff --git a/tests/uitests/src/test/snapshots/images/libraries.matrix.ui.components_SelectedRoom_Night_0_en.png b/tests/uitests/src/test/snapshots/images/libraries.matrix.ui.components_SelectedRoom_Night_0_en.png index 141ed9fc81..5a1da9c3a2 100644 --- a/tests/uitests/src/test/snapshots/images/libraries.matrix.ui.components_SelectedRoom_Night_0_en.png +++ b/tests/uitests/src/test/snapshots/images/libraries.matrix.ui.components_SelectedRoom_Night_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:bcbb1951463a29e167d3ae09be263461bb449ca8677229fe00f18b6a60c8c31d -size 7535 +oid sha256:428c291e304d9f2c25658569a8ecf324eafccf4b63b31897727dda8151289d05 +size 7040 diff --git a/tests/uitests/src/test/snapshots/images/libraries.matrix.ui.components_SelectedRoom_Night_1_en.png b/tests/uitests/src/test/snapshots/images/libraries.matrix.ui.components_SelectedRoom_Night_1_en.png index d13d6225c8..37ec525c79 100644 --- a/tests/uitests/src/test/snapshots/images/libraries.matrix.ui.components_SelectedRoom_Night_1_en.png +++ b/tests/uitests/src/test/snapshots/images/libraries.matrix.ui.components_SelectedRoom_Night_1_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:3118842f8b80ab4ffdcfbd8124cebaf536d131700d884ec06aa6b19ce22f742c -size 6954 +oid sha256:345cb5d50b201e957be4aaed8b2ac785cd4dfc795924e28ba45015b62bb0d1d7 +size 7707 diff --git a/tests/uitests/src/test/snapshots/images/libraries.matrix.ui.components_SelectedRoom_Night_2_en.png b/tests/uitests/src/test/snapshots/images/libraries.matrix.ui.components_SelectedRoom_Night_2_en.png new file mode 100644 index 0000000000..617a9fdeba --- /dev/null +++ b/tests/uitests/src/test/snapshots/images/libraries.matrix.ui.components_SelectedRoom_Night_2_en.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:d0ba819713f7d3bdc667481726af1e60366a30c62148893f2eef5e503c5e1df0 +size 7827 diff --git a/tests/uitests/src/test/snapshots/images/libraries.roomselect.impl_RoomSelectView_Day_2_en.png b/tests/uitests/src/test/snapshots/images/libraries.roomselect.impl_RoomSelectView_Day_2_en.png index 0a71dbf5f1..0e22f34d88 100644 --- a/tests/uitests/src/test/snapshots/images/libraries.roomselect.impl_RoomSelectView_Day_2_en.png +++ b/tests/uitests/src/test/snapshots/images/libraries.roomselect.impl_RoomSelectView_Day_2_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:f7e19544c7a255dc1c52f69c1387966a806ffca809f6ad071b9bc501c86a9577 -size 30327 +oid sha256:0db3f0cdb53eb761bf3742ce94f925472a7e1b48b306d2cd81baa2c42bee6a14 +size 31142 diff --git a/tests/uitests/src/test/snapshots/images/libraries.roomselect.impl_RoomSelectView_Day_3_en.png b/tests/uitests/src/test/snapshots/images/libraries.roomselect.impl_RoomSelectView_Day_3_en.png index 6ab3bff9e8..6d265d0892 100644 --- a/tests/uitests/src/test/snapshots/images/libraries.roomselect.impl_RoomSelectView_Day_3_en.png +++ b/tests/uitests/src/test/snapshots/images/libraries.roomselect.impl_RoomSelectView_Day_3_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:a417fb437c823b44a62a4e59be87f44425de32ad347115d800f74d4d2db98ecc -size 28361 +oid sha256:d1a17ed95a976a813b541eb373e2eb1f50388f6a994da7b65a586d31be8e0d23 +size 29199 diff --git a/tests/uitests/src/test/snapshots/images/libraries.roomselect.impl_RoomSelectView_Day_4_en.png b/tests/uitests/src/test/snapshots/images/libraries.roomselect.impl_RoomSelectView_Day_4_en.png index 97e40ee187..a90769134c 100644 --- a/tests/uitests/src/test/snapshots/images/libraries.roomselect.impl_RoomSelectView_Day_4_en.png +++ b/tests/uitests/src/test/snapshots/images/libraries.roomselect.impl_RoomSelectView_Day_4_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:207aa1698d4b851d6c3b97cd99ade7499abb1882c5d8a6450c83de596430a448 -size 32767 +oid sha256:1d5390b71350b1029a153c770f1e525c6346052043583fad2b3c4aadfb694b16 +size 33441 diff --git a/tests/uitests/src/test/snapshots/images/libraries.roomselect.impl_RoomSelectView_Day_5_en.png b/tests/uitests/src/test/snapshots/images/libraries.roomselect.impl_RoomSelectView_Day_5_en.png index ebb64178ab..6411138939 100644 --- a/tests/uitests/src/test/snapshots/images/libraries.roomselect.impl_RoomSelectView_Day_5_en.png +++ b/tests/uitests/src/test/snapshots/images/libraries.roomselect.impl_RoomSelectView_Day_5_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:d8278dba6831714c5f27c8389e4dc048c6d20404bd679e888891c2053baac351 -size 27995 +oid sha256:5aa120484502f3ed14e33a7460b19bd090ac421bbb383e75127bbdf3f54f5ca3 +size 28818 diff --git a/tests/uitests/src/test/snapshots/images/libraries.roomselect.impl_RoomSelectView_Night_2_en.png b/tests/uitests/src/test/snapshots/images/libraries.roomselect.impl_RoomSelectView_Night_2_en.png index 37f74b70b4..451df5a6bd 100644 --- a/tests/uitests/src/test/snapshots/images/libraries.roomselect.impl_RoomSelectView_Night_2_en.png +++ b/tests/uitests/src/test/snapshots/images/libraries.roomselect.impl_RoomSelectView_Night_2_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:d89466ad2d6274b2def2b1354862490445bedc0d02e73aec8e9bd1fa77d7133c -size 29405 +oid sha256:646bf7110d66643fda586c2ecd54b78f09111d0e74a531a7c1fa08e968b1abc3 +size 30217 diff --git a/tests/uitests/src/test/snapshots/images/libraries.roomselect.impl_RoomSelectView_Night_3_en.png b/tests/uitests/src/test/snapshots/images/libraries.roomselect.impl_RoomSelectView_Night_3_en.png index af53f31764..4ef4a97357 100644 --- a/tests/uitests/src/test/snapshots/images/libraries.roomselect.impl_RoomSelectView_Night_3_en.png +++ b/tests/uitests/src/test/snapshots/images/libraries.roomselect.impl_RoomSelectView_Night_3_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:8bd095f282b4c40bf7f74a3487bcf3bcbea0b2c0f352f9e02400ee6312d75ed6 -size 27953 +oid sha256:594841dd922deceeee60da8bdd7228f9c685f2aa700a2ccbe0dd03bd4b9e4b98 +size 28739 diff --git a/tests/uitests/src/test/snapshots/images/libraries.roomselect.impl_RoomSelectView_Night_4_en.png b/tests/uitests/src/test/snapshots/images/libraries.roomselect.impl_RoomSelectView_Night_4_en.png index d7f4f85e88..de422e8d4c 100644 --- a/tests/uitests/src/test/snapshots/images/libraries.roomselect.impl_RoomSelectView_Night_4_en.png +++ b/tests/uitests/src/test/snapshots/images/libraries.roomselect.impl_RoomSelectView_Night_4_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:6bd6844fb58ba85693bcf3b1c443fc585c09ed410054d7c127e477527a5aed49 -size 32131 +oid sha256:6fddc7151694a9622baf4daf5387c47266f1bae4ba0a50bd7ee4435eb403a375 +size 33088 diff --git a/tests/uitests/src/test/snapshots/images/libraries.roomselect.impl_RoomSelectView_Night_5_en.png b/tests/uitests/src/test/snapshots/images/libraries.roomselect.impl_RoomSelectView_Night_5_en.png index ea3268f523..f19ea6f743 100644 --- a/tests/uitests/src/test/snapshots/images/libraries.roomselect.impl_RoomSelectView_Night_5_en.png +++ b/tests/uitests/src/test/snapshots/images/libraries.roomselect.impl_RoomSelectView_Night_5_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:728d0e42d5e07b3fd47b8cf3f415f945fadc606de425dc0b1b2f65750a1c5e34 -size 27059 +oid sha256:8c44fadbdeb27169f88a2678ab8b6db9ac7a9f6b21871a436d14728eec398daf +size 27883 diff --git a/tools/detekt/detekt.yml b/tools/detekt/detekt.yml index 263b2e9683..1e73ef425d 100644 --- a/tools/detekt/detekt.yml +++ b/tools/detekt/detekt.yml @@ -3,7 +3,7 @@ style: AlsoCouldBeApply: active: true - OptionalWhenBraces: + BracesOnWhenStatements: active: false CascadingCallWrapping: active: true diff --git a/tools/lint/lint.xml b/tools/lint/lint.xml index 57b2ab0750..6596246383 100644 --- a/tools/lint/lint.xml +++ b/tools/lint/lint.xml @@ -117,4 +117,9 @@ + + + + +