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