diff --git a/.gitignore b/.gitignore
index e3fcb2ef13..e1b1c5c8ab 100644
--- a/.gitignore
+++ b/.gitignore
@@ -62,6 +62,7 @@ captures/
# Android Studio 3 in .gitignore file.
.idea/caches
.idea/copilot
+.idea/copilot.*
.idea/inspectionProfiles
# Shelved changes in the IDE
.idea/shelf
diff --git a/CHANGES.md b/CHANGES.md
index 93f947f3f7..5377aedff1 100644
--- a/CHANGES.md
+++ b/CHANGES.md
@@ -1,3 +1,61 @@
+Changes in Element X v25.09.1
+=============================
+
+## What's Changed
+
+We have migrated our DI libraries from Dagger and Anvil to Metro. If you need more details on the migration steps, please read the [documentation](https://github.com/element-hq/element-x-android/blob/develop/docs/migration_to_metro.md).
+
+### ✨ Features
+* Allow replying to a message with an attachment by @jmartinesp in https://github.com/element-hq/element-x-android/pull/5261
+* Add emoji search to the reaction emoji picker by @jmartinesp in https://github.com/element-hq/element-x-android/pull/5255
+### 🙌 Improvements
+* Spelling correction in Update FeatureFlags.kt by @escix in https://github.com/element-hq/element-x-android/pull/5232
+* [a11y] Add content descriptions to room list item indicators by @jmartinesp in https://github.com/element-hq/element-x-android/pull/5236
+* [a11y] Add click action to the message bottom sheet handle by @jmartinesp in https://github.com/element-hq/element-x-android/pull/5228
+### 🐛 Bugfixes
+* Reload member list after moderation actions by @jmartinesp in https://github.com/element-hq/element-x-android/pull/5268
+* Restore view log code by @bmarty in https://github.com/element-hq/element-x-android/pull/5294
+* Detect mime type when picking a file by @bmarty in https://github.com/element-hq/element-x-android/pull/5291
+### 🗣 Translations
+* Sync Strings by @ElementBot in https://github.com/element-hq/element-x-android/pull/5249
+* Sync Strings - new translations to Korean by @ElementBot in https://github.com/element-hq/element-x-android/pull/5286
+* Sync Strings by @ElementBot in https://github.com/element-hq/element-x-android/pull/5290
+### 🧱 Build
+* Iterate on build chain by @bmarty in https://github.com/element-hq/element-x-android/pull/5272
+* Cleanup our DI solution and add documentation about the migration to Metro by @bmarty in https://github.com/element-hq/element-x-android/pull/5287
+* Revert agp to 8.11 by @bmarty in https://github.com/element-hq/element-x-android/pull/5311
+### 🚧 In development 🚧
+* Space: add content in home screen by @bmarty in https://github.com/element-hq/element-x-android/pull/5273
+* Hide the home navigation bar if the user is not a member of any Space. by @bmarty in https://github.com/element-hq/element-x-android/pull/5292
+### Dependency upgrades
+* Update dependency org.maplibre.gl:android-sdk to v11.13.1 by @renovate[bot] in https://github.com/element-hq/element-x-android/pull/5239
+* Update dependency com.google.firebase:firebase-bom to v34.2.0 by @renovate[bot] in https://github.com/element-hq/element-x-android/pull/5245
+* Update dependency com.posthog:posthog-android to v3.21.0 by @renovate[bot] in https://github.com/element-hq/element-x-android/pull/5238
+* Update dependency org.matrix.rustcomponents:sdk-android to v25.9.1 by @renovate[bot] in https://github.com/element-hq/element-x-android/pull/5251
+* Update plugin sonarqube to v6.3.1.5724 by @renovate[bot] in https://github.com/element-hq/element-x-android/pull/5235
+* Update android.gradle.plugin to v8.12.2 by @renovate[bot] in https://github.com/element-hq/element-x-android/pull/5244
+* Update dependency io.element.android:emojibase-bindings to v1.4.3 by @renovate[bot] in https://github.com/element-hq/element-x-android/pull/5250
+* Update actions/setup-python action to v6 by @renovate[bot] in https://github.com/element-hq/element-x-android/pull/5270
+* Update dependency com.posthog:posthog-android to v3.21.1 by @renovate[bot] in https://github.com/element-hq/element-x-android/pull/5275
+* Migrate Anvil KSP to Metro by @jmartinesp in https://github.com/element-hq/element-x-android/pull/5253
+* Update actions/github-script action to v8 by @renovate[bot] in https://github.com/element-hq/element-x-android/pull/5284
+* Update codecov/codecov-action action to v5.5.1 by @renovate[bot] in https://github.com/element-hq/element-x-android/pull/5274
+* Update dependency io.sentry:sentry-android to v8.21.0 by @renovate[bot] in https://github.com/element-hq/element-x-android/pull/5293
+### Others
+* Remove LoginUserStory. by @bmarty in https://github.com/element-hq/element-x-android/pull/5237
+* Update state in runUpdatingState when CancellationException occurs by @jbrenorv in https://github.com/element-hq/element-x-android/pull/5243
+* Refactor: Move InMemorySessionStore to test module by @bmarty in https://github.com/element-hq/element-x-android/pull/5252
+* Enable `largeHeap` option to have a larger max heap size by @jmartinesp in https://github.com/element-hq/element-x-android/pull/5258
+* Set a custom request config for the Client by @jmartinesp in https://github.com/element-hq/element-x-android/pull/5266
+* Set shortcut ID on received notifications to make them appear as a Conversation by @frebib in https://github.com/element-hq/element-x-android/pull/5192
+* Improve management of shortcut ids. by @bmarty in https://github.com/element-hq/element-x-android/pull/5303
+
+## New Contributors
+* @escix made their first contribution in https://github.com/element-hq/element-x-android/pull/5232
+* @jbrenorv made their first contribution in https://github.com/element-hq/element-x-android/pull/5243
+
+**Full Changelog**: https://github.com/element-hq/element-x-android/compare/v25.09.0...v25.09.1
+
Changes in Element X v25.09.0
=============================
diff --git a/app/build.gradle.kts b/app/build.gradle.kts
index 14203ec711..9be152e9e7 100644
--- a/app/build.gradle.kts
+++ b/app/build.gradle.kts
@@ -24,6 +24,7 @@ import extension.koverDependencies
import extension.locales
import extension.setupDependencyInjection
import extension.setupKover
+import extension.testCommonDependencies
import java.util.Locale
plugins {
@@ -290,15 +291,9 @@ dependencies {
implementation(libs.matrix.emojibase.bindings)
- testImplementation(libs.test.junit)
- testImplementation(libs.test.robolectric)
- testImplementation(libs.coroutines.test)
- testImplementation(libs.molecule.runtime)
- testImplementation(libs.test.truth)
- testImplementation(libs.test.turbine)
+ testCommonDependencies(libs)
testImplementation(projects.libraries.matrix.test)
testImplementation(projects.services.toolbox.test)
- testImplementation(projects.tests.testutils)
koverDependencies()
}
diff --git a/app/src/main/res/xml/locales_config.xml b/app/src/main/res/xml/locales_config.xml
index a92d7b2ef9..72a7d32cc0 100644
--- a/app/src/main/res/xml/locales_config.xml
+++ b/app/src/main/res/xml/locales_config.xml
@@ -9,6 +9,7 @@
+
diff --git a/appnav/build.gradle.kts b/appnav/build.gradle.kts
index 7c29626d75..3ea6f9d1c9 100644
--- a/appnav/build.gradle.kts
+++ b/appnav/build.gradle.kts
@@ -9,6 +9,7 @@
import extension.allFeaturesApi
import extension.setupDependencyInjection
+import extension.testCommonDependencies
plugins {
id("io.element.android-compose-library")
@@ -42,18 +43,12 @@ dependencies {
implementation(projects.features.ftue.api)
implementation(projects.features.share.api)
- implementation(projects.features.viewfolder.api)
implementation(projects.services.apperror.impl)
implementation(projects.services.appnavstate.api)
implementation(projects.services.analytics.api)
- testImplementation(libs.test.junit)
- testImplementation(libs.test.robolectric)
- testImplementation(libs.coroutines.test)
- testImplementation(libs.molecule.runtime)
- testImplementation(libs.test.truth)
- testImplementation(libs.test.turbine)
+ testCommonDependencies(libs)
testImplementation(projects.features.login.test)
testImplementation(projects.libraries.matrix.test)
testImplementation(projects.libraries.oidc.test)
@@ -61,11 +56,8 @@ dependencies {
testImplementation(projects.libraries.push.test)
testImplementation(projects.libraries.pushproviders.test)
testImplementation(projects.features.networkmonitor.test)
- testImplementation(projects.tests.testutils)
testImplementation(projects.features.rageshake.test)
testImplementation(projects.services.appnavstate.test)
testImplementation(projects.services.analytics.test)
testImplementation(projects.services.toolbox.test)
- testImplementation(libs.test.appyx.junit)
- testImplementation(libs.test.arch.core)
}
diff --git a/appnav/src/main/kotlin/io/element/android/appnav/LoggedInFlowNode.kt b/appnav/src/main/kotlin/io/element/android/appnav/LoggedInFlowNode.kt
index 2d08d5f6f5..fc4fcc3a7a 100644
--- a/appnav/src/main/kotlin/io/element/android/appnav/LoggedInFlowNode.kt
+++ b/appnav/src/main/kotlin/io/element/android/appnav/LoggedInFlowNode.kt
@@ -52,7 +52,6 @@ import io.element.android.features.ftue.api.FtueEntryPoint
import io.element.android.features.ftue.api.state.FtueService
import io.element.android.features.ftue.api.state.FtueState
import io.element.android.features.home.api.HomeEntryPoint
-import io.element.android.features.logout.api.LogoutEntryPoint
import io.element.android.features.networkmonitor.api.NetworkMonitor
import io.element.android.features.networkmonitor.api.NetworkStatus
import io.element.android.features.preferences.api.PreferencesEntryPoint
@@ -60,6 +59,7 @@ import io.element.android.features.roomdirectory.api.RoomDescription
import io.element.android.features.roomdirectory.api.RoomDirectoryEntryPoint
import io.element.android.features.securebackup.api.SecureBackupEntryPoint
import io.element.android.features.share.api.ShareEntryPoint
+import io.element.android.features.space.api.SpaceEntryPoint
import io.element.android.features.startchat.api.StartChatEntryPoint
import io.element.android.features.userprofile.api.UserProfileEntryPoint
import io.element.android.features.verifysession.api.IncomingVerificationEntryPoint
@@ -118,7 +118,6 @@ class LoggedInFlowNode(
private val shareEntryPoint: ShareEntryPoint,
private val matrixClient: MatrixClient,
private val sendingQueue: SendQueues,
- private val logoutEntryPoint: LogoutEntryPoint,
private val incomingVerificationEntryPoint: IncomingVerificationEntryPoint,
private val mediaPreviewConfigMigration: MediaPreviewConfigMigration,
private val sessionEnterpriseService: SessionEnterpriseService,
@@ -276,9 +275,6 @@ class LoggedInFlowNode(
@Parcelize
data class IncomingShare(val intent: Intent) : NavTarget
- @Parcelize
- data object LogoutForNativeSlidingSyncMigrationNeeded : NavTarget
-
@Parcelize
data class IncomingVerificationRequest(val data: VerificationRequest.Incoming) : NavTarget
}
@@ -323,10 +319,6 @@ class LoggedInFlowNode(
override fun onReportBugClick() {
plugins().forEach { it.onOpenBugReport() }
}
-
- override fun onLogoutForNativeSlidingSyncMigrationNeeded() {
- backstack.push(NavTarget.LogoutForNativeSlidingSyncMigrationNeeded)
- }
}
homeEntryPoint
.nodeBuilder(this, buildContext)
@@ -334,7 +326,7 @@ class LoggedInFlowNode(
.build()
}
is NavTarget.Room -> {
- val callback = object : JoinedRoomLoadedFlowNode.Callback {
+ val joinedRoomCallback = object : JoinedRoomLoadedFlowNode.Callback {
override fun onOpenRoom(roomId: RoomId, serverNames: List) {
backstack.push(NavTarget.Room(roomId.toRoomIdOrAlias(), serverNames))
}
@@ -373,6 +365,11 @@ class LoggedInFlowNode(
backstack.push(NavTarget.Settings(PreferencesEntryPoint.InitialTarget.NotificationSettings))
}
}
+ val spaceCallback = object : SpaceEntryPoint.Callback {
+ override fun onOpenRoom(roomId: RoomId) {
+ backstack.push(NavTarget.Room(roomId.toRoomIdOrAlias()))
+ }
+ }
val inputs = RoomFlowNode.Inputs(
roomIdOrAlias = navTarget.roomIdOrAlias,
roomDescription = Optional.ofNullable(navTarget.roomDescription),
@@ -380,7 +377,7 @@ class LoggedInFlowNode(
trigger = Optional.ofNullable(navTarget.trigger),
initialElement = navTarget.initialElement
)
- createNode(buildContext, plugins = listOf(inputs, callback))
+ createNode(buildContext, plugins = listOf(inputs, joinedRoomCallback, spaceCallback))
}
is NavTarget.UserProfile -> {
val callback = object : UserProfileEntryPoint.Callback {
@@ -448,8 +445,7 @@ class LoggedInFlowNode(
.build()
}
NavTarget.Ftue -> {
- ftueEntryPoint.nodeBuilder(this, buildContext)
- .build()
+ ftueEntryPoint.createNode(this, buildContext)
}
NavTarget.RoomDirectorySearch -> {
roomDirectoryEntryPoint.nodeBuilder(this, buildContext)
@@ -480,17 +476,6 @@ class LoggedInFlowNode(
.params(ShareEntryPoint.Params(intent = navTarget.intent))
.build()
}
- is NavTarget.LogoutForNativeSlidingSyncMigrationNeeded -> {
- val callback = object : LogoutEntryPoint.Callback {
- override fun onChangeRecoveryKeyClick() {
- backstack.push(NavTarget.SecureBackup())
- }
- }
-
- logoutEntryPoint.nodeBuilder(this, buildContext)
- .callback(callback)
- .build()
- }
is NavTarget.IncomingVerificationRequest -> {
incomingVerificationEntryPoint.nodeBuilder(this, buildContext)
.params(IncomingVerificationEntryPoint.Params(navTarget.data))
diff --git a/appnav/src/main/kotlin/io/element/android/appnav/RootFlowNode.kt b/appnav/src/main/kotlin/io/element/android/appnav/RootFlowNode.kt
index 818e670e46..3f1d40335d 100644
--- a/appnav/src/main/kotlin/io/element/android/appnav/RootFlowNode.kt
+++ b/appnav/src/main/kotlin/io/element/android/appnav/RootFlowNode.kt
@@ -39,7 +39,6 @@ import io.element.android.features.login.api.accesscontrol.AccountProviderAccess
import io.element.android.features.rageshake.api.bugreport.BugReportEntryPoint
import io.element.android.features.rageshake.api.reporter.BugReporter
import io.element.android.features.signedout.api.SignedOutEntryPoint
-import io.element.android.features.viewfolder.api.ViewFolderEntryPoint
import io.element.android.libraries.architecture.BackstackView
import io.element.android.libraries.architecture.BaseFlowNode
import io.element.android.libraries.architecture.createNode
@@ -47,13 +46,13 @@ import io.element.android.libraries.architecture.waitForChildAttached
import io.element.android.libraries.core.uri.ensureProtocol
import io.element.android.libraries.deeplink.api.DeeplinkData
import io.element.android.libraries.designsystem.theme.components.CircularProgressIndicator
-import io.element.android.libraries.matrix.api.auth.MatrixAuthenticationService
import io.element.android.libraries.matrix.api.core.SessionId
import io.element.android.libraries.matrix.api.core.toRoomIdOrAlias
import io.element.android.libraries.matrix.api.permalink.PermalinkData
import io.element.android.libraries.oidc.api.OidcAction
import io.element.android.libraries.oidc.api.OidcActionFlow
import io.element.android.libraries.sessionstorage.api.LoggedInState
+import io.element.android.libraries.sessionstorage.api.SessionStore
import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach
@@ -65,13 +64,12 @@ import timber.log.Timber
class RootFlowNode(
@Assisted val buildContext: BuildContext,
@Assisted plugins: List,
- private val authenticationService: MatrixAuthenticationService,
+ private val sessionStore: SessionStore,
private val accountProviderAccessControl: AccountProviderAccessControl,
private val navStateFlowFactory: RootNavStateFlowFactory,
private val matrixSessionCache: MatrixSessionCache,
private val presenter: RootPresenter,
private val bugReportEntryPoint: BugReportEntryPoint,
- private val viewFolderEntryPoint: ViewFolderEntryPoint,
private val signedOutEntryPoint: SignedOutEntryPoint,
private val intentResolver: IntentResolver,
private val oidcActionFlow: OidcActionFlow,
@@ -154,7 +152,7 @@ class RootFlowNode(
onSuccess: (SessionId) -> Unit,
onFailure: () -> Unit
) {
- val latestSessionId = authenticationService.getLatestSessionId()
+ val latestSessionId = sessionStore.getLatestSessionId()
if (latestSessionId == null) {
onFailure()
return
@@ -200,11 +198,6 @@ class RootFlowNode(
@Parcelize
data object BugReport : NavTarget
-
- @Parcelize
- data class ViewLogs(
- val rootPath: String,
- ) : NavTarget
}
override fun resolve(navTarget: NavTarget, buildContext: BuildContext): Node {
@@ -244,31 +237,12 @@ class RootFlowNode(
NavTarget.SplashScreen -> splashNode(buildContext)
NavTarget.BugReport -> {
val callback = object : BugReportEntryPoint.Callback {
- override fun onBugReportSent() {
- backstack.pop()
- }
-
- override fun onViewLogs(basePath: String) {
- backstack.push(NavTarget.ViewLogs(rootPath = basePath))
- }
- }
- bugReportEntryPoint
- .nodeBuilder(this, buildContext)
- .callback(callback)
- .build()
- }
- is NavTarget.ViewLogs -> {
- val callback = object : ViewFolderEntryPoint.Callback {
override fun onDone() {
backstack.pop()
}
}
- val params = ViewFolderEntryPoint.Params(
- rootPath = navTarget.rootPath,
- )
- viewFolderEntryPoint
+ bugReportEntryPoint
.nodeBuilder(this, buildContext)
- .params(params)
.callback(callback)
.build()
}
@@ -294,7 +268,7 @@ class RootFlowNode(
private suspend fun onLoginLink(params: LoginParams) {
// Is there a session already?
- val latestSessionId = authenticationService.getLatestSessionId()
+ val latestSessionId = sessionStore.getLatestSessionId()
if (latestSessionId == null) {
// No session, open login
if (accountProviderAccessControl.isAllowedToConnectToAccountProvider(params.accountProvider.ensureProtocol())) {
@@ -311,7 +285,7 @@ class RootFlowNode(
private suspend fun onIncomingShare(intent: Intent) {
// Is there a session already?
- val latestSessionId = authenticationService.getLatestSessionId()
+ val latestSessionId = sessionStore.getLatestSessionId()
if (latestSessionId == null) {
// No session, open login
switchToNotLoggedInFlow(null)
@@ -368,3 +342,5 @@ class RootFlowNode(
.attachSession()
}
}
+
+private suspend fun SessionStore.getLatestSessionId() = getLatestSession()?.userId?.let(::SessionId)
diff --git a/appnav/src/main/kotlin/io/element/android/appnav/di/RoomComponentFactory.kt b/appnav/src/main/kotlin/io/element/android/appnav/di/RoomComponentFactory.kt
index 4911ab50b5..fc8f2c175b 100644
--- a/appnav/src/main/kotlin/io/element/android/appnav/di/RoomComponentFactory.kt
+++ b/appnav/src/main/kotlin/io/element/android/appnav/di/RoomComponentFactory.kt
@@ -9,6 +9,6 @@ package io.element.android.appnav.di
import io.element.android.libraries.matrix.api.room.JoinedRoom
-interface RoomComponentFactory {
+fun interface RoomComponentFactory {
fun create(room: JoinedRoom): Any
}
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 12d9df78cf..6f04a08f7b 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
@@ -30,7 +30,9 @@ import io.element.android.appnav.room.joined.JoinedRoomLoadedFlowNode
import io.element.android.appnav.room.joined.LoadingRoomNodeView
import io.element.android.features.joinroom.api.JoinRoomEntryPoint
import io.element.android.features.roomaliasesolver.api.RoomAliasResolverEntryPoint
+import io.element.android.features.roomaliasesolver.api.RoomAliasResolverEntryPoint.Params
import io.element.android.features.roomdirectory.api.RoomDescription
+import io.element.android.features.space.api.SpaceEntryPoint
import io.element.android.libraries.architecture.BackstackView
import io.element.android.libraries.architecture.BaseFlowNode
import io.element.android.libraries.architecture.NodeInputs
@@ -52,7 +54,6 @@ import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.filter
-import kotlinx.coroutines.flow.first
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.shareIn
@@ -72,6 +73,7 @@ class RoomFlowNode(
private val roomAliasResolverEntryPoint: RoomAliasResolverEntryPoint,
private val syncService: SyncService,
private val membershipObserver: RoomMembershipObserver,
+ private val spaceEntryPoint: SpaceEntryPoint,
) : BaseFlowNode(
backstack = BackStack(
initialElement = NavTarget.Loading,
@@ -106,6 +108,9 @@ class RoomFlowNode(
@Parcelize
data class JoinedRoom(val roomId: RoomId) : NavTarget
+
+ @Parcelize
+ data class JoinedSpace(val spaceId: RoomId) : NavTarget
}
override fun onBuilt() {
@@ -143,40 +148,28 @@ class RoomFlowNode(
.withPreviousValue()
combine(currentMembershipFlow, isSpaceFlow) { (previousMembership, membership), isSpace ->
Timber.d("Room membership: $membership")
- when (membership) {
- CurrentUserMembership.JOINED -> {
- if (isSpace) {
- // It should not happen, but probably due to an issue in the sliding sync,
- // we can have a space here in case the space has just been joined.
- // So navigate to the JoinRoom target for now, which will
- // handle the space not supported screen
- backstack.newRoot(
- NavTarget.JoinRoom(
- roomId = roomId,
- serverNames = serverNames,
- trigger = inputs.trigger.getOrNull() ?: JoinedRoom.Trigger.Invite,
- )
- )
- } else {
- backstack.newRoot(NavTarget.JoinedRoom(roomId))
- }
+ if (membership == CurrentUserMembership.JOINED) {
+ if (isSpace) {
+ backstack.newRoot(NavTarget.JoinedSpace(spaceId = roomId))
+ } else {
+ backstack.newRoot(NavTarget.JoinedRoom(roomId))
}
- else -> {
- if (membership == CurrentUserMembership.LEFT && previousMembership == CurrentUserMembership.JOINED) {
- // The user left the room in this device, remove the room from the backstack
- if (!membershipUpdateFlow.first().isUserInRoom) {
- navigateUp()
- }
- } else {
- // Was invited or the room is not known, display the join room screen
- backstack.newRoot(
- NavTarget.JoinRoom(
- roomId = roomId,
- serverNames = serverNames,
- trigger = inputs.trigger.getOrNull() ?: JoinedRoom.Trigger.Invite,
- )
+ } else {
+ val leavingFromCurrentDevice =
+ membership == CurrentUserMembership.LEFT &&
+ previousMembership == CurrentUserMembership.JOINED &&
+ membershipUpdateFlow.replayCache.lastOrNull()?.isUserInRoom == false
+
+ if (leavingFromCurrentDevice) {
+ navigateUp()
+ } else {
+ backstack.newRoot(
+ NavTarget.JoinRoom(
+ roomId = roomId,
+ serverNames = serverNames,
+ trigger = inputs.trigger.getOrNull() ?: JoinedRoom.Trigger.Invite,
)
- }
+ )
}
}
}.launchIn(lifecycleScope)
@@ -194,7 +187,7 @@ class RoomFlowNode(
)
}
}
- val params = RoomAliasResolverEntryPoint.Params(navTarget.roomAlias)
+ val params = Params(navTarget.roomAlias)
roomAliasResolverEntryPoint.nodeBuilder(this, buildContext)
.callback(callback)
.params(params)
@@ -218,6 +211,13 @@ class RoomFlowNode(
)
createNode(buildContext, plugins = listOf(inputs) + roomFlowNodeCallback)
}
+ is NavTarget.JoinedSpace -> {
+ val spaceCallback = plugins().single()
+ spaceEntryPoint.nodeBuilder(this, buildContext)
+ .inputs(SpaceEntryPoint.Inputs(roomId = navTarget.spaceId))
+ .callback(spaceCallback)
+ .build()
+ }
}
}
diff --git a/appnav/src/main/kotlin/io/element/android/appnav/root/RootNavStateFlowFactory.kt b/appnav/src/main/kotlin/io/element/android/appnav/root/RootNavStateFlowFactory.kt
index 962bac614b..dfa478d6be 100644
--- a/appnav/src/main/kotlin/io/element/android/appnav/root/RootNavStateFlowFactory.kt
+++ b/appnav/src/main/kotlin/io/element/android/appnav/root/RootNavStateFlowFactory.kt
@@ -12,9 +12,9 @@ import com.bumble.appyx.core.state.SavedStateMap
import dev.zacsweers.metro.Inject
import io.element.android.appnav.di.MatrixSessionCache
import io.element.android.features.preferences.api.CacheService
-import io.element.android.libraries.matrix.api.auth.MatrixAuthenticationService
import io.element.android.libraries.matrix.ui.media.ImageLoaderHolder
import io.element.android.libraries.preferences.api.store.SessionPreferencesStoreFactory
+import io.element.android.libraries.sessionstorage.api.SessionStore
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.flow
@@ -28,7 +28,7 @@ private const val SAVE_INSTANCE_KEY = "io.element.android.x.RootNavStateFlowFact
*/
@Inject
class RootNavStateFlowFactory(
- private val authenticationService: MatrixAuthenticationService,
+ private val sessionStore: SessionStore,
private val cacheService: CacheService,
private val matrixSessionCache: MatrixSessionCache,
private val imageLoaderHolder: ImageLoaderHolder,
@@ -39,7 +39,7 @@ class RootNavStateFlowFactory(
fun create(savedStateMap: SavedStateMap?): Flow {
return combine(
cacheIndexFlow(savedStateMap),
- authenticationService.loggedInStateFlow(),
+ sessionStore.loggedInStateFlow(),
) { cacheIndex, loggedInState ->
RootNavState(
cacheIndex = cacheIndex,
diff --git a/appnav/src/main/res/values-pt/translations.xml b/appnav/src/main/res/values-pt/translations.xml
index d606a8d103..2d84d29475 100644
--- a/appnav/src/main/res/values-pt/translations.xml
+++ b/appnav/src/main/res/values-pt/translations.xml
@@ -2,5 +2,5 @@
"Sair & Atualizar"
"%1$s já não suporta o protocolo antigo. Termina a sessão e volta a iniciar sessão para continuares a utilizar a aplicação."
- "Seu homeserver não suporta mais o protocolo antigo. Termine sessão e volte a iniciar sessão para continuar a utilizar a aplicação."
+ "O teu servidor já não permite o protocolo antigo. Termine sessão e volte a iniciá-la para continuar a utilizar a aplicação."
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 d86c46f159..47cbda4b91 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
@@ -501,22 +501,16 @@ class LoggedInPresenterTest {
@Test
fun `present - CheckSlidingSyncProxyAvailability forces the sliding sync migration under the right circumstances`() = runTest {
- // The migration will be forced if:
- // - The user is not using the native sliding sync
- // - The sliding sync proxy is no longer supported
- // - The native sliding sync is supported
+ // The migration will be forced if the user is not using the native sliding sync
val matrixClient = FakeMatrixClient(
currentSlidingSyncVersionLambda = { Result.success(SlidingSyncVersion.Proxy) },
- availableSlidingSyncVersionsLambda = { Result.success(listOf(SlidingSyncVersion.Native)) },
)
createLoggedInPresenter(
matrixClient = matrixClient,
).test {
val initialState = awaitItem()
assertThat(initialState.forceNativeSlidingSyncMigration).isFalse()
-
initialState.eventSink(LoggedInEvents.CheckSlidingSyncProxyAvailability)
-
assertThat(awaitItem().forceNativeSlidingSyncMigration).isTrue()
}
}
diff --git a/build.gradle.kts b/build.gradle.kts
index b4ebcf6268..7171d5b079 100644
--- a/build.gradle.kts
+++ b/build.gradle.kts
@@ -93,6 +93,8 @@ allprojects {
// Fix compilation warning for annotations
// See https://youtrack.jetbrains.com/issue/KT-73255/Change-defaulting-rule-for-annotations for more details
freeCompilerArgs.add("-Xannotation-default-target=first-only")
+ // Opt-in to context receivers
+ freeCompilerArgs.add("-Xcontext-parameters")
}
}
}
diff --git a/fastlane/metadata/android/en-US/changelogs/202509020.txt b/fastlane/metadata/android/en-US/changelogs/202509020.txt
new file mode 100644
index 0000000000..8955ade680
--- /dev/null
+++ b/fastlane/metadata/android/en-US/changelogs/202509020.txt
@@ -0,0 +1,2 @@
+Main changes in this version: bug fixes and improvements.
+Full changelog: https://github.com/element-hq/element-x-android/releases
diff --git a/features/analytics/api/src/main/kotlin/io/element/android/features/analytics/api/AnalyticsEntryPoint.kt b/features/analytics/api/src/main/kotlin/io/element/android/features/analytics/api/AnalyticsEntryPoint.kt
index 404bae44d1..37a78fd727 100644
--- a/features/analytics/api/src/main/kotlin/io/element/android/features/analytics/api/AnalyticsEntryPoint.kt
+++ b/features/analytics/api/src/main/kotlin/io/element/android/features/analytics/api/AnalyticsEntryPoint.kt
@@ -9,4 +9,4 @@ package io.element.android.features.analytics.api
import io.element.android.libraries.architecture.SimpleFeatureEntryPoint
-interface AnalyticsEntryPoint : SimpleFeatureEntryPoint
+fun interface AnalyticsEntryPoint : SimpleFeatureEntryPoint
diff --git a/features/analytics/impl/build.gradle.kts b/features/analytics/impl/build.gradle.kts
index b722196c59..ddf093d9c3 100644
--- a/features/analytics/impl/build.gradle.kts
+++ b/features/analytics/impl/build.gradle.kts
@@ -1,4 +1,5 @@
import extension.setupDependencyInjection
+import extension.testCommonDependencies
/*
* Copyright 2023, 2024 New Vector Ltd.
@@ -30,13 +31,7 @@ dependencies {
implementation(libs.androidx.datastore.preferences)
implementation(libs.androidx.browser)
- testImplementation(libs.test.junit)
- testImplementation(libs.coroutines.test)
- testImplementation(libs.molecule.runtime)
- testImplementation(libs.test.truth)
- testImplementation(libs.test.turbine)
- testImplementation(libs.test.mockk)
+ testCommonDependencies(libs)
testImplementation(projects.libraries.matrix.test)
testImplementation(projects.services.analytics.test)
- testImplementation(projects.tests.testutils)
}
diff --git a/features/analytics/impl/src/test/kotlin/io/element/android/features/analytics/impl/DefaultAnalyticsEntryPointTest.kt b/features/analytics/impl/src/test/kotlin/io/element/android/features/analytics/impl/DefaultAnalyticsEntryPointTest.kt
new file mode 100644
index 0000000000..b5ec819632
--- /dev/null
+++ b/features/analytics/impl/src/test/kotlin/io/element/android/features/analytics/impl/DefaultAnalyticsEntryPointTest.kt
@@ -0,0 +1,39 @@
+/*
+ * Copyright 2025 New Vector Ltd.
+ *
+ * SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial
+ * Please see LICENSE files in the repository root for full details.
+ */
+
+package io.element.android.features.analytics.impl
+
+import androidx.arch.core.executor.testing.InstantTaskExecutorRule
+import com.bumble.appyx.core.modality.BuildContext
+import com.google.common.truth.Truth.assertThat
+import io.element.android.libraries.matrix.test.core.aBuildMeta
+import io.element.android.services.analytics.test.FakeAnalyticsService
+import io.element.android.tests.testutils.node.TestParentNode
+import org.junit.Rule
+import org.junit.Test
+
+class DefaultAnalyticsEntryPointTest {
+ @get:Rule
+ val instantTaskExecutorRule = InstantTaskExecutorRule()
+
+ @Test
+ fun `test node creation`() {
+ val entryPoint = DefaultAnalyticsEntryPoint()
+ val parentNode = TestParentNode.create { buildContext, plugins ->
+ AnalyticsOptInNode(
+ buildContext = buildContext,
+ plugins = plugins,
+ AnalyticsOptInPresenter(
+ buildMeta = aBuildMeta(),
+ analyticsService = FakeAnalyticsService()
+ )
+ )
+ }
+ val result = entryPoint.createNode(parentNode, BuildContext.root(null))
+ assertThat(result).isInstanceOf(AnalyticsOptInNode::class.java)
+ }
+}
diff --git a/features/cachecleaner/impl/build.gradle.kts b/features/cachecleaner/impl/build.gradle.kts
index 45cc5fe09b..8603de6322 100644
--- a/features/cachecleaner/impl/build.gradle.kts
+++ b/features/cachecleaner/impl/build.gradle.kts
@@ -1,4 +1,5 @@
import extension.setupDependencyInjection
+import extension.testCommonDependencies
/*
* Copyright 2023, 2024 New Vector Ltd.
@@ -22,8 +23,5 @@ dependencies {
implementation(projects.libraries.core)
implementation(projects.libraries.architecture)
- testImplementation(libs.test.junit)
- testImplementation(libs.coroutines.test)
- testImplementation(libs.test.truth)
- testImplementation(projects.tests.testutils)
+ testCommonDependencies(libs)
}
diff --git a/features/call/api/src/main/kotlin/io/element/android/features/call/api/ElementCallEntryPoint.kt b/features/call/api/src/main/kotlin/io/element/android/features/call/api/ElementCallEntryPoint.kt
index 53e1b8c846..8de7a3839b 100644
--- a/features/call/api/src/main/kotlin/io/element/android/features/call/api/ElementCallEntryPoint.kt
+++ b/features/call/api/src/main/kotlin/io/element/android/features/call/api/ElementCallEntryPoint.kt
@@ -29,6 +29,7 @@ interface ElementCallEntryPoint {
* @param senderName The name of the sender of the event that started the call.
* @param avatarUrl The avatar url of the room or DM.
* @param timestamp The timestamp of the event that started the call.
+ * @param expirationTimestamp The timestamp at which the call should stop ringing.
* @param notificationChannelId The id of the notification channel to use for the call notification.
* @param textContent The text content of the notification. If null the default content from the system will be used.
*/
@@ -40,6 +41,7 @@ interface ElementCallEntryPoint {
senderName: String?,
avatarUrl: String?,
timestamp: Long,
+ expirationTimestamp: Long,
notificationChannelId: String,
textContent: String?,
)
diff --git a/features/call/impl/build.gradle.kts b/features/call/impl/build.gradle.kts
index 0c9ae5a4b0..9efe5ba75b 100644
--- a/features/call/impl/build.gradle.kts
+++ b/features/call/impl/build.gradle.kts
@@ -1,6 +1,7 @@
import extension.buildConfigFieldStr
import extension.readLocalProperty
import extension.setupDependencyInjection
+import extension.testCommonDependencies
/*
* Copyright 2024 New Vector Ltd.
@@ -87,12 +88,7 @@ dependencies {
implementation(libs.element.call.embedded)
api(projects.features.call.api)
- testImplementation(libs.coroutines.test)
- testImplementation(libs.molecule.runtime)
- testImplementation(libs.test.truth)
- testImplementation(libs.test.turbine)
- testImplementation(libs.test.robolectric)
- testImplementation(libs.test.mockk)
+ testCommonDependencies(libs, true)
testImplementation(projects.features.call.test)
testImplementation(projects.libraries.featureflag.test)
testImplementation(projects.libraries.preferences.test)
@@ -100,7 +96,5 @@ dependencies {
testImplementation(projects.libraries.push.test)
testImplementation(projects.services.analytics.test)
testImplementation(projects.services.appnavstate.test)
- testImplementation(projects.tests.testutils)
- testImplementation(libs.androidx.compose.ui.test.junit)
- testReleaseImplementation(libs.androidx.compose.ui.test.manifest)
+ testImplementation(projects.services.toolbox.test)
}
diff --git a/features/call/impl/src/main/kotlin/io/element/android/features/call/impl/DefaultElementCallEntryPoint.kt b/features/call/impl/src/main/kotlin/io/element/android/features/call/impl/DefaultElementCallEntryPoint.kt
index 3b937dbf92..a1c07462f8 100644
--- a/features/call/impl/src/main/kotlin/io/element/android/features/call/impl/DefaultElementCallEntryPoint.kt
+++ b/features/call/impl/src/main/kotlin/io/element/android/features/call/impl/DefaultElementCallEntryPoint.kt
@@ -43,6 +43,7 @@ class DefaultElementCallEntryPoint(
senderName: String?,
avatarUrl: String?,
timestamp: Long,
+ expirationTimestamp: Long,
notificationChannelId: String,
textContent: String?,
) {
@@ -55,6 +56,7 @@ class DefaultElementCallEntryPoint(
senderName = senderName,
avatarUrl = avatarUrl,
timestamp = timestamp,
+ expirationTimestamp = expirationTimestamp,
notificationChannelId = notificationChannelId,
textContent = textContent,
)
diff --git a/features/call/impl/src/main/kotlin/io/element/android/features/call/impl/data/WidgetMessage.kt b/features/call/impl/src/main/kotlin/io/element/android/features/call/impl/data/WidgetMessage.kt
index c18fef410e..5001d598d9 100644
--- a/features/call/impl/src/main/kotlin/io/element/android/features/call/impl/data/WidgetMessage.kt
+++ b/features/call/impl/src/main/kotlin/io/element/android/features/call/impl/data/WidgetMessage.kt
@@ -41,5 +41,8 @@ data class WidgetMessage(
@SerialName("send_event")
SendEvent,
+
+ @SerialName("content_loaded")
+ ContentLoaded,
}
}
diff --git a/features/call/impl/src/main/kotlin/io/element/android/features/call/impl/notifications/CallNotificationData.kt b/features/call/impl/src/main/kotlin/io/element/android/features/call/impl/notifications/CallNotificationData.kt
index 7c97cc8529..0bfbfb0411 100644
--- a/features/call/impl/src/main/kotlin/io/element/android/features/call/impl/notifications/CallNotificationData.kt
+++ b/features/call/impl/src/main/kotlin/io/element/android/features/call/impl/notifications/CallNotificationData.kt
@@ -26,4 +26,6 @@ data class CallNotificationData(
val notificationChannelId: String,
val timestamp: Long,
val textContent: String?,
+ // Expiration timestamp in millis since epoch
+ val expirationTimestamp: Long,
) : Parcelable
diff --git a/features/call/impl/src/main/kotlin/io/element/android/features/call/impl/notifications/RingingCallNotificationCreator.kt b/features/call/impl/src/main/kotlin/io/element/android/features/call/impl/notifications/RingingCallNotificationCreator.kt
index 988105ae06..2f8ce3e53a 100644
--- a/features/call/impl/src/main/kotlin/io/element/android/features/call/impl/notifications/RingingCallNotificationCreator.kt
+++ b/features/call/impl/src/main/kotlin/io/element/android/features/call/impl/notifications/RingingCallNotificationCreator.kt
@@ -64,6 +64,7 @@ class RingingCallNotificationCreator(
roomAvatarUrl: String?,
notificationChannelId: String,
timestamp: Long,
+ expirationTimestamp: Long,
textContent: String?,
): Notification? {
val matrixClient = matrixClientProvider.getOrRestore(sessionId).getOrNull() ?: return null
@@ -88,6 +89,7 @@ class RingingCallNotificationCreator(
notificationChannelId = notificationChannelId,
timestamp = timestamp,
textContent = textContent,
+ expirationTimestamp = expirationTimestamp,
)
val declineIntent = PendingIntentCompat.getBroadcast(
diff --git a/features/call/impl/src/main/kotlin/io/element/android/features/call/impl/ui/CallScreenPresenter.kt b/features/call/impl/src/main/kotlin/io/element/android/features/call/impl/ui/CallScreenPresenter.kt
index d82c64b607..c1c58d4607 100644
--- a/features/call/impl/src/main/kotlin/io/element/android/features/call/impl/ui/CallScreenPresenter.kt
+++ b/features/call/impl/src/main/kotlin/io/element/android/features/call/impl/ui/CallScreenPresenter.kt
@@ -79,7 +79,7 @@ class CallScreenPresenter(
val urlState = remember { mutableStateOf>(AsyncData.Uninitialized) }
val callWidgetDriver = remember { mutableStateOf(null) }
val messageInterceptor = remember { mutableStateOf(null) }
- var isJoinedCall by rememberSaveable { mutableStateOf(false) }
+ var isWidgetLoaded by rememberSaveable { mutableStateOf(false) }
var ignoreWebViewError by rememberSaveable { mutableStateOf(false) }
var webViewError by remember { mutableStateOf(null) }
val languageTag = languageTagProvider.provideLanguageTag()
@@ -139,8 +139,8 @@ class CallScreenPresenter(
if (parsedMessage?.direction == WidgetMessage.Direction.FromWidget) {
if (parsedMessage.action == WidgetMessage.Action.Close) {
close(callWidgetDriver.value, navigator)
- } else if (parsedMessage.action == WidgetMessage.Action.Join) {
- isJoinedCall = true
+ } else if (parsedMessage.action == WidgetMessage.Action.ContentLoaded) {
+ isWidgetLoaded = true
}
}
}
@@ -151,8 +151,8 @@ class CallScreenPresenter(
// Wait for the call to be joined, if it takes too long, we display an error
delay(10.seconds)
- if (!isJoinedCall) {
- Timber.w("The call took too long to be joined. Displaying an error before exiting.")
+ if (!isWidgetLoaded) {
+ Timber.w("The call took too long to load. Displaying an error before exiting.")
// This will display a simple 'Sorry, an error occurred' dialog and force the user to exit the call
webViewError = ""
@@ -165,10 +165,10 @@ class CallScreenPresenter(
is CallScreenEvents.Hangup -> {
val widgetId = callWidgetDriver.value?.id
val interceptor = messageInterceptor.value
- if (widgetId != null && interceptor != null && isJoinedCall) {
+ if (widgetId != null && interceptor != null && isWidgetLoaded) {
// If the call was joined, we need to hang up first. Then the UI will be dismissed automatically.
sendHangupMessage(widgetId, interceptor)
- isJoinedCall = false
+ isWidgetLoaded = false
coroutineScope.launch {
// Wait for a couple of seconds to receive the hangup message
@@ -198,7 +198,7 @@ class CallScreenPresenter(
urlState = urlState.value,
webViewError = webViewError,
userAgent = userAgent,
- isCallActive = isJoinedCall,
+ isCallActive = isWidgetLoaded,
isInWidgetMode = isInWidgetMode,
eventSink = { handleEvents(it) },
)
diff --git a/features/call/impl/src/main/kotlin/io/element/android/features/call/impl/ui/IncomingCallScreen.kt b/features/call/impl/src/main/kotlin/io/element/android/features/call/impl/ui/IncomingCallScreen.kt
index 954fa3568f..9483b91a14 100644
--- a/features/call/impl/src/main/kotlin/io/element/android/features/call/impl/ui/IncomingCallScreen.kt
+++ b/features/call/impl/src/main/kotlin/io/element/android/features/call/impl/ui/IncomingCallScreen.kt
@@ -176,6 +176,7 @@ internal fun IncomingCallScreenPreview() = ElementPreview {
notificationChannelId = "incoming_call",
timestamp = 0L,
textContent = null,
+ expirationTimestamp = 1000L,
),
onAnswer = {},
onCancel = {},
diff --git a/features/call/impl/src/main/kotlin/io/element/android/features/call/impl/utils/ActiveCallManager.kt b/features/call/impl/src/main/kotlin/io/element/android/features/call/impl/utils/ActiveCallManager.kt
index 54a5e567c8..34f46d1ea0 100644
--- a/features/call/impl/src/main/kotlin/io/element/android/features/call/impl/utils/ActiveCallManager.kt
+++ b/features/call/impl/src/main/kotlin/io/element/android/features/call/impl/utils/ActiveCallManager.kt
@@ -34,6 +34,7 @@ import io.element.android.libraries.push.api.notifications.ForegroundServiceType
import io.element.android.libraries.push.api.notifications.NotificationIdProvider
import io.element.android.libraries.push.api.notifications.OnMissedCallNotificationHandler
import io.element.android.services.appnavstate.api.AppForegroundStateService
+import io.element.android.services.toolbox.api.systemclock.SystemClock
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.Job
@@ -53,7 +54,7 @@ import kotlinx.coroutines.launch
import kotlinx.coroutines.sync.Mutex
import kotlinx.coroutines.sync.withLock
import timber.log.Timber
-import kotlin.time.Duration.Companion.seconds
+import kotlin.math.min
/**
* Manages the active call state.
@@ -98,6 +99,7 @@ class DefaultActiveCallManager(
private val defaultCurrentCallService: DefaultCurrentCallService,
private val appForegroundStateService: AppForegroundStateService,
private val imageLoaderHolder: ImageLoaderHolder,
+ private val systemClock: SystemClock,
) : ActiveCallManager {
private val tag = "DefaultActiveCallManager"
private var timedOutCallJob: Job? = null
@@ -118,8 +120,20 @@ class DefaultActiveCallManager(
override suspend fun registerIncomingCall(notificationData: CallNotificationData) {
mutex.withLock {
+ val ringDuration =
+ min(
+ notificationData.expirationTimestamp - systemClock.epochMillis(),
+ ElementCallConfig.RINGING_CALL_DURATION_SECONDS * 1000L
+ )
+
+ if (ringDuration < 0) {
+ // Should already have stopped ringing, ignore.
+ Timber.tag(tag).d("Received timed-out incoming ringing call for room id: ${notificationData.roomId}, cancel ringing")
+ return
+ }
+
appForegroundStateService.updateHasRingingCall(true)
- Timber.tag(tag).d("Received incoming call for room id: ${notificationData.roomId}")
+ Timber.tag(tag).d("Received incoming call for room id: ${notificationData.roomId}, ringDuration(ms): $ringDuration")
if (activeCall.value != null) {
displayMissedCallNotification(notificationData)
Timber.tag(tag).w("Already have an active call, ignoring incoming call: $notificationData")
@@ -138,14 +152,14 @@ class DefaultActiveCallManager(
showIncomingCallNotification(notificationData)
// Wait for the ringing call to time out
- delay(ElementCallConfig.RINGING_CALL_DURATION_SECONDS.seconds)
+ delay(timeMillis = ringDuration)
incomingCallTimedOut(displayMissedCallNotification = true)
}
// Acquire a wake lock to keep the device awake during the incoming call, so we can process the room info data
if (activeWakeLock?.isHeld == false) {
Timber.tag(tag).d("Acquiring partial wakelock")
- activeWakeLock.acquire(ElementCallConfig.RINGING_CALL_DURATION_SECONDS * 1000L)
+ activeWakeLock.acquire(ringDuration)
}
}
}
@@ -180,12 +194,22 @@ class DefaultActiveCallManager(
}
override suspend fun hungUpCall(callType: CallType) = mutex.withLock {
- if (activeCall.value?.callType != callType) {
+ Timber.tag(tag).d("Hung up call: $callType")
+ val currentActiveCall = activeCall.value ?: run {
+ Timber.tag(tag).w("No active call, ignoring hang up")
+ return
+ }
+ if (currentActiveCall.callType != callType) {
Timber.tag(tag).w("Call type $callType does not match the active call type, ignoring")
return
}
-
- Timber.tag(tag).d("Hung up call: $callType")
+ if (currentActiveCall.callState is CallState.Ringing) {
+ // Decline the call
+ val notificationData = currentActiveCall.callState.notificationData
+ matrixClientProvider.getOrRestore(notificationData.sessionId).getOrNull()
+ ?.getRoom(notificationData.roomId)
+ ?.declineCall(notificationData.eventId)
+ }
cancelIncomingCallNotification()
if (activeWakeLock?.isHeld == true) {
@@ -226,6 +250,7 @@ class DefaultActiveCallManager(
notificationChannelId = notificationData.notificationChannelId,
timestamp = notificationData.timestamp,
textContent = notificationData.textContent,
+ expirationTimestamp = notificationData.expirationTimestamp,
) ?: return
runCatchingExceptions {
notificationManagerCompat.notify(
@@ -256,6 +281,43 @@ class DefaultActiveCallManager(
@OptIn(ExperimentalCoroutinesApi::class)
private fun observeRingingCall() {
+ activeCall
+ .filterNotNull()
+ .filter { it.callState is CallState.Ringing && it.callType is CallType.RoomCall }
+ .flatMapLatest { activeCall ->
+ val callType = activeCall.callType as CallType.RoomCall
+ val ringingInfo = activeCall.callState as CallState.Ringing
+ val client = matrixClientProvider.getOrRestore(callType.sessionId).getOrNull() ?: run {
+ Timber.tag(tag).d("Couldn't find session for incoming call: $activeCall")
+ return@flatMapLatest flowOf()
+ }
+ val room = client.getRoom(callType.roomId) ?: run {
+ Timber.tag(tag).d("Couldn't find room for incoming call: $activeCall")
+ return@flatMapLatest flowOf()
+ }
+
+ Timber.tag(tag).d("Found room for ringing call: ${room.roomId}")
+
+ // If we have declined from another phone we want to stop ringing.
+ room.subscribeToCallDecline(ringingInfo.notificationData.eventId)
+ .filter { decliner ->
+ Timber.tag(tag).d("Call: $activeCall was declined by $decliner")
+ // only want to listen if the call was declined from another of my sessions,
+ // (we are ringing for an incoming call in a DM)
+ decliner == client.sessionId
+ }
+ }
+ .onEach { decliner ->
+ Timber.tag(tag).d("Call: $activeCall was declined by user from another session")
+ // Remove the active call and cancel the notification
+ activeCall.value = null
+ if (activeWakeLock?.isHeld == true) {
+ Timber.tag(tag).d("Releasing partial wakelock after call declined from another session")
+ activeWakeLock.release()
+ }
+ cancelIncomingCallNotification()
+ }
+ .launchIn(coroutineScope)
// This will observe ringing calls and ensure they're terminated if the room call is cancelled or if the user
// has joined the call from another session.
activeCall
diff --git a/features/call/impl/src/main/kotlin/io/element/android/features/call/impl/utils/DefaultCallWidgetProvider.kt b/features/call/impl/src/main/kotlin/io/element/android/features/call/impl/utils/DefaultCallWidgetProvider.kt
index 77d98d12af..dc217bc118 100644
--- a/features/call/impl/src/main/kotlin/io/element/android/features/call/impl/utils/DefaultCallWidgetProvider.kt
+++ b/features/call/impl/src/main/kotlin/io/element/android/features/call/impl/utils/DefaultCallWidgetProvider.kt
@@ -45,8 +45,14 @@ class DefaultCallWidgetProvider(
val customBaseUrl = appPreferencesStore.getCustomElementCallBaseUrlFlow().firstOrNull()
val baseUrl = customBaseUrl ?: EMBEDDED_CALL_WIDGET_BASE_URL
- val isEncrypted = room.info().isEncrypted ?: room.getUpdatedIsEncrypted().getOrThrow()
- val widgetSettings = callWidgetSettingsProvider.provide(baseUrl, encrypted = isEncrypted, direct = room.isDm())
+ val roomInfo = room.info()
+ val isEncrypted = roomInfo.isEncrypted ?: room.getUpdatedIsEncrypted().getOrThrow()
+ val widgetSettings = callWidgetSettingsProvider.provide(
+ baseUrl = baseUrl,
+ encrypted = isEncrypted,
+ direct = room.isDm(),
+ hasActiveCall = roomInfo.hasRoomCall,
+ )
val callUrl = room.generateWidgetWebViewUrl(
widgetSettings = widgetSettings,
clientId = clientId,
diff --git a/features/call/impl/src/main/kotlin/io/element/android/features/call/impl/utils/WebViewAudioManager.kt b/features/call/impl/src/main/kotlin/io/element/android/features/call/impl/utils/WebViewAudioManager.kt
index 51f758a3bb..7745cda13b 100644
--- a/features/call/impl/src/main/kotlin/io/element/android/features/call/impl/utils/WebViewAudioManager.kt
+++ b/features/call/impl/src/main/kotlin/io/element/android/features/call/impl/utils/WebViewAudioManager.kt
@@ -29,7 +29,7 @@ import kotlinx.serialization.json.Json
import timber.log.Timber
import java.util.concurrent.Executors
import java.util.concurrent.atomic.AtomicBoolean
-import kotlin.time.Duration.Companion.milliseconds
+import kotlin.time.Duration.Companion.seconds
/**
* This class manages the audio devices for a WebView.
@@ -246,7 +246,6 @@ class WebViewAudioManager(
private fun registerWebViewDeviceSelectedCallback() {
val webViewAudioDeviceSelectedCallback = AndroidWebViewAudioBridge(
onAudioDeviceSelected = { selectedDeviceId ->
- Timber.d("Audio device selected in webview, id: $selectedDeviceId")
previousSelectedDevice = listAudioDevices().find { it.id.toString() == selectedDeviceId }
audioManager.selectAudioDevice(selectedDeviceId)
},
@@ -254,7 +253,7 @@ class WebViewAudioManager(
coroutineScope.launch(Dispatchers.Main) {
// Even with the callback, it seems like starting the audio takes a bit on the webview side,
// so we add an extra delay here to make sure it's ready
- delay(500.milliseconds)
+ delay(2.seconds)
// Calling this ahead of time makes the default audio device to not use the right audio stream
setAvailableAudioDevices()
diff --git a/features/call/impl/src/test/kotlin/io/element/android/features/call/DefaultElementCallEntryPointTest.kt b/features/call/impl/src/test/kotlin/io/element/android/features/call/DefaultElementCallEntryPointTest.kt
index 86d9b80d65..7d0f15b540 100644
--- a/features/call/impl/src/test/kotlin/io/element/android/features/call/DefaultElementCallEntryPointTest.kt
+++ b/features/call/impl/src/test/kotlin/io/element/android/features/call/DefaultElementCallEntryPointTest.kt
@@ -59,6 +59,7 @@ class DefaultElementCallEntryPointTest {
senderName = "senderName",
avatarUrl = "avatarUrl",
timestamp = 0,
+ expirationTimestamp = 0,
notificationChannelId = "notificationChannelId",
textContent = "textContent",
)
diff --git a/features/call/impl/src/test/kotlin/io/element/android/features/call/notifications/RingingCallNotificationCreatorTest.kt b/features/call/impl/src/test/kotlin/io/element/android/features/call/notifications/RingingCallNotificationCreatorTest.kt
index f36267a353..0af482fc49 100644
--- a/features/call/impl/src/test/kotlin/io/element/android/features/call/notifications/RingingCallNotificationCreatorTest.kt
+++ b/features/call/impl/src/test/kotlin/io/element/android/features/call/notifications/RingingCallNotificationCreatorTest.kt
@@ -73,6 +73,7 @@ class RingingCallNotificationCreatorTest {
roomAvatarUrl = "https://example.com/avatar.jpg",
notificationChannelId = "channelId",
timestamp = 0L,
+ expirationTimestamp = 20L,
textContent = "textContent",
)
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 15f1334773..47a91afa1c 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
@@ -215,7 +215,7 @@ import kotlin.time.Duration.Companion.seconds
}
@Test
- fun `present - a received 'joined' action makes the call to be active`() = runTest {
+ fun `present - a received 'content loaded' action makes the call to be active`() = runTest {
val navigator = FakeCallScreenNavigator()
val widgetDriver = FakeMatrixWidgetDriver()
val presenter = createCallScreenPresenter(
@@ -238,7 +238,7 @@ import kotlin.time.Duration.Companion.seconds
messageInterceptor.givenInterceptedMessage(
"""
{
- "action":"io.element.join",
+ "action":"content_loaded",
"api":"fromWidget",
"widgetId":"1",
"requestId":"1"
diff --git a/features/call/impl/src/test/kotlin/io/element/android/features/call/utils/DefaultActiveCallManagerTest.kt b/features/call/impl/src/test/kotlin/io/element/android/features/call/utils/DefaultActiveCallManagerTest.kt
index 84084c38fe..3d1c35df4d 100644
--- a/features/call/impl/src/test/kotlin/io/element/android/features/call/utils/DefaultActiveCallManagerTest.kt
+++ b/features/call/impl/src/test/kotlin/io/element/android/features/call/utils/DefaultActiveCallManagerTest.kt
@@ -22,13 +22,16 @@ import io.element.android.features.call.test.aCallNotificationData
import io.element.android.libraries.matrix.api.core.EventId
import io.element.android.libraries.matrix.api.core.RoomId
import io.element.android.libraries.matrix.api.core.SessionId
+import io.element.android.libraries.matrix.api.room.JoinedRoom
import io.element.android.libraries.matrix.test.AN_EVENT_ID
+import io.element.android.libraries.matrix.test.AN_EVENT_ID_2
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_SESSION_ID
import io.element.android.libraries.matrix.test.FakeMatrixClient
import io.element.android.libraries.matrix.test.FakeMatrixClientProvider
import io.element.android.libraries.matrix.test.room.FakeBaseRoom
+import io.element.android.libraries.matrix.test.room.FakeJoinedRoom
import io.element.android.libraries.matrix.test.room.aRoomInfo
import io.element.android.libraries.push.api.notifications.ForegroundServiceType
import io.element.android.libraries.push.api.notifications.NotificationIdProvider
@@ -36,8 +39,12 @@ import io.element.android.libraries.push.test.notifications.FakeImageLoaderHolde
import io.element.android.libraries.push.test.notifications.FakeOnMissedCallNotificationHandler
import io.element.android.libraries.push.test.notifications.push.FakeNotificationBitmapLoader
import io.element.android.services.appnavstate.test.FakeAppForegroundStateService
+import io.element.android.services.toolbox.test.systemclock.A_FAKE_TIMESTAMP
+import io.element.android.services.toolbox.test.systemclock.FakeSystemClock
import io.element.android.tests.testutils.lambda.lambdaRecorder
import io.element.android.tests.testutils.lambda.value
+import io.element.android.tests.testutils.plantTestTimber
+import io.mockk.coVerify
import io.mockk.mockk
import io.mockk.verify
import kotlinx.coroutines.ExperimentalCoroutinesApi
@@ -164,6 +171,102 @@ class DefaultActiveCallManagerTest {
verify { notificationManagerCompat.cancel(notificationId) }
}
+ @Test
+ fun `Decline event - Hangup on a ringing call should send a decline event`() = runTest {
+ setupShadowPowerManager()
+ val notificationManagerCompat = mockk(relaxed = true)
+
+ val room = mockk(relaxed = true)
+
+ val matrixClient = FakeMatrixClient().apply {
+ givenGetRoomResult(A_ROOM_ID, room)
+ }
+ val clientProvider = FakeMatrixClientProvider({ Result.success(matrixClient) })
+
+ val manager = createActiveCallManager(
+ matrixClientProvider = clientProvider,
+ notificationManagerCompat = notificationManagerCompat
+ )
+
+ val notificationData = aCallNotificationData(roomId = A_ROOM_ID)
+ manager.registerIncomingCall(notificationData)
+
+ manager.hungUpCall(CallType.RoomCall(notificationData.sessionId, notificationData.roomId))
+
+ coVerify {
+ room.declineCall(notificationEventId = notificationData.eventId)
+ }
+ }
+
+ @OptIn(ExperimentalCoroutinesApi::class)
+ @Test
+ fun `Decline event - Declining from another session should stop ringing`() = runTest {
+ setupShadowPowerManager()
+ val notificationManagerCompat = mockk(relaxed = true)
+
+ val room = FakeJoinedRoom()
+
+ val matrixClient = FakeMatrixClient().apply {
+ givenGetRoomResult(A_ROOM_ID, room)
+ }
+ val clientProvider = FakeMatrixClientProvider({ Result.success(matrixClient) })
+
+ val manager = createActiveCallManager(
+ matrixClientProvider = clientProvider,
+ notificationManagerCompat = notificationManagerCompat
+ )
+
+ val notificationData = aCallNotificationData(roomId = A_ROOM_ID)
+ manager.registerIncomingCall(notificationData)
+
+ runCurrent()
+
+ // Simulate declined from other session
+ room.baseRoom.givenDecliner(matrixClient.sessionId, notificationData.eventId)
+
+ runCurrent()
+
+ assertThat(manager.activeCall.value).isNull()
+ assertThat(manager.activeWakeLock?.isHeld).isFalse()
+
+ verify { notificationManagerCompat.cancel(notificationId) }
+ }
+
+ @OptIn(ExperimentalCoroutinesApi::class)
+ @Test
+ fun `Decline event - Should ignore decline for other notification events`() = runTest {
+ plantTestTimber()
+ setupShadowPowerManager()
+ val notificationManagerCompat = mockk(relaxed = true)
+
+ val room = FakeJoinedRoom()
+
+ val matrixClient = FakeMatrixClient().apply {
+ givenGetRoomResult(A_ROOM_ID, room)
+ }
+ val clientProvider = FakeMatrixClientProvider({ Result.success(matrixClient) })
+
+ val manager = createActiveCallManager(
+ matrixClientProvider = clientProvider,
+ notificationManagerCompat = notificationManagerCompat
+ )
+
+ val notificationData = aCallNotificationData(roomId = A_ROOM_ID)
+ manager.registerIncomingCall(notificationData)
+
+ runCurrent()
+
+ // Simulate declined for another notification event
+ room.baseRoom.givenDecliner(matrixClient.sessionId, AN_EVENT_ID_2)
+
+ runCurrent()
+
+ assertThat(manager.activeCall.value).isNotNull()
+ assertThat(manager.activeWakeLock?.isHeld).isTrue()
+
+ verify(exactly = 0) { notificationManagerCompat.cancel(notificationId) }
+ }
+
@Test
fun `hungUpCall - does nothing if the CallType doesn't match`() = runTest {
setupShadowPowerManager()
@@ -267,6 +370,83 @@ class DefaultActiveCallManagerTest {
assertThat(manager.activeCall.value).isNotNull()
}
+ @OptIn(ExperimentalCoroutinesApi::class)
+ @Test
+ fun `IncomingCall - rings no longer than expiration time`() = runTest {
+ setupShadowPowerManager()
+ val notificationManagerCompat = mockk(relaxed = true)
+ val clock = FakeSystemClock()
+ val manager = createActiveCallManager(notificationManagerCompat = notificationManagerCompat, systemClock = clock)
+
+ assertThat(manager.activeWakeLock?.isHeld).isFalse()
+ assertThat(manager.activeCall.value).isNull()
+
+ val eventTimestamp = A_FAKE_TIMESTAMP
+ // The call should not ring more than 30 seconds after the initial event was sent
+ val expirationTimestamp = eventTimestamp + 30_000
+
+ val callNotificationData = aCallNotificationData(
+ timestamp = eventTimestamp,
+ expirationTimestamp = expirationTimestamp,
+ )
+
+ // suppose it took 10s to be notified
+ clock.epochMillisResult = eventTimestamp + 10_000
+ manager.registerIncomingCall(callNotificationData)
+
+ assertThat(manager.activeCall.value).isEqualTo(
+ ActiveCall(
+ callType = CallType.RoomCall(
+ sessionId = callNotificationData.sessionId,
+ roomId = callNotificationData.roomId,
+ ),
+ callState = CallState.Ringing(callNotificationData)
+ )
+ )
+
+ runCurrent()
+
+ assertThat(manager.activeWakeLock?.isHeld).isTrue()
+ verify { notificationManagerCompat.notify(notificationId, any()) }
+
+ // advance by 21s it should have stopped ringing
+ advanceTimeBy(21_000)
+ runCurrent()
+
+ verify { notificationManagerCompat.cancel(any()) }
+ }
+ @OptIn(ExperimentalCoroutinesApi::class)
+ @Test
+ fun `IncomingCall - ignore expired ring lifetime`() = runTest {
+ setupShadowPowerManager()
+ val notificationManagerCompat = mockk(relaxed = true)
+ val clock = FakeSystemClock()
+ val manager = createActiveCallManager(notificationManagerCompat = notificationManagerCompat, systemClock = clock)
+
+ assertThat(manager.activeWakeLock?.isHeld).isFalse()
+ assertThat(manager.activeCall.value).isNull()
+
+ val eventTimestamp = A_FAKE_TIMESTAMP
+ // The call should not ring more than 30 seconds after the initial event was sent
+ val expirationTimestamp = eventTimestamp + 30_000
+
+ val callNotificationData = aCallNotificationData(
+ timestamp = eventTimestamp,
+ expirationTimestamp = expirationTimestamp,
+ )
+
+ // suppose it took 35s to be notified
+ clock.epochMillisResult = eventTimestamp + 35_000
+ manager.registerIncomingCall(callNotificationData)
+
+ assertThat(manager.activeCall.value).isNull()
+
+ runCurrent()
+
+ assertThat(manager.activeWakeLock?.isHeld).isFalse()
+ verify(exactly = 0) { notificationManagerCompat.notify(notificationId, any()) }
+ }
+
private fun setupShadowPowerManager() {
shadowOf(InstrumentationRegistry.getInstrumentation().targetContext.getSystemService()).apply {
setIsWakeLockLevelSupported(PowerManager.PARTIAL_WAKE_LOCK, true)
@@ -277,6 +457,7 @@ class DefaultActiveCallManagerTest {
matrixClientProvider: FakeMatrixClientProvider = FakeMatrixClientProvider(),
onMissedCallNotificationHandler: FakeOnMissedCallNotificationHandler = FakeOnMissedCallNotificationHandler(),
notificationManagerCompat: NotificationManagerCompat = mockk(relaxed = true),
+ systemClock: FakeSystemClock = FakeSystemClock(),
) = DefaultActiveCallManager(
context = InstrumentationRegistry.getInstrumentation().targetContext,
coroutineScope = backgroundScope,
@@ -292,5 +473,6 @@ class DefaultActiveCallManagerTest {
defaultCurrentCallService = DefaultCurrentCallService(),
appForegroundStateService = FakeAppForegroundStateService(),
imageLoaderHolder = FakeImageLoaderHolder(),
+ systemClock = systemClock,
)
}
diff --git a/features/call/test/src/main/kotlin/io/element/android/features/call/test/CallNotificationData.kt b/features/call/test/src/main/kotlin/io/element/android/features/call/test/CallNotificationData.kt
index 8e6ee00a16..2c56ab299b 100644
--- a/features/call/test/src/main/kotlin/io/element/android/features/call/test/CallNotificationData.kt
+++ b/features/call/test/src/main/kotlin/io/element/android/features/call/test/CallNotificationData.kt
@@ -30,6 +30,7 @@ fun aCallNotificationData(
avatarUrl: String? = AN_AVATAR_URL,
notificationChannelId: String = "channel_id",
timestamp: Long = 0L,
+ expirationTimestamp: Long = 30_000L,
textContent: String? = null,
): CallNotificationData = CallNotificationData(
sessionId = sessionId,
@@ -41,5 +42,6 @@ fun aCallNotificationData(
avatarUrl = avatarUrl,
notificationChannelId = notificationChannelId,
timestamp = timestamp,
+ expirationTimestamp = expirationTimestamp,
textContent = textContent,
)
diff --git a/features/call/test/src/main/kotlin/io/element/android/features/call/test/FakeElementCallEntryPoint.kt b/features/call/test/src/main/kotlin/io/element/android/features/call/test/FakeElementCallEntryPoint.kt
index 09a1269259..cd2e617b4d 100644
--- a/features/call/test/src/main/kotlin/io/element/android/features/call/test/FakeElementCallEntryPoint.kt
+++ b/features/call/test/src/main/kotlin/io/element/android/features/call/test/FakeElementCallEntryPoint.kt
@@ -38,6 +38,7 @@ class FakeElementCallEntryPoint(
senderName: String?,
avatarUrl: String?,
timestamp: Long,
+ expirationTimestamp: Long,
notificationChannelId: String,
textContent: String?,
) {
diff --git a/features/changeroommemberroles/api/src/main/kotlin/io/element/android/features/changeroommemberroes/api/ChangeRoomMemberRolesEntryPoint.kt b/features/changeroommemberroles/api/src/main/kotlin/io/element/android/features/changeroommemberroes/api/ChangeRoomMemberRolesEntryPoint.kt
index 0175cdf247..b6f7680b38 100644
--- a/features/changeroommemberroles/api/src/main/kotlin/io/element/android/features/changeroommemberroes/api/ChangeRoomMemberRolesEntryPoint.kt
+++ b/features/changeroommemberroles/api/src/main/kotlin/io/element/android/features/changeroommemberroes/api/ChangeRoomMemberRolesEntryPoint.kt
@@ -14,7 +14,7 @@ import io.element.android.libraries.architecture.NodeInputs
import io.element.android.libraries.matrix.api.core.RoomId
import io.element.android.libraries.matrix.api.room.JoinedRoom
-interface ChangeRoomMemberRolesEntryPoint : FeatureEntryPoint {
+fun interface ChangeRoomMemberRolesEntryPoint : FeatureEntryPoint {
fun builder(parentNode: Node, buildContext: BuildContext): Builder
interface Builder {
diff --git a/features/changeroommemberroles/impl/build.gradle.kts b/features/changeroommemberroles/impl/build.gradle.kts
index fe5cbe3333..be2bf17979 100644
--- a/features/changeroommemberroles/impl/build.gradle.kts
+++ b/features/changeroommemberroles/impl/build.gradle.kts
@@ -1,4 +1,5 @@
import extension.setupDependencyInjection
+import extension.testCommonDependencies
/*
* Copyright 2025 New Vector Ltd.
@@ -37,15 +38,7 @@ dependencies {
implementation(projects.libraries.uiStrings)
implementation(projects.services.analytics.api)
+ testCommonDependencies(libs, true)
testImplementation(projects.services.analytics.test)
- testImplementation(libs.test.junit)
- testImplementation(libs.coroutines.test)
- testImplementation(libs.molecule.runtime)
- testImplementation(libs.test.robolectric)
- testImplementation(libs.test.truth)
- testImplementation(libs.test.turbine)
testImplementation(projects.libraries.matrix.test)
- testImplementation(projects.tests.testutils)
- testImplementation(libs.androidx.compose.ui.test.junit)
- testReleaseImplementation(libs.androidx.compose.ui.test.manifest)
}
diff --git a/features/changeroommemberroles/impl/src/main/kotlin/io/element/android/features/changeroommemberroles/impl/ChangeRolesNode.kt b/features/changeroommemberroles/impl/src/main/kotlin/io/element/android/features/changeroommemberroles/impl/ChangeRolesNode.kt
index 342fba632f..697297372f 100644
--- a/features/changeroommemberroles/impl/src/main/kotlin/io/element/android/features/changeroommemberroles/impl/ChangeRolesNode.kt
+++ b/features/changeroommemberroles/impl/src/main/kotlin/io/element/android/features/changeroommemberroles/impl/ChangeRolesNode.kt
@@ -37,16 +37,7 @@ class ChangeRolesNode(
) : NodeInputs
private val inputs: Inputs = inputs()
-
- private val presenter = presenterFactory.run {
- val role = when (inputs.listType) {
- ChangeRoomMemberRolesListType.Admins -> RoomMember.Role.Admin
- ChangeRoomMemberRolesListType.Moderators -> RoomMember.Role.Moderator
- ChangeRoomMemberRolesListType.SelectNewOwnersWhenLeaving -> RoomMember.Role.Owner(isCreator = false)
- }
- create(role)
- }
-
+ private val presenter = presenterFactory.create(inputs.listType.toRoomMemberRole())
private val stateFlow = launchMolecule { presenter.present() }
suspend fun waitForRoleChanged() {
@@ -63,3 +54,9 @@ class ChangeRolesNode(
)
}
}
+
+internal fun ChangeRoomMemberRolesListType.toRoomMemberRole() = when (this) {
+ ChangeRoomMemberRolesListType.Admins -> RoomMember.Role.Admin
+ ChangeRoomMemberRolesListType.Moderators -> RoomMember.Role.Moderator
+ ChangeRoomMemberRolesListType.SelectNewOwnersWhenLeaving -> RoomMember.Role.Owner(isCreator = false)
+}
diff --git a/features/changeroommemberroles/impl/src/main/kotlin/io/element/android/features/changeroommemberroles/impl/ChangeRolesPresenter.kt b/features/changeroommemberroles/impl/src/main/kotlin/io/element/android/features/changeroommemberroles/impl/ChangeRolesPresenter.kt
index a6d0ed6a51..cf43874b10 100644
--- a/features/changeroommemberroles/impl/src/main/kotlin/io/element/android/features/changeroommemberroles/impl/ChangeRolesPresenter.kt
+++ b/features/changeroommemberroles/impl/src/main/kotlin/io/element/android/features/changeroommemberroles/impl/ChangeRolesPresenter.kt
@@ -55,7 +55,7 @@ class ChangeRolesPresenter(
private val analyticsService: AnalyticsService,
) : Presenter {
@AssistedFactory
- interface Factory {
+ fun interface Factory {
fun create(role: RoomMember.Role): ChangeRolesPresenter
}
diff --git a/features/changeroommemberroles/impl/src/main/kotlin/io/element/android/features/changeroommemberroles/impl/ChangeRoomMemberRolesRootNode.kt b/features/changeroommemberroles/impl/src/main/kotlin/io/element/android/features/changeroommemberroles/impl/ChangeRoomMemberRolesRootNode.kt
index 0ce019aa16..5055761e6e 100644
--- a/features/changeroommemberroles/impl/src/main/kotlin/io/element/android/features/changeroommemberroles/impl/ChangeRoomMemberRolesRootNode.kt
+++ b/features/changeroommemberroles/impl/src/main/kotlin/io/element/android/features/changeroommemberroles/impl/ChangeRoomMemberRolesRootNode.kt
@@ -39,16 +39,13 @@ class ChangeRoomMemberRolesRootNode(
roomComponentFactory: RoomComponentFactory,
) : ParentNode(
navModel = PermanentNavModel(
- navTargets = setOf(NavTarget.Root),
+ navTargets = setOf(NavTarget),
savedStateMap = buildContext.savedStateMap,
),
buildContext = buildContext,
plugins = plugins,
), DependencyInjectionGraphOwner, ChangeRoomMemberRolesEntryPoint.NodeProxy {
- sealed interface NavTarget : Parcelable {
- @Parcelize
- object Root : NavTarget
- }
+ @Parcelize object NavTarget : Parcelable
data class Inputs(
val joinedRoom: JoinedRoom,
@@ -60,14 +57,10 @@ class ChangeRoomMemberRolesRootNode(
override val graph = roomComponentFactory.create(inputs.joinedRoom)
override fun resolve(navTarget: NavTarget, buildContext: BuildContext): Node {
- return when (navTarget) {
- NavTarget.Root -> {
- createNode(
- buildContext = buildContext,
- plugins = listOf(ChangeRolesNode.Inputs(listType = inputs.listType)),
- )
- }
- }
+ return createNode(
+ buildContext = buildContext,
+ plugins = listOf(ChangeRolesNode.Inputs(listType = inputs.listType)),
+ )
}
@Composable
diff --git a/features/changeroommemberroles/impl/src/main/res/values-cy/translations.xml b/features/changeroommemberroles/impl/src/main/res/values-cy/translations.xml
index 53d4927f0f..4740c15888 100644
--- a/features/changeroommemberroles/impl/src/main/res/values-cy/translations.xml
+++ b/features/changeroommemberroles/impl/src/main/res/values-cy/translations.xml
@@ -2,7 +2,7 @@
"Gweinyddwyr yn unig"
"Gwahardd pobl"
- "Dileu negeseuon"
+ "Tynnu negeseuon"
"Pawb"
"Gwahodd pobl a derbyn ceisiadau i ymuno"
"Cymedroli aelodau"
@@ -17,13 +17,17 @@
"Golygu Gweinyddwyr"
"Fyddwch chi ddim yn gallu dadwneud y weithred hon. Rydych chi\'n hyrwyddo\'r defnyddiwr i gael yr un lefel pŵer â chi."
"Ychwanegu Gweinyddwr?"
+ "Fyddwch chi ddim yn gallu dadwneud y weithred hon. Rydych yn trosglwyddo\'r berchnogaeth i\'r defnyddwyr a ddewiswyd. Unwaith y byddwch yn gadael bydd hyn yn barhaol."
+ "Trosglwyddo perchnogaeth?"
"Gostwng"
"Fyddwch chi ddim yn gallu dadwneud y newid hwn gan eich bod yn israddio eich hun, os mai chi yw\'r defnyddiwr breintiedig olaf yn yr ystafell bydd yn amhosibl adennill breintiau."
"Israddio eich hun?"
"%1$s (Yn aros)"
"Yn aros"
"Mae gan weinyddwyr freintiau cymedrolwr yn awtomatig"
+ "Mae gan berchnogion freintiau gweinyddwr yn awtomatig."
"Golygu Cymedrolwyr"
+ "Dewiswch Berchnogion"
"Gweinyddwyr"
"Cymedrolwyr"
"Aelodau"
@@ -48,15 +52,18 @@
"Dan ystyriaeth"
"Gweinyddwr"
"Cymedrolwr"
+ "Perchennog"
"Aelodau\'r ystafell"
"Dad-wahardd %1$s"
"Gweinyddwyr"
+ "Gweinyddwyr a pherchnogion"
"Newid fy rôl"
"Israddio aelod"
"Israddio cymedrolwr"
"Cymedroli aelodau"
"Negeseuon a chynnwys"
"Cymedrolwyr"
+ "Perchnogion"
"Caniatâd"
"Ailosod caniatâd"
"Ar ôl i chi ailosod caniatâd, byddwch yn colli\'r gosodiadau cyfredol."
diff --git a/features/changeroommemberroles/impl/src/main/res/values-fi/translations.xml b/features/changeroommemberroles/impl/src/main/res/values-fi/translations.xml
index b8ff96085a..1279d466e2 100644
--- a/features/changeroommemberroles/impl/src/main/res/values-fi/translations.xml
+++ b/features/changeroommemberroles/impl/src/main/res/values-fi/translations.xml
@@ -16,12 +16,12 @@
"Viestien lähettäminen"
"Muokkaa ylläpitäjiä"
"Et voi peruuttaa tätä toimenpidettä. Ylennät käyttäjän samalle oikeustasolle kuin sinä."
- "Lisää ylläpitäjä?"
+ "Lisätäänkö ylläpitäjä?"
"Et voi kumota tätä toimintoa. Olet siirtämässä omistajuuden valituille käyttäjille. Kun poistut, muutos on pysyvä."
"Siirretäänkö omistajuus?"
"Alenna"
"Et voi perua tätä muutosta, koska olet alentamassa itseäsi. Jos olet viimeinen oikeutettu henkilö tässä huoneessa, oikeuksia ei voi enää saada takaisin."
- "Alenna itsesi?"
+ "Haluatko alentaa itsesi?"
"%1$s (Kutsuttu)"
"(Kutsuttu)"
"Ylläpitäjillä on automaattisesti valvojan oikeudet"
@@ -32,7 +32,7 @@
"Valvojat"
"Jäsenet"
"Sinulla on tallentamattomia muutoksia"
- "Tallenna muutokset?"
+ "Tallennetaanko muutokset?"
"Tässä huoneessa ei ole porttikieltoja"
- "%1$d henkilö"
diff --git a/features/changeroommemberroles/impl/src/test/kotlin/io/element/android/features/changeroommemberroles/impl/ChangeRolesNodeTest.kt b/features/changeroommemberroles/impl/src/test/kotlin/io/element/android/features/changeroommemberroles/impl/ChangeRolesNodeTest.kt
new file mode 100644
index 0000000000..5a47f52e89
--- /dev/null
+++ b/features/changeroommemberroles/impl/src/test/kotlin/io/element/android/features/changeroommemberroles/impl/ChangeRolesNodeTest.kt
@@ -0,0 +1,25 @@
+/*
+ * Copyright 2025 New Vector Ltd.
+ *
+ * SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial
+ * Please see LICENSE files in the repository root for full details.
+ */
+
+package io.element.android.features.changeroommemberroles.impl
+
+import com.google.common.truth.Truth.assertThat
+import io.element.android.features.changeroommemberroes.api.ChangeRoomMemberRolesListType
+import io.element.android.libraries.matrix.api.room.RoomMember
+import org.junit.Test
+
+class ChangeRolesNodeTest {
+ @Test
+ fun `test toRoomMemberRole`() {
+ assertThat(ChangeRoomMemberRolesListType.Admins.toRoomMemberRole())
+ .isEqualTo(RoomMember.Role.Admin)
+ assertThat(ChangeRoomMemberRolesListType.Moderators.toRoomMemberRole())
+ .isEqualTo(RoomMember.Role.Moderator)
+ assertThat(ChangeRoomMemberRolesListType.SelectNewOwnersWhenLeaving.toRoomMemberRole())
+ .isEqualTo(RoomMember.Role.Owner(false))
+ }
+}
diff --git a/features/changeroommemberroles/impl/src/test/kotlin/io/element/android/features/changeroommemberroles/impl/ChangeRolesPresenterTest.kt b/features/changeroommemberroles/impl/src/test/kotlin/io/element/android/features/changeroommemberroles/impl/ChangeRolesPresenterTest.kt
index a5b2da566c..e5e22b8846 100644
--- a/features/changeroommemberroles/impl/src/test/kotlin/io/element/android/features/changeroommemberroles/impl/ChangeRolesPresenterTest.kt
+++ b/features/changeroommemberroles/impl/src/test/kotlin/io/element/android/features/changeroommemberroles/impl/ChangeRolesPresenterTest.kt
@@ -37,7 +37,6 @@ import kotlinx.collections.immutable.toPersistentMap
import kotlinx.coroutines.test.TestScope
import kotlinx.coroutines.test.runTest
import org.junit.Test
-import kotlin.collections.plus
class ChangeRolesPresenterTest {
@Test
@@ -556,18 +555,18 @@ class ChangeRolesPresenterTest {
users = pairs.associate { (userId, role) -> userId to role.powerLevel }.toPersistentMap()
)
}
-
- private fun TestScope.createChangeRolesPresenter(
- role: RoomMember.Role = RoomMember.Role.Admin,
- room: FakeJoinedRoom = FakeJoinedRoom(baseRoom = FakeBaseRoom(updateMembersResult = {})),
- dispatchers: CoroutineDispatchers = testCoroutineDispatchers(),
- analyticsService: FakeAnalyticsService = FakeAnalyticsService(),
- ): ChangeRolesPresenter {
- return ChangeRolesPresenter(
- role = role,
- room = room,
- dispatchers = dispatchers,
- analyticsService = analyticsService,
- )
- }
+}
+
+internal fun TestScope.createChangeRolesPresenter(
+ role: RoomMember.Role = RoomMember.Role.Admin,
+ room: FakeJoinedRoom = FakeJoinedRoom(baseRoom = FakeBaseRoom(updateMembersResult = {})),
+ dispatchers: CoroutineDispatchers = testCoroutineDispatchers(),
+ analyticsService: FakeAnalyticsService = FakeAnalyticsService(),
+): ChangeRolesPresenter {
+ return ChangeRolesPresenter(
+ role = role,
+ room = room,
+ dispatchers = dispatchers,
+ analyticsService = analyticsService,
+ )
}
diff --git a/features/changeroommemberroles/impl/src/test/kotlin/io/element/android/features/changeroommemberroles/impl/DefaultChangeRoomMemberRolesEntyPointTest.kt b/features/changeroommemberroles/impl/src/test/kotlin/io/element/android/features/changeroommemberroles/impl/DefaultChangeRoomMemberRolesEntyPointTest.kt
new file mode 100644
index 0000000000..5f68fe5970
--- /dev/null
+++ b/features/changeroommemberroles/impl/src/test/kotlin/io/element/android/features/changeroommemberroles/impl/DefaultChangeRoomMemberRolesEntyPointTest.kt
@@ -0,0 +1,44 @@
+/*
+ * Copyright 2025 New Vector Ltd.
+ *
+ * SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial
+ * Please see LICENSE files in the repository root for full details.
+ */
+
+package io.element.android.features.changeroommemberroles.impl
+
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import com.bumble.appyx.core.modality.BuildContext
+import com.google.common.truth.Truth.assertThat
+import io.element.android.features.changeroommemberroes.api.ChangeRoomMemberRolesListType
+import io.element.android.libraries.matrix.test.room.FakeJoinedRoom
+import io.element.android.tests.testutils.node.TestParentNode
+import kotlinx.coroutines.test.runTest
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@RunWith(AndroidJUnit4::class)
+class DefaultChangeRoomMemberRolesEntyPointTest {
+ @Test
+ fun `test node builder`() = runTest {
+ val entryPoint = DefaultChangeRoomMemberRolesEntyPoint()
+ val parentNode = TestParentNode.create { buildContext, plugins ->
+ ChangeRoomMemberRolesRootNode(
+ buildContext = buildContext,
+ plugins = plugins,
+ roomComponentFactory = { },
+ )
+ }
+ val room = FakeJoinedRoom()
+ val listType = ChangeRoomMemberRolesListType.Admins
+ val result = entryPoint.builder(parentNode, BuildContext.root(null))
+ .room(FakeJoinedRoom())
+ .listType(listType)
+ .build()
+ assertThat(result).isInstanceOf(ChangeRoomMemberRolesRootNode::class.java)
+ // Search for the Inputs plugin
+ val input = result.plugins.filterIsInstance().single()
+ assertThat(input.joinedRoom.roomId).isEqualTo(room.roomId)
+ assertThat(input.listType).isEqualTo(listType)
+ }
+}
diff --git a/features/createroom/impl/build.gradle.kts b/features/createroom/impl/build.gradle.kts
index faf293c54d..712ce110f8 100644
--- a/features/createroom/impl/build.gradle.kts
+++ b/features/createroom/impl/build.gradle.kts
@@ -1,4 +1,5 @@
import extension.setupDependencyInjection
+import extension.testCommonDependencies
/*
* Copyright 2022-2024 New Vector Ltd.
@@ -43,13 +44,7 @@ dependencies {
implementation(projects.features.invitepeople.api)
api(projects.features.createroom.api)
- testImplementation(libs.test.junit)
- testImplementation(libs.test.mockk)
- testImplementation(libs.coroutines.test)
- testImplementation(libs.molecule.runtime)
- testImplementation(libs.test.truth)
- testImplementation(libs.test.turbine)
- testImplementation(libs.test.robolectric)
+ testCommonDependencies(libs, true)
testImplementation(projects.services.analytics.test)
testImplementation(projects.libraries.matrix.test)
testImplementation(projects.libraries.mediapickers.test)
@@ -58,7 +53,4 @@ dependencies {
testImplementation(projects.libraries.usersearch.test)
testImplementation(projects.features.startchat.test)
testImplementation(projects.libraries.featureflag.test)
- testImplementation(projects.tests.testutils)
- testImplementation(libs.androidx.compose.ui.test.junit)
- testReleaseImplementation(libs.androidx.compose.ui.test.manifest)
}
diff --git a/features/createroom/impl/src/test/kotlin/io/element/android/features/createroom/impl/DefaultCreateRoomEntryPointTest.kt b/features/createroom/impl/src/test/kotlin/io/element/android/features/createroom/impl/DefaultCreateRoomEntryPointTest.kt
new file mode 100644
index 0000000000..61c7c052c5
--- /dev/null
+++ b/features/createroom/impl/src/test/kotlin/io/element/android/features/createroom/impl/DefaultCreateRoomEntryPointTest.kt
@@ -0,0 +1,46 @@
+/*
+ * Copyright 2025 New Vector Ltd.
+ *
+ * SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial
+ * Please see LICENSE files in the repository root for full details.
+ */
+
+package io.element.android.features.createroom.impl
+
+import androidx.arch.core.executor.testing.InstantTaskExecutorRule
+import com.bumble.appyx.core.modality.BuildContext
+import com.bumble.appyx.testing.junit4.util.MainDispatcherRule
+import com.google.common.truth.Truth.assertThat
+import io.element.android.features.createroom.api.CreateRoomEntryPoint
+import io.element.android.libraries.matrix.api.core.RoomId
+import io.element.android.tests.testutils.lambda.lambdaError
+import io.element.android.tests.testutils.node.TestParentNode
+import org.junit.Rule
+import org.junit.Test
+
+class DefaultCreateRoomEntryPointTest {
+ @get:Rule
+ val instantTaskExecutorRule = InstantTaskExecutorRule()
+
+ @get:Rule
+ val mainDispatcherRule = MainDispatcherRule()
+
+ @Test
+ fun `test node builder`() {
+ val entryPoint = DefaultCreateRoomEntryPoint()
+
+ val parentNode = TestParentNode.create { buildContext, plugins ->
+ CreateRoomFlowNode(
+ buildContext = buildContext,
+ plugins = plugins,
+ )
+ }
+ val callback = object : CreateRoomEntryPoint.Callback {
+ override fun onRoomCreated(roomId: RoomId) = lambdaError()
+ }
+ val result = entryPoint.nodeBuilder(parentNode, BuildContext.root(null))
+ .callback(callback)
+ .build()
+ assertThat(result.plugins).contains(callback)
+ }
+}
diff --git a/features/deactivation/impl/build.gradle.kts b/features/deactivation/impl/build.gradle.kts
index 3908b9d0a4..842206bab7 100644
--- a/features/deactivation/impl/build.gradle.kts
+++ b/features/deactivation/impl/build.gradle.kts
@@ -1,4 +1,5 @@
import extension.setupDependencyInjection
+import extension.testCommonDependencies
/*
* Copyright 2024 New Vector Ltd.
@@ -34,14 +35,6 @@ dependencies {
implementation(projects.libraries.uiStrings)
api(projects.features.deactivation.api)
- testImplementation(libs.test.junit)
- testImplementation(libs.coroutines.test)
- testImplementation(libs.molecule.runtime)
- testImplementation(libs.test.truth)
- testImplementation(libs.test.turbine)
- testImplementation(libs.test.robolectric)
- testImplementation(libs.androidx.compose.ui.test.junit)
- testReleaseImplementation(libs.androidx.compose.ui.test.manifest)
+ testCommonDependencies(libs, true)
testImplementation(projects.libraries.matrix.test)
- testImplementation(projects.tests.testutils)
}
diff --git a/features/deactivation/impl/src/main/res/values-eo/translations.xml b/features/deactivation/impl/src/main/res/values-eo/translations.xml
new file mode 100644
index 0000000000..75c2c252e7
--- /dev/null
+++ b/features/deactivation/impl/src/main/res/values-eo/translations.xml
@@ -0,0 +1,4 @@
+
+
+ "Delete your account information from our server."
+
diff --git a/features/deactivation/impl/src/main/res/values-pt/translations.xml b/features/deactivation/impl/src/main/res/values-pt/translations.xml
index 536f4cec34..0a8c618e44 100644
--- a/features/deactivation/impl/src/main/res/values-pt/translations.xml
+++ b/features/deactivation/impl/src/main/res/values-pt/translations.xml
@@ -1,6 +1,6 @@
- "Confirme que pretende desativar a sua conta. Esta ação não pode ser desfeita."
+ "Confirma que pretendes desativar a tua conta. Esta ação não pode ser desfeita."
"Eliminar todas as minhas mensagens"
"Aviso: futuros usuários podem ver conversas incompletas."
"A desativação da sua conta é %1$s, irá:"
diff --git a/features/deactivation/impl/src/test/kotlin/io/element/android/features/logout/impl/AccountDeactivationPresenterTest.kt b/features/deactivation/impl/src/test/kotlin/io/element/android/features/logout/impl/AccountDeactivationPresenterTest.kt
index 1383bdde21..d0b9f57dd9 100644
--- a/features/deactivation/impl/src/test/kotlin/io/element/android/features/logout/impl/AccountDeactivationPresenterTest.kt
+++ b/features/deactivation/impl/src/test/kotlin/io/element/android/features/logout/impl/AccountDeactivationPresenterTest.kt
@@ -148,10 +148,10 @@ class AccountDeactivationPresenterTest {
assertThat(finalState2.accountDeactivationAction).isEqualTo(AsyncAction.Uninitialized)
}
}
-
- private fun createPresenter(
- matrixClient: MatrixClient = FakeMatrixClient(),
- ) = AccountDeactivationPresenter(
- matrixClient = matrixClient,
- )
}
+
+internal fun createPresenter(
+ matrixClient: MatrixClient = FakeMatrixClient(),
+) = AccountDeactivationPresenter(
+ matrixClient = matrixClient,
+)
diff --git a/features/deactivation/impl/src/test/kotlin/io/element/android/features/logout/impl/DefaultAccountDeactivationEntryPointTest.kt b/features/deactivation/impl/src/test/kotlin/io/element/android/features/logout/impl/DefaultAccountDeactivationEntryPointTest.kt
new file mode 100644
index 0000000000..05ad52efe9
--- /dev/null
+++ b/features/deactivation/impl/src/test/kotlin/io/element/android/features/logout/impl/DefaultAccountDeactivationEntryPointTest.kt
@@ -0,0 +1,34 @@
+/*
+ * Copyright 2025 New Vector Ltd.
+ *
+ * SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial
+ * Please see LICENSE files in the repository root for full details.
+ */
+
+package io.element.android.features.logout.impl
+
+import androidx.arch.core.executor.testing.InstantTaskExecutorRule
+import com.bumble.appyx.core.modality.BuildContext
+import com.google.common.truth.Truth.assertThat
+import io.element.android.tests.testutils.node.TestParentNode
+import org.junit.Rule
+import org.junit.Test
+
+class DefaultAccountDeactivationEntryPointTest {
+ @get:Rule
+ val instantTaskExecutorRule = InstantTaskExecutorRule()
+
+ @Test
+ fun `test node builder`() {
+ val entryPoint = DefaultAccountDeactivationEntryPoint()
+ val parentNode = TestParentNode.create { buildContext, plugins ->
+ AccountDeactivationNode(
+ buildContext = buildContext,
+ plugins = plugins,
+ presenter = createPresenter(),
+ )
+ }
+ val result = entryPoint.createNode(parentNode, BuildContext.root(null))
+ assertThat(result).isInstanceOf(AccountDeactivationNode::class.java)
+ }
+}
diff --git a/features/enterprise/impl-foss/build.gradle.kts b/features/enterprise/impl-foss/build.gradle.kts
index 0b32b5d97c..956c0e1900 100644
--- a/features/enterprise/impl-foss/build.gradle.kts
+++ b/features/enterprise/impl-foss/build.gradle.kts
@@ -1,4 +1,5 @@
import extension.setupDependencyInjection
+import extension.testCommonDependencies
/*
* Copyright 2024 New Vector Ltd.
@@ -22,8 +23,6 @@ dependencies {
implementation(projects.libraries.architecture)
implementation(projects.libraries.matrix.api)
- testImplementation(libs.coroutines.test)
- testImplementation(libs.test.junit)
- testImplementation(libs.test.truth)
+ testCommonDependencies(libs)
testImplementation(projects.libraries.matrix.test)
}
diff --git a/features/ftue/api/src/main/kotlin/io/element/android/features/ftue/api/FtueEntryPoint.kt b/features/ftue/api/src/main/kotlin/io/element/android/features/ftue/api/FtueEntryPoint.kt
index f719064fde..3d5aae3860 100644
--- a/features/ftue/api/src/main/kotlin/io/element/android/features/ftue/api/FtueEntryPoint.kt
+++ b/features/ftue/api/src/main/kotlin/io/element/android/features/ftue/api/FtueEntryPoint.kt
@@ -7,14 +7,6 @@
package io.element.android.features.ftue.api
-import com.bumble.appyx.core.modality.BuildContext
-import com.bumble.appyx.core.node.Node
-import io.element.android.libraries.architecture.FeatureEntryPoint
+import io.element.android.libraries.architecture.SimpleFeatureEntryPoint
-interface FtueEntryPoint : FeatureEntryPoint {
- fun nodeBuilder(parentNode: Node, buildContext: BuildContext): NodeBuilder
-
- interface NodeBuilder {
- fun build(): Node
- }
-}
+interface FtueEntryPoint : SimpleFeatureEntryPoint
diff --git a/features/ftue/api/src/main/kotlin/io/element/android/features/ftue/api/state/FtueService.kt b/features/ftue/api/src/main/kotlin/io/element/android/features/ftue/api/state/FtueService.kt
index 7ea26c548f..b596f328d5 100644
--- a/features/ftue/api/src/main/kotlin/io/element/android/features/ftue/api/state/FtueService.kt
+++ b/features/ftue/api/src/main/kotlin/io/element/android/features/ftue/api/state/FtueService.kt
@@ -15,9 +15,6 @@ import kotlinx.coroutines.flow.StateFlow
interface FtueService {
/** The current state of the FTUE. */
val state: StateFlow
-
- /** Reset the FTUE state. */
- suspend fun reset()
}
/** The state of the FTUE. */
diff --git a/features/ftue/impl/build.gradle.kts b/features/ftue/impl/build.gradle.kts
index 44ccf323b9..8f940ed29a 100644
--- a/features/ftue/impl/build.gradle.kts
+++ b/features/ftue/impl/build.gradle.kts
@@ -1,4 +1,5 @@
import extension.setupDependencyInjection
+import extension.testCommonDependencies
/*
* Copyright 2023, 2024 New Vector Ltd.
@@ -46,14 +47,7 @@ dependencies {
implementation(projects.services.toolbox.api)
implementation(projects.appconfig)
- testImplementation(libs.test.junit)
- testImplementation(libs.coroutines.test)
- testImplementation(libs.molecule.runtime)
- testImplementation(libs.test.truth)
- testImplementation(libs.test.turbine)
- testImplementation(libs.test.robolectric)
- testImplementation(libs.androidx.compose.ui.test.junit)
- testReleaseImplementation(libs.androidx.compose.ui.test.manifest)
+ testCommonDependencies(libs, true)
testImplementation(projects.libraries.matrix.test)
testImplementation(projects.services.analytics.test)
testImplementation(projects.services.analytics.noop)
@@ -61,5 +55,4 @@ dependencies {
testImplementation(projects.libraries.preferences.test)
testImplementation(projects.features.lockscreen.test)
testImplementation(projects.services.toolbox.test)
- testImplementation(projects.tests.testutils)
}
diff --git a/features/ftue/impl/src/main/kotlin/io/element/android/features/ftue/impl/DefaultFtueEntryPoint.kt b/features/ftue/impl/src/main/kotlin/io/element/android/features/ftue/impl/DefaultFtueEntryPoint.kt
index db3c6a9c91..4fa086f4cd 100644
--- a/features/ftue/impl/src/main/kotlin/io/element/android/features/ftue/impl/DefaultFtueEntryPoint.kt
+++ b/features/ftue/impl/src/main/kotlin/io/element/android/features/ftue/impl/DefaultFtueEntryPoint.kt
@@ -9,7 +9,6 @@ package io.element.android.features.ftue.impl
import com.bumble.appyx.core.modality.BuildContext
import com.bumble.appyx.core.node.Node
-import com.bumble.appyx.core.plugin.Plugin
import dev.zacsweers.metro.AppScope
import dev.zacsweers.metro.ContributesBinding
import dev.zacsweers.metro.Inject
@@ -19,13 +18,7 @@ import io.element.android.libraries.architecture.createNode
@ContributesBinding(AppScope::class)
@Inject
class DefaultFtueEntryPoint : FtueEntryPoint {
- override fun nodeBuilder(parentNode: Node, buildContext: BuildContext): FtueEntryPoint.NodeBuilder {
- val plugins = ArrayList()
-
- return object : FtueEntryPoint.NodeBuilder {
- override fun build(): Node {
- return parentNode.createNode(buildContext, plugins)
- }
- }
+ override fun createNode(parentNode: Node, buildContext: BuildContext): Node {
+ return parentNode.createNode(buildContext)
}
}
diff --git a/features/ftue/impl/src/main/kotlin/io/element/android/features/ftue/impl/FtueFlowNode.kt b/features/ftue/impl/src/main/kotlin/io/element/android/features/ftue/impl/FtueFlowNode.kt
index 1f4ca9e4ee..a4aa9f18d7 100644
--- a/features/ftue/impl/src/main/kotlin/io/element/android/features/ftue/impl/FtueFlowNode.kt
+++ b/features/ftue/impl/src/main/kotlin/io/element/android/features/ftue/impl/FtueFlowNode.kt
@@ -14,7 +14,6 @@ import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.lifecycle.lifecycleScope
-import com.bumble.appyx.core.lifecycle.subscribe
import com.bumble.appyx.core.modality.BuildContext
import com.bumble.appyx.core.node.Node
import com.bumble.appyx.core.plugin.Plugin
@@ -30,18 +29,16 @@ import io.element.android.features.ftue.impl.notifications.NotificationsOptInNod
import io.element.android.features.ftue.impl.sessionverification.FtueSessionVerificationFlowNode
import io.element.android.features.ftue.impl.state.DefaultFtueService
import io.element.android.features.ftue.impl.state.FtueStep
+import io.element.android.features.ftue.impl.state.InternalFtueState
import io.element.android.features.lockscreen.api.LockScreenEntryPoint
import io.element.android.libraries.architecture.BackstackView
import io.element.android.libraries.architecture.BaseFlowNode
import io.element.android.libraries.architecture.createNode
import io.element.android.libraries.designsystem.theme.components.CircularProgressIndicator
import io.element.android.libraries.di.SessionScope
-import io.element.android.services.analytics.api.AnalyticsService
-import kotlinx.coroutines.flow.distinctUntilChanged
-import kotlinx.coroutines.flow.filter
+import kotlinx.coroutines.flow.filterIsInstance
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach
-import kotlinx.coroutines.launch
import kotlinx.parcelize.Parcelize
@ContributesNode(SessionScope::class)
@@ -49,9 +46,8 @@ import kotlinx.parcelize.Parcelize
class FtueFlowNode(
@Assisted buildContext: BuildContext,
@Assisted plugins: List,
- private val ftueState: DefaultFtueService,
+ private val defaultFtueService: DefaultFtueService,
private val analyticsEntryPoint: AnalyticsEntryPoint,
- private val analyticsService: AnalyticsService,
private val lockScreenEntryPoint: LockScreenEntryPoint,
) : BaseFlowNode(
backstack = BackStack(
@@ -80,19 +76,11 @@ class FtueFlowNode(
override fun onBuilt() {
super.onBuilt()
-
- lifecycle.subscribe(onCreate = {
- moveToNextStepIfNeeded()
- })
-
- analyticsService.didAskUserConsentFlow
- .distinctUntilChanged()
- .onEach { moveToNextStepIfNeeded() }
- .launchIn(lifecycleScope)
-
- ftueState.isVerificationStatusKnown
- .filter { it }
- .onEach { moveToNextStepIfNeeded() }
+ defaultFtueService.ftueStepStateFlow
+ .filterIsInstance(InternalFtueState.Incomplete::class)
+ .onEach {
+ showStep(it.nextStep)
+ }
.launchIn(lifecycleScope)
}
@@ -104,7 +92,7 @@ class FtueFlowNode(
is NavTarget.SessionVerification -> {
val callback = object : FtueSessionVerificationFlowNode.Callback {
override fun onDone() {
- moveToNextStepIfNeeded()
+ defaultFtueService.onUserCompletedSessionVerification()
}
}
createNode(buildContext, listOf(callback))
@@ -112,7 +100,7 @@ class FtueFlowNode(
NavTarget.NotificationsOptIn -> {
val callback = object : NotificationsOptInNode.Callback {
override fun onNotificationsOptInFinished() {
- moveToNextStepIfNeeded()
+ defaultFtueService.updateFtueStep()
}
}
createNode(buildContext, listOf(callback))
@@ -123,7 +111,7 @@ class FtueFlowNode(
NavTarget.LockScreenSetup -> {
val callback = object : LockScreenEntryPoint.Callback {
override fun onSetupDone() {
- moveToNextStepIfNeeded()
+ defaultFtueService.updateFtueStep()
}
}
lockScreenEntryPoint.nodeBuilder(this, buildContext, LockScreenEntryPoint.Target.Setup)
@@ -133,8 +121,8 @@ class FtueFlowNode(
}
}
- private fun moveToNextStepIfNeeded() = lifecycleScope.launch {
- when (ftueState.getNextStep()) {
+ private fun showStep(ftueStep: FtueStep) {
+ when (ftueStep) {
FtueStep.WaitingForInitialState -> {
backstack.newRoot(NavTarget.Placeholder)
}
@@ -150,7 +138,6 @@ class FtueFlowNode(
FtueStep.LockscreenSetup -> {
backstack.newRoot(NavTarget.LockScreenSetup)
}
- null -> Unit
}
}
diff --git a/features/ftue/impl/src/main/kotlin/io/element/android/features/ftue/impl/state/DefaultFtueService.kt b/features/ftue/impl/src/main/kotlin/io/element/android/features/ftue/impl/state/DefaultFtueService.kt
index 43e85aa708..40f19b1e7a 100644
--- a/features/ftue/impl/src/main/kotlin/io/element/android/features/ftue/impl/state/DefaultFtueService.kt
+++ b/features/ftue/impl/src/main/kotlin/io/element/android/features/ftue/impl/state/DefaultFtueService.kt
@@ -9,13 +9,13 @@ package io.element.android.features.ftue.impl.state
import android.Manifest
import android.os.Build
-import androidx.annotation.VisibleForTesting
import dev.zacsweers.metro.ContributesBinding
import dev.zacsweers.metro.Inject
import dev.zacsweers.metro.SingleIn
import io.element.android.features.ftue.api.state.FtueService
import io.element.android.features.ftue.api.state.FtueState
import io.element.android.features.lockscreen.api.LockScreenService
+import io.element.android.libraries.core.coroutine.mapState
import io.element.android.libraries.di.SessionScope
import io.element.android.libraries.di.annotations.SessionCoroutineScope
import io.element.android.libraries.matrix.api.verification.SessionVerificationService
@@ -26,61 +26,70 @@ import io.element.android.services.analytics.api.AnalyticsService
import io.element.android.services.toolbox.api.sdk.BuildVersionSdkIntProvider
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.distinctUntilChanged
-import kotlinx.coroutines.flow.filter
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.flow.launchIn
-import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.onEach
+import kotlinx.coroutines.launch
@ContributesBinding(SessionScope::class)
@SingleIn(SessionScope::class)
@Inject
class DefaultFtueService(
private val sdkVersionProvider: BuildVersionSdkIntProvider,
- @SessionCoroutineScope sessionCoroutineScope: CoroutineScope,
+ @SessionCoroutineScope private val sessionCoroutineScope: CoroutineScope,
private val analyticsService: AnalyticsService,
private val permissionStateProvider: PermissionStateProvider,
private val lockScreenService: LockScreenService,
private val sessionVerificationService: SessionVerificationService,
private val sessionPreferencesStore: SessionPreferencesStore,
) : FtueService {
- override val state = MutableStateFlow(FtueState.Unknown)
+ private val userNeedsToConfirmSessionVerificationSuccess = MutableStateFlow(false)
- /**
- * This flow emits true when the FTUE flow is ready to be displayed.
- * In this case, the FTUE flow is ready when the session verification status is known.
- */
- val isVerificationStatusKnown = sessionVerificationService.sessionVerifiedStatus
- .map { it != SessionVerifiedStatus.Unknown }
- .distinctUntilChanged()
+ val ftueStepStateFlow = MutableStateFlow(InternalFtueState.Unknown)
- override suspend fun reset() {
- analyticsService.reset()
- if (sdkVersionProvider.isAtLeast(Build.VERSION_CODES.TIRAMISU)) {
- permissionStateProvider.resetPermission(Manifest.permission.POST_NOTIFICATIONS)
+ override val state = ftueStepStateFlow
+ .mapState {
+ when (it) {
+ is InternalFtueState.Unknown -> FtueState.Unknown
+ is InternalFtueState.Incomplete -> FtueState.Incomplete
+ is InternalFtueState.Complete -> FtueState.Complete
+ }
+ }
+
+ init {
+ combine(
+ sessionVerificationService.sessionVerifiedStatus.onEach { sessionVerifiedStatus ->
+ if (sessionVerifiedStatus == SessionVerifiedStatus.NotVerified) {
+ // Ensure we wait for the user to confirm the session verified screen before going further
+ userNeedsToConfirmSessionVerificationSuccess.value = true
+ }
+ },
+ userNeedsToConfirmSessionVerificationSuccess,
+ analyticsService.didAskUserConsentFlow.distinctUntilChanged(),
+ ) {
+ updateFtueStep()
+ }
+ .launchIn(sessionCoroutineScope)
+ }
+
+ fun updateFtueStep() = sessionCoroutineScope.launch {
+ val step = getNextStep(null)
+ ftueStepStateFlow.value = when (step) {
+ null -> InternalFtueState.Complete
+ else -> InternalFtueState.Incomplete(step)
}
}
- init {
- sessionVerificationService.sessionVerifiedStatus
- .onEach { updateState() }
- .launchIn(sessionCoroutineScope)
-
- analyticsService.didAskUserConsentFlow
- .distinctUntilChanged()
- .onEach { updateState() }
- .launchIn(sessionCoroutineScope)
- }
-
- suspend fun getNextStep(currentStep: FtueStep? = null): FtueStep? =
- when (currentStep) {
+ private suspend fun getNextStep(completedStep: FtueStep? = null): FtueStep? =
+ when (completedStep) {
null -> if (!isSessionVerificationStateReady()) {
FtueStep.WaitingForInitialState
} else {
getNextStep(FtueStep.WaitingForInitialState)
}
- FtueStep.WaitingForInitialState -> if (isSessionNotVerified()) {
+ FtueStep.WaitingForInitialState -> if (isSessionNotVerified() || userNeedsToConfirmSessionVerificationSuccess.value) {
FtueStep.SessionVerification
} else {
getNextStep(FtueStep.SessionVerification)
@@ -108,9 +117,6 @@ class DefaultFtueService(
}
private suspend fun isSessionNotVerified(): Boolean {
- // Wait until the session verification status is known
- isVerificationStatusKnown.filter { it }.first()
-
return sessionVerificationService.sessionVerifiedStatus.value == SessionVerifiedStatus.NotVerified && !canSkipVerification()
}
@@ -137,14 +143,8 @@ class DefaultFtueService(
return lockScreenService.isSetupRequired().first()
}
- @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE)
- internal suspend fun updateState() {
- val nextStep = getNextStep()
- state.value = when {
- // Final state, there aren't any more next steps
- nextStep == null -> FtueState.Complete
- else -> FtueState.Incomplete
- }
+ fun onUserCompletedSessionVerification() {
+ userNeedsToConfirmSessionVerificationSuccess.value = false
}
}
diff --git a/features/ftue/impl/src/main/kotlin/io/element/android/features/ftue/impl/state/InternalFtueState.kt b/features/ftue/impl/src/main/kotlin/io/element/android/features/ftue/impl/state/InternalFtueState.kt
new file mode 100644
index 0000000000..c620a2ca5b
--- /dev/null
+++ b/features/ftue/impl/src/main/kotlin/io/element/android/features/ftue/impl/state/InternalFtueState.kt
@@ -0,0 +1,18 @@
+/*
+ * Copyright 2025 New Vector Ltd.
+ *
+ * SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial
+ * Please see LICENSE files in the repository root for full details.
+ */
+
+package io.element.android.features.ftue.impl.state
+
+sealed interface InternalFtueState {
+ data object Unknown : InternalFtueState
+
+ data class Incomplete(
+ val nextStep: FtueStep,
+ ) : InternalFtueState
+
+ data object Complete : InternalFtueState
+}
diff --git a/features/ftue/impl/src/main/res/values-eo/translations.xml b/features/ftue/impl/src/main/res/values-eo/translations.xml
new file mode 100644
index 0000000000..fae7da561c
--- /dev/null
+++ b/features/ftue/impl/src/main/res/values-eo/translations.xml
@@ -0,0 +1,9 @@
+
+
+ "Create a new backup password"
+ "Confirm this device to set up secure messaging."
+ "Confirm it\'s you"
+ "Use backup password"
+ "Device confirmed"
+ "Enter backup password"
+
diff --git a/features/ftue/impl/src/test/kotlin/io/element/android/features/ftue/impl/DefaultFtueEntryPointTest.kt b/features/ftue/impl/src/test/kotlin/io/element/android/features/ftue/impl/DefaultFtueEntryPointTest.kt
new file mode 100644
index 0000000000..3a8ed11ea2
--- /dev/null
+++ b/features/ftue/impl/src/test/kotlin/io/element/android/features/ftue/impl/DefaultFtueEntryPointTest.kt
@@ -0,0 +1,57 @@
+/*
+ * Copyright 2025 New Vector Ltd.
+ *
+ * SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial
+ * Please see LICENSE files in the repository root for full details.
+ */
+
+package io.element.android.features.ftue.impl
+
+import android.content.Context
+import android.content.Intent
+import androidx.arch.core.executor.testing.InstantTaskExecutorRule
+import com.bumble.appyx.core.modality.BuildContext
+import com.bumble.appyx.testing.junit4.util.MainDispatcherRule
+import com.google.common.truth.Truth.assertThat
+import io.element.android.features.lockscreen.api.LockScreenEntryPoint
+import io.element.android.tests.testutils.lambda.lambdaError
+import io.element.android.tests.testutils.node.TestParentNode
+import kotlinx.coroutines.test.runTest
+import org.junit.Rule
+import org.junit.Test
+
+class DefaultFtueEntryPointTest {
+ @get:Rule
+ val instantTaskExecutorRule = InstantTaskExecutorRule()
+
+ @get:Rule
+ val mainDispatcherRule = MainDispatcherRule()
+
+ @Test
+ fun `test node builder`() = runTest {
+ val entryPoint = DefaultFtueEntryPoint()
+ val parentNode = TestParentNode.create { buildContext, plugins ->
+ FtueFlowNode(
+ buildContext = buildContext,
+ plugins = plugins,
+ analyticsEntryPoint = { _, _ -> lambdaError() },
+ defaultFtueService = createDefaultFtueService(),
+ lockScreenEntryPoint = object : LockScreenEntryPoint {
+ override fun nodeBuilder(
+ parentNode: com.bumble.appyx.core.node.Node,
+ buildContext: BuildContext,
+ navTarget: LockScreenEntryPoint.Target
+ ): LockScreenEntryPoint.NodeBuilder {
+ lambdaError()
+ }
+
+ override fun pinUnlockIntent(context: Context): Intent {
+ lambdaError()
+ }
+ },
+ )
+ }
+ val result = entryPoint.createNode(parentNode, BuildContext.root(null))
+ assertThat(result).isInstanceOf(FtueFlowNode::class.java)
+ }
+}
diff --git a/features/ftue/impl/src/test/kotlin/io/element/android/features/ftue/impl/DefaultFtueServiceTest.kt b/features/ftue/impl/src/test/kotlin/io/element/android/features/ftue/impl/DefaultFtueServiceTest.kt
index 4a05433e5e..e46f43f3c3 100644
--- a/features/ftue/impl/src/test/kotlin/io/element/android/features/ftue/impl/DefaultFtueServiceTest.kt
+++ b/features/ftue/impl/src/test/kotlin/io/element/android/features/ftue/impl/DefaultFtueServiceTest.kt
@@ -13,6 +13,7 @@ import com.google.common.truth.Truth.assertThat
import io.element.android.features.ftue.api.state.FtueState
import io.element.android.features.ftue.impl.state.DefaultFtueService
import io.element.android.features.ftue.impl.state.FtueStep
+import io.element.android.features.ftue.impl.state.InternalFtueState
import io.element.android.features.lockscreen.api.LockScreenService
import io.element.android.features.lockscreen.test.FakeLockScreenService
import io.element.android.libraries.matrix.api.verification.SessionVerificationService
@@ -26,8 +27,6 @@ import io.element.android.services.analytics.api.AnalyticsService
import io.element.android.services.analytics.noop.NoopAnalyticsService
import io.element.android.services.analytics.test.FakeAnalyticsService
import io.element.android.services.toolbox.test.sdk.FakeBuildVersionSdkIntProvider
-import io.element.android.tests.testutils.lambda.lambdaRecorder
-import io.element.android.tests.testutils.lambda.value
import kotlinx.coroutines.test.TestScope
import kotlinx.coroutines.test.runTest
import org.junit.Test
@@ -69,9 +68,11 @@ class DefaultFtueServiceTest {
analyticsService.setDidAskUserConsent()
permissionStateProvider.setPermissionGranted()
lockScreenService.setIsPinSetup(true)
- service.updateState()
-
- assertThat(service.state.value).isEqualTo(FtueState.Complete)
+ service.updateFtueStep()
+ service.state.test {
+ assertThat(awaitItem()).isEqualTo(FtueState.Unknown)
+ assertThat(awaitItem()).isEqualTo(FtueState.Complete)
+ }
}
@Test
@@ -90,9 +91,11 @@ class DefaultFtueServiceTest {
sessionVerificationService.emitVerifiedStatus(SessionVerifiedStatus.Verified)
permissionStateProvider.setPermissionGranted()
lockScreenService.setIsPinSetup(true)
- service.updateState()
-
- assertThat(service.state.value).isEqualTo(FtueState.Complete)
+ service.updateFtueStep()
+ service.state.test {
+ assertThat(awaitItem()).isEqualTo(FtueState.Unknown)
+ assertThat(awaitItem()).isEqualTo(FtueState.Complete)
+ }
}
@Test
@@ -109,35 +112,30 @@ class DefaultFtueServiceTest {
permissionStateProvider = permissionStateProvider,
lockScreenService = lockScreenService,
)
- val steps = mutableListOf()
- // Session verification
- steps.add(service.getNextStep(steps.lastOrNull()))
- sessionVerificationService.emitVerifiedStatus(SessionVerifiedStatus.NotVerified)
-
- // Notifications opt in
- steps.add(service.getNextStep(steps.lastOrNull()))
- permissionStateProvider.setPermissionGranted()
-
- // Entering PIN code
- steps.add(service.getNextStep(steps.lastOrNull()))
- lockScreenService.setIsPinSetup(true)
-
- // Analytics opt in
- steps.add(service.getNextStep(steps.lastOrNull()))
- analyticsService.setDidAskUserConsent()
-
- // Final step (null)
- steps.add(service.getNextStep(steps.lastOrNull()))
-
- assertThat(steps).containsExactly(
- FtueStep.SessionVerification,
- FtueStep.NotificationsOptIn,
- FtueStep.LockscreenSetup,
- FtueStep.AnalyticsOptIn,
- // Final state
- null,
- )
+ service.ftueStepStateFlow.test {
+ assertThat(awaitItem()).isEqualTo(InternalFtueState.Unknown)
+ // Session verification
+ assertThat(awaitItem()).isEqualTo(InternalFtueState.Incomplete(FtueStep.SessionVerification))
+ sessionVerificationService.emitVerifiedStatus(SessionVerifiedStatus.Verified)
+ // User completes verification
+ service.onUserCompletedSessionVerification()
+ // Notifications opt in
+ assertThat(awaitItem()).isEqualTo(InternalFtueState.Incomplete(FtueStep.NotificationsOptIn))
+ permissionStateProvider.setPermissionGranted()
+ // Simulate event from NotificationsOptInNode.Callback.onNotificationsOptInFinished
+ service.updateFtueStep()
+ // Entering PIN code
+ assertThat(awaitItem()).isEqualTo(InternalFtueState.Incomplete(FtueStep.LockscreenSetup))
+ lockScreenService.setIsPinSetup(true)
+ // Simulate event from LockScreenEntryPoint.Callback.onSetupDone()
+ service.updateFtueStep()
+ // Analytics opt in
+ assertThat(awaitItem()).isEqualTo(InternalFtueState.Incomplete(FtueStep.AnalyticsOptIn))
+ analyticsService.setDidAskUserConsent()
+ // Final step
+ assertThat(awaitItem()).isEqualTo(InternalFtueState.Complete)
+ }
}
@Test
@@ -158,10 +156,13 @@ class DefaultFtueServiceTest {
permissionStateProvider.setPermissionGranted()
lockScreenService.setIsPinSetup(true)
- assertThat(service.getNextStep()).isEqualTo(FtueStep.AnalyticsOptIn)
-
- analyticsService.setDidAskUserConsent()
- assertThat(service.getNextStep(null)).isNull()
+ service.ftueStepStateFlow.test {
+ assertThat(awaitItem()).isEqualTo(InternalFtueState.Unknown)
+ // Analytics opt in
+ assertThat(awaitItem()).isEqualTo(InternalFtueState.Incomplete(FtueStep.AnalyticsOptIn))
+ analyticsService.setDidAskUserConsent()
+ assertThat(awaitItem()).isEqualTo(InternalFtueState.Complete)
+ }
}
@Test
@@ -180,68 +181,30 @@ class DefaultFtueServiceTest {
sessionVerificationService.emitVerifiedStatus(SessionVerifiedStatus.Verified)
lockScreenService.setIsPinSetup(true)
- assertThat(service.getNextStep()).isEqualTo(FtueStep.AnalyticsOptIn)
-
- analyticsService.setDidAskUserConsent()
- assertThat(service.getNextStep(null)).isNull()
+ service.ftueStepStateFlow.test {
+ assertThat(awaitItem()).isEqualTo(InternalFtueState.Unknown)
+ // Analytics opt in
+ assertThat(awaitItem()).isEqualTo(InternalFtueState.Incomplete(FtueStep.AnalyticsOptIn))
+ analyticsService.setDidAskUserConsent()
+ assertThat(awaitItem()).isEqualTo(InternalFtueState.Complete)
+ }
}
-
- @Test
- fun `reset do the expected actions S`() = runTest {
- val resetAnalyticsLambda = lambdaRecorder { }
- val analyticsService = FakeAnalyticsService(
- resetLambda = resetAnalyticsLambda
- )
- val resetPermissionLambda = lambdaRecorder { }
- val permissionStateProvider = FakePermissionStateProvider(
- resetPermissionLambda = resetPermissionLambda
- )
- val service = createDefaultFtueService(
- sdkIntVersion = Build.VERSION_CODES.S,
- permissionStateProvider = permissionStateProvider,
- analyticsService = analyticsService,
- )
- service.reset()
- resetAnalyticsLambda.assertions().isCalledOnce()
- resetPermissionLambda.assertions().isNeverCalled()
- }
-
- @Test
- fun `reset do the expected actions TIRAMISU`() = runTest {
- val resetLambda = lambdaRecorder { }
- val analyticsService = FakeAnalyticsService(
- resetLambda = resetLambda
- )
- val resetPermissionLambda = lambdaRecorder { }
- val permissionStateProvider = FakePermissionStateProvider(
- resetPermissionLambda = resetPermissionLambda
- )
- val service = createDefaultFtueService(
- sdkIntVersion = Build.VERSION_CODES.TIRAMISU,
- permissionStateProvider = permissionStateProvider,
- analyticsService = analyticsService,
- )
- service.reset()
- resetLambda.assertions().isCalledOnce()
- resetPermissionLambda.assertions().isCalledOnce()
- .with(value("android.permission.POST_NOTIFICATIONS"))
- }
-
- private fun TestScope.createDefaultFtueService(
- sessionVerificationService: SessionVerificationService = FakeSessionVerificationService(),
- analyticsService: AnalyticsService = FakeAnalyticsService(),
- permissionStateProvider: PermissionStateProvider = FakePermissionStateProvider(permissionGranted = false),
- lockScreenService: LockScreenService = FakeLockScreenService(),
- sessionPreferencesStore: SessionPreferencesStore = InMemorySessionPreferencesStore(),
- // First version where notification permission is required
- sdkIntVersion: Int = Build.VERSION_CODES.TIRAMISU,
- ) = DefaultFtueService(
- sessionCoroutineScope = backgroundScope,
- sessionVerificationService = sessionVerificationService,
- sdkVersionProvider = FakeBuildVersionSdkIntProvider(sdkIntVersion),
- analyticsService = analyticsService,
- permissionStateProvider = permissionStateProvider,
- lockScreenService = lockScreenService,
- sessionPreferencesStore = sessionPreferencesStore,
- )
}
+
+internal fun TestScope.createDefaultFtueService(
+ sessionVerificationService: SessionVerificationService = FakeSessionVerificationService(),
+ analyticsService: AnalyticsService = FakeAnalyticsService(),
+ permissionStateProvider: PermissionStateProvider = FakePermissionStateProvider(permissionGranted = false),
+ lockScreenService: LockScreenService = FakeLockScreenService(),
+ sessionPreferencesStore: SessionPreferencesStore = InMemorySessionPreferencesStore(),
+ // First version where notification permission is required
+ sdkIntVersion: Int = Build.VERSION_CODES.TIRAMISU,
+) = DefaultFtueService(
+ sessionCoroutineScope = backgroundScope,
+ sessionVerificationService = sessionVerificationService,
+ sdkVersionProvider = FakeBuildVersionSdkIntProvider(sdkIntVersion),
+ analyticsService = analyticsService,
+ permissionStateProvider = permissionStateProvider,
+ lockScreenService = lockScreenService,
+ sessionPreferencesStore = sessionPreferencesStore,
+)
diff --git a/features/ftue/test/src/main/kotlin/io/element/android/features/ftue/test/FakeFtueService.kt b/features/ftue/test/src/main/kotlin/io/element/android/features/ftue/test/FakeFtueService.kt
index 9217dbd22c..1dbc2c281b 100644
--- a/features/ftue/test/src/main/kotlin/io/element/android/features/ftue/test/FakeFtueService.kt
+++ b/features/ftue/test/src/main/kotlin/io/element/android/features/ftue/test/FakeFtueService.kt
@@ -9,18 +9,11 @@ package io.element.android.features.ftue.test
import io.element.android.features.ftue.api.state.FtueService
import io.element.android.features.ftue.api.state.FtueState
-import io.element.android.tests.testutils.lambda.lambdaError
import kotlinx.coroutines.flow.MutableStateFlow
-class FakeFtueService(
- private val resetLambda: () -> Unit = { lambdaError() },
-) : FtueService {
+class FakeFtueService : FtueService {
override val state: MutableStateFlow = MutableStateFlow(FtueState.Unknown)
- override suspend fun reset() {
- resetLambda()
- }
-
suspend fun emitState(newState: FtueState) {
state.emit(newState)
}
diff --git a/features/home/api/src/main/kotlin/io/element/android/features/home/api/HomeEntryPoint.kt b/features/home/api/src/main/kotlin/io/element/android/features/home/api/HomeEntryPoint.kt
index 88b55d4e02..9beb147568 100644
--- a/features/home/api/src/main/kotlin/io/element/android/features/home/api/HomeEntryPoint.kt
+++ b/features/home/api/src/main/kotlin/io/element/android/features/home/api/HomeEntryPoint.kt
@@ -28,6 +28,5 @@ interface HomeEntryPoint : FeatureEntryPoint {
fun onSessionConfirmRecoveryKeyClick()
fun onRoomSettingsClick(roomId: RoomId)
fun onReportBugClick()
- fun onLogoutForNativeSlidingSyncMigrationNeeded()
}
}
diff --git a/features/home/impl/build.gradle.kts b/features/home/impl/build.gradle.kts
index 57fefaf413..b6a83775fc 100644
--- a/features/home/impl/build.gradle.kts
+++ b/features/home/impl/build.gradle.kts
@@ -1,4 +1,5 @@
import extension.setupDependencyInjection
+import extension.testCommonDependencies
/*
* Copyright 2022-2024 New Vector Ltd.
@@ -55,16 +56,10 @@ dependencies {
implementation(libs.haze.materials)
implementation(projects.features.reportroom.api)
implementation(projects.features.changeroommemberroles.api)
+ implementation(projects.libraries.previewutils)
api(projects.features.home.api)
- testImplementation(libs.androidx.compose.ui.test.junit)
- testReleaseImplementation(libs.androidx.compose.ui.test.manifest)
- testImplementation(libs.test.junit)
- testImplementation(libs.coroutines.test)
- testImplementation(libs.molecule.runtime)
- testImplementation(libs.test.truth)
- testImplementation(libs.test.turbine)
- testImplementation(libs.test.robolectric)
+ testCommonDependencies(libs, true)
testImplementation(projects.features.invite.test)
testImplementation(projects.features.logout.test)
testImplementation(projects.features.networkmonitor.test)
@@ -79,5 +74,4 @@ dependencies {
testImplementation(projects.libraries.push.test)
testImplementation(projects.services.analytics.test)
testImplementation(projects.services.toolbox.test)
- testImplementation(projects.tests.testutils)
}
diff --git a/features/home/impl/src/main/kotlin/io/element/android/features/home/impl/HomeFlowNode.kt b/features/home/impl/src/main/kotlin/io/element/android/features/home/impl/HomeFlowNode.kt
index a8eeb6eee8..d8ecf7016f 100644
--- a/features/home/impl/src/main/kotlin/io/element/android/features/home/impl/HomeFlowNode.kt
+++ b/features/home/impl/src/main/kotlin/io/element/android/features/home/impl/HomeFlowNode.kt
@@ -164,7 +164,7 @@ class HomeFlowNode(
stateFlow.value.roomListState.eventSink(RoomListEvents.LeaveRoom(roomId, needsConfirmation = false))
}
- fun rootNode(buildContext: BuildContext): Node {
+ private fun rootNode(buildContext: BuildContext): Node {
return node(buildContext) { modifier ->
val state by stateFlow.collectAsState()
val activity = requireNotNull(LocalActivity.current)
diff --git a/features/home/impl/src/main/kotlin/io/element/android/features/home/impl/HomeView.kt b/features/home/impl/src/main/kotlin/io/element/android/features/home/impl/HomeView.kt
index 6d531504ab..37727712fb 100644
--- a/features/home/impl/src/main/kotlin/io/element/android/features/home/impl/HomeView.kt
+++ b/features/home/impl/src/main/kotlin/io/element/android/features/home/impl/HomeView.kt
@@ -269,7 +269,7 @@ private fun HomeScaffold(
.hazeSource(state = hazeState),
state = state.homeSpacesState,
onSpaceClick = { spaceId ->
- // TODO
+ onRoomClick(spaceId)
}
)
}
diff --git a/features/home/impl/src/main/kotlin/io/element/android/features/home/impl/datasource/RoomListDataSource.kt b/features/home/impl/src/main/kotlin/io/element/android/features/home/impl/datasource/RoomListDataSource.kt
index 28f7f95908..b9e8d27bf7 100644
--- a/features/home/impl/src/main/kotlin/io/element/android/features/home/impl/datasource/RoomListDataSource.kt
+++ b/features/home/impl/src/main/kotlin/io/element/android/features/home/impl/datasource/RoomListDataSource.kt
@@ -30,6 +30,7 @@ import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.sync.Mutex
import kotlinx.coroutines.sync.withLock
import kotlinx.coroutines.withContext
+import timber.log.Timber
import kotlin.time.Duration.Companion.seconds
@Inject
@@ -102,13 +103,44 @@ class RoomListDataSource(
}
private suspend fun buildAndEmitAllRooms(roomSummaries: List, useCache: Boolean = true) {
+ // Used to detect duplicates in the room list summaries - see comment below
+ data class CacheResult(val index: Int, val fromCache: Boolean)
+ val cachingResults = mutableMapOf>()
+
val roomListRoomSummaries = diffCache.indices().mapNotNull { index ->
if (useCache) {
- diffCache.get(index) ?: buildAndCacheItem(roomSummaries, index)
+ diffCache.get(index)?.let { cachedItem ->
+ // Add the cached item to the caching results
+ val pairs = cachingResults.getOrDefault(cachedItem.roomId, mutableListOf())
+ pairs.add(CacheResult(index, fromCache = true))
+ cachingResults[cachedItem.roomId] = pairs
+ cachedItem
+ } ?: run {
+ roomSummaries.getOrNull(index)?.roomId?.let {
+ // Add the non-cached item to the caching results
+ val pairs = cachingResults.getOrDefault(it, mutableListOf())
+ pairs.add(CacheResult(index, fromCache = false))
+ cachingResults[it] = pairs
+ }
+ buildAndCacheItem(roomSummaries, index)
+ }
} else {
+ roomSummaries.getOrNull(index)?.roomId?.let {
+ // Add the non-cached item to the caching results
+ val pairs = cachingResults.getOrDefault(it, mutableListOf())
+ pairs.add(CacheResult(index, fromCache = false))
+ cachingResults[it] = pairs
+ }
buildAndCacheItem(roomSummaries, index)
}
}
+
+ // TODO remove once https://github.com/element-hq/element-x-android/issues/5031 has been confirmed as fixed
+ val duplicates = cachingResults.filter { (_, operations) -> operations.size > 1 }
+ if (duplicates.isNotEmpty()) {
+ Timber.e("Found duplicates in room summaries after an UI update: $duplicates. This could be a race condition/caching issue of some kind")
+ }
+
_allRooms.emit(roomListRoomSummaries.toImmutableList())
}
diff --git a/features/home/impl/src/main/kotlin/io/element/android/features/home/impl/roomlist/RoomListPresenter.kt b/features/home/impl/src/main/kotlin/io/element/android/features/home/impl/roomlist/RoomListPresenter.kt
index 9c77ab816a..b8e299c5e9 100644
--- a/features/home/impl/src/main/kotlin/io/element/android/features/home/impl/roomlist/RoomListPresenter.kt
+++ b/features/home/impl/src/main/kotlin/io/element/android/features/home/impl/roomlist/RoomListPresenter.kt
@@ -36,7 +36,6 @@ import io.element.android.features.leaveroom.api.LeaveRoomEvent
import io.element.android.features.leaveroom.api.LeaveRoomState
import io.element.android.libraries.architecture.AsyncData
import io.element.android.libraries.architecture.Presenter
-import io.element.android.libraries.core.coroutine.mapState
import io.element.android.libraries.fullscreenintent.api.FullScreenIntentPermissionsState
import io.element.android.libraries.matrix.api.MatrixClient
import io.element.android.libraries.matrix.api.core.RoomId
@@ -44,6 +43,7 @@ import io.element.android.libraries.matrix.api.encryption.EncryptionService
import io.element.android.libraries.matrix.api.encryption.RecoveryState
import io.element.android.libraries.matrix.api.roomlist.RoomList
import io.element.android.libraries.matrix.api.timeline.ReceiptType
+import io.element.android.libraries.matrix.ui.safety.rememberHideInvitesAvatar
import io.element.android.libraries.preferences.api.store.AppPreferencesStore
import io.element.android.libraries.preferences.api.store.SessionPreferencesStore
import io.element.android.libraries.push.api.battery.BatteryOptimizationState
@@ -101,12 +101,7 @@ class RoomListPresenter(
var securityBannerDismissed by rememberSaveable { mutableStateOf(false) }
// Avatar indicator
- val hideInvitesAvatar by remember {
- client
- .mediaPreviewService()
- .mediaPreviewConfigFlow
- .mapState { config -> config.hideInviteAvatar }
- }.collectAsState()
+ val hideInvitesAvatar by client.rememberHideInvitesAvatar()
val contextMenu = remember { mutableStateOf(RoomListState.ContextMenu.Hidden) }
val declineInviteMenu = remember { mutableStateOf(RoomListState.DeclineInviteMenu.Hidden) }
diff --git a/features/home/impl/src/main/kotlin/io/element/android/features/home/impl/spaces/HomeSpacesPresenter.kt b/features/home/impl/src/main/kotlin/io/element/android/features/home/impl/spaces/HomeSpacesPresenter.kt
index 29ceca14bf..dea6defc0a 100644
--- a/features/home/impl/src/main/kotlin/io/element/android/features/home/impl/spaces/HomeSpacesPresenter.kt
+++ b/features/home/impl/src/main/kotlin/io/element/android/features/home/impl/spaces/HomeSpacesPresenter.kt
@@ -13,10 +13,9 @@ import androidx.compose.runtime.getValue
import androidx.compose.runtime.remember
import dev.zacsweers.metro.Inject
import io.element.android.features.invite.api.SeenInvitesStore
-import io.element.android.features.invite.api.seenSpaceIds
import io.element.android.libraries.architecture.Presenter
-import io.element.android.libraries.core.coroutine.mapState
import io.element.android.libraries.matrix.api.MatrixClient
+import io.element.android.libraries.matrix.ui.safety.rememberHideInvitesAvatar
import kotlinx.collections.immutable.persistentSetOf
import kotlinx.collections.immutable.toPersistentSet
import kotlinx.coroutines.flow.map
@@ -28,15 +27,10 @@ class HomeSpacesPresenter(
) : Presenter {
@Composable
override fun present(): HomeSpacesState {
- val hideInvitesAvatar by remember {
- client
- .mediaPreviewService()
- .mediaPreviewConfigFlow
- .mapState { config -> config.hideInviteAvatar }
- }.collectAsState()
- val spaceRooms by client.spaceService.spaceRooms.collectAsState(emptyList())
+ val hideInvitesAvatar by client.rememberHideInvitesAvatar()
+ val spaceRooms by client.spaceService.spaceRoomsFlow.collectAsState(emptyList())
val seenSpaceInvites by remember {
- seenInvitesStore.seenSpaceIds().map { it.toPersistentSet() }
+ seenInvitesStore.seenRoomIds().map { it.toPersistentSet() }
}.collectAsState(persistentSetOf())
fun handleEvents(event: HomeSpacesEvents) {
diff --git a/features/home/impl/src/main/kotlin/io/element/android/features/home/impl/spaces/HomeSpacesState.kt b/features/home/impl/src/main/kotlin/io/element/android/features/home/impl/spaces/HomeSpacesState.kt
index 6def46c7b3..96733991f9 100644
--- a/features/home/impl/src/main/kotlin/io/element/android/features/home/impl/spaces/HomeSpacesState.kt
+++ b/features/home/impl/src/main/kotlin/io/element/android/features/home/impl/spaces/HomeSpacesState.kt
@@ -7,14 +7,14 @@
package io.element.android.features.home.impl.spaces
-import io.element.android.libraries.matrix.api.core.SpaceId
+import io.element.android.libraries.matrix.api.core.RoomId
import io.element.android.libraries.matrix.api.spaces.SpaceRoom
import kotlinx.collections.immutable.ImmutableSet
data class HomeSpacesState(
val space: CurrentSpace,
val spaceRooms: List,
- val seenSpaceInvites: ImmutableSet,
+ val seenSpaceInvites: ImmutableSet,
val hideInvitesAvatar: Boolean,
val eventSink: (HomeSpacesEvents) -> Unit,
)
diff --git a/features/home/impl/src/main/kotlin/io/element/android/features/home/impl/spaces/HomeSpacesStateProvider.kt b/features/home/impl/src/main/kotlin/io/element/android/features/home/impl/spaces/HomeSpacesStateProvider.kt
index 466f515b26..921c340886 100644
--- a/features/home/impl/src/main/kotlin/io/element/android/features/home/impl/spaces/HomeSpacesStateProvider.kt
+++ b/features/home/impl/src/main/kotlin/io/element/android/features/home/impl/spaces/HomeSpacesStateProvider.kt
@@ -8,8 +8,9 @@
package io.element.android.features.home.impl.spaces
import androidx.compose.ui.tooling.preview.PreviewParameterProvider
-import io.element.android.libraries.matrix.api.core.SpaceId
+import io.element.android.libraries.matrix.api.core.RoomId
import io.element.android.libraries.matrix.api.spaces.SpaceRoom
+import io.element.android.libraries.previewutils.room.aSpaceRoom
import kotlinx.collections.immutable.toImmutableSet
open class HomeSpacesStateProvider : PreviewParameterProvider {
@@ -18,12 +19,12 @@ open class HomeSpacesStateProvider : PreviewParameterProvider {
aHomeSpacesState(
spaceRooms = SpaceRoomProvider().values.toList(),
seenSpaceInvites = setOf(
- SpaceId("!spaceId3:example.com"),
+ RoomId("!spaceId3:example.com"),
),
),
aHomeSpacesState(
space = CurrentSpace.Space(
- spaceRoom = aSpaceRooms(spaceId = SpaceId("!mySpace:example.com"))
+ spaceRoom = aSpaceRoom(roomId = RoomId("!mySpace:example.com"))
),
spaceRooms = aListOfSpaceRooms(),
),
@@ -33,7 +34,7 @@ open class HomeSpacesStateProvider : PreviewParameterProvider {
internal fun aHomeSpacesState(
space: CurrentSpace = CurrentSpace.Root,
spaceRooms: List = aListOfSpaceRooms(),
- seenSpaceInvites: Set = emptySet(),
+ seenSpaceInvites: Set = emptySet(),
hideInvitesAvatar: Boolean = false,
eventSink: (HomeSpacesEvents) -> Unit = {},
) = HomeSpacesState(
@@ -46,8 +47,8 @@ internal fun aHomeSpacesState(
fun aListOfSpaceRooms(): List {
return listOf(
- aSpaceRooms(spaceId = SpaceId("!spaceId0:example.com")),
- aSpaceRooms(spaceId = SpaceId("!spaceId1:example.com")),
- aSpaceRooms(spaceId = SpaceId("!spaceId2:example.com")),
+ aSpaceRoom(roomId = RoomId("!spaceId0:example.com")),
+ aSpaceRoom(roomId = RoomId("!spaceId1:example.com")),
+ aSpaceRoom(roomId = RoomId("!spaceId2:example.com")),
)
}
diff --git a/features/home/impl/src/main/kotlin/io/element/android/features/home/impl/spaces/HomeSpacesView.kt b/features/home/impl/src/main/kotlin/io/element/android/features/home/impl/spaces/HomeSpacesView.kt
index be6639e94b..8b07b9f526 100644
--- a/features/home/impl/src/main/kotlin/io/element/android/features/home/impl/spaces/HomeSpacesView.kt
+++ b/features/home/impl/src/main/kotlin/io/element/android/features/home/impl/spaces/HomeSpacesView.kt
@@ -14,17 +14,18 @@ import androidx.compose.ui.tooling.preview.PreviewParameter
import io.element.android.libraries.designsystem.components.avatar.AvatarSize
import io.element.android.libraries.designsystem.preview.ElementPreview
import io.element.android.libraries.designsystem.preview.PreviewsDayNight
-import io.element.android.libraries.matrix.api.core.SpaceId
+import io.element.android.libraries.matrix.api.core.RoomId
import io.element.android.libraries.matrix.api.room.CurrentUserMembership
import io.element.android.libraries.matrix.ui.components.SpaceHeaderRootView
import io.element.android.libraries.matrix.ui.components.SpaceHeaderView
+import io.element.android.libraries.matrix.ui.components.SpaceRoomItemView
import io.element.android.libraries.matrix.ui.model.getAvatarData
import kotlinx.collections.immutable.toImmutableList
@Composable
fun HomeSpacesView(
state: HomeSpacesState,
- onSpaceClick: (SpaceId) -> Unit,
+ onSpaceClick: (RoomId) -> Unit,
modifier: Modifier = Modifier,
) {
LazyColumn(modifier) {
@@ -51,15 +52,18 @@ fun HomeSpacesView(
)
}
}
- state.spaceRooms.forEach {
- item(it.spaceId) {
- val isInvitation = it.state == CurrentUserMembership.INVITED
- HomeSpaceItemView(
- spaceRoom = it,
- showUnreadIndicator = isInvitation && it.spaceId !in state.seenSpaceInvites,
+ state.spaceRooms.forEach { spaceRoom ->
+ item(spaceRoom.roomId) {
+ val isInvitation = spaceRoom.state == CurrentUserMembership.INVITED
+ SpaceRoomItemView(
+ spaceRoom = spaceRoom,
+ showUnreadIndicator = isInvitation && spaceRoom.roomId !in state.seenSpaceInvites,
hideAvatars = isInvitation && state.hideInvitesAvatar,
onClick = {
- onSpaceClick(it.spaceId)
+ onSpaceClick(spaceRoom.roomId)
+ },
+ onLongClick = {
+ // TODO
}
)
}
diff --git a/features/home/impl/src/main/kotlin/io/element/android/features/home/impl/spaces/SpaceRoomProvider.kt b/features/home/impl/src/main/kotlin/io/element/android/features/home/impl/spaces/SpaceRoomProvider.kt
index 29c18c78a0..474e08293a 100644
--- a/features/home/impl/src/main/kotlin/io/element/android/features/home/impl/spaces/SpaceRoomProvider.kt
+++ b/features/home/impl/src/main/kotlin/io/element/android/features/home/impl/spaces/SpaceRoomProvider.kt
@@ -8,77 +8,44 @@
package io.element.android.features.home.impl.spaces
import androidx.compose.ui.tooling.preview.PreviewParameterProvider
-import io.element.android.libraries.matrix.api.core.RoomAlias
-import io.element.android.libraries.matrix.api.core.SpaceId
+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.RoomType
-import io.element.android.libraries.matrix.api.room.join.JoinRule
import io.element.android.libraries.matrix.api.spaces.SpaceRoom
-import io.element.android.libraries.matrix.api.user.MatrixUser
+import io.element.android.libraries.previewutils.room.aSpaceRoom
class SpaceRoomProvider : PreviewParameterProvider {
override val values: Sequence = sequenceOf(
- aSpaceRooms(),
- aSpaceRooms(
+ aSpaceRoom(),
+ aSpaceRoom(
numJoinedMembers = 5,
childrenCount = 10,
worldReadable = true,
- spaceId = SpaceId("!spaceId0:example.com"),
+ roomId = RoomId("!spaceId0:example.com"),
),
- aSpaceRooms(
+ aSpaceRoom(
numJoinedMembers = 5,
childrenCount = 10,
worldReadable = true,
avatarUrl = "anUrl",
- spaceId = SpaceId("!spaceId1:example.com"),
+ roomId = RoomId("!spaceId1:example.com"),
),
- aSpaceRooms(
+ aSpaceRoom(
name = null,
numJoinedMembers = 5,
childrenCount = 10,
worldReadable = true,
avatarUrl = "anUrl",
- spaceId = SpaceId("!spaceId2:example.com"),
+ roomId = RoomId("!spaceId2:example.com"),
state = CurrentUserMembership.INVITED,
),
- aSpaceRooms(
+ aSpaceRoom(
name = null,
numJoinedMembers = 5,
childrenCount = 10,
worldReadable = true,
avatarUrl = "anUrl",
- spaceId = SpaceId("!spaceId3:example.com"),
+ roomId = RoomId("!spaceId3:example.com"),
state = CurrentUserMembership.INVITED,
),
)
}
-
-fun aSpaceRooms(
- name: String? = "Space name",
- avatarUrl: String? = null,
- canonicalAlias: RoomAlias? = null,
- childrenCount: Int = 0,
- guestCanJoin: Boolean = false,
- heroes: List = emptyList(),
- joinRule: JoinRule? = null,
- numJoinedMembers: Int = 0,
- spaceId: SpaceId = SpaceId("!spaceId:example.com"),
- roomType: RoomType = RoomType.Space,
- state: CurrentUserMembership? = null,
- topic: String? = null,
- worldReadable: Boolean = false,
-) = SpaceRoom(
- name = name,
- avatarUrl = avatarUrl,
- canonicalAlias = canonicalAlias,
- childrenCount = childrenCount,
- guestCanJoin = guestCanJoin,
- heroes = heroes,
- joinRule = joinRule,
- numJoinedMembers = numJoinedMembers,
- spaceId = spaceId,
- roomType = roomType,
- state = state,
- topic = topic,
- worldReadable = worldReadable
-)
diff --git a/features/home/impl/src/main/res/values-cy/translations.xml b/features/home/impl/src/main/res/values-cy/translations.xml
index bde8ee4c19..c8417952a6 100644
--- a/features/home/impl/src/main/res/values-cy/translations.xml
+++ b/features/home/impl/src/main/res/values-cy/translations.xml
@@ -13,6 +13,7 @@
"Er mwyn sicrhau fyddwch chi ddim yn colli galwad bwysig, newidiwch eich gosodiadau i ganiatáu hysbysiadau sgrin lawn pan fydd eich ffôn wedi\'i gloi."
"Gwella profiad eich galwadau"
"Sgyrsiau"
+ "Gofodau"
"Ydych chi\'n siŵr eich bod am wrthod y gwahoddiad i ymuno â %1$s?"
"Gwrthod y gwahoddiad"
"Ydych chi\'n siŵr eich bod am wrthod y sgwrs breifat hon gyda %1$s?"
@@ -32,6 +33,7 @@ Am y tro, gallwch ddad-ddewis hidlwyr er mwyn gweld eich sgyrsiau eraill""Gwahoddiadau"
"Does gennych chi ddim gwahoddiadau yn aros."
"Blaenoriaeth Isel"
+ "Does gennych chi ddim sgyrsiau blaenoriaeth isel eto"
"Gallwch ddad-ddewis hidlwyr er mwyn gweld eich sgyrsiau eraill"
"Does gennych chi ddim sgyrsiau ar gyfer y dewis hwn"
"Pobl"
diff --git a/features/home/impl/src/main/res/values-eo/translations.xml b/features/home/impl/src/main/res/values-eo/translations.xml
new file mode 100644
index 0000000000..0dc9b8e816
--- /dev/null
+++ b/features/home/impl/src/main/res/values-eo/translations.xml
@@ -0,0 +1,11 @@
+
+
+ "Restore your account security and message history with a backup password if you have lost all your existing devices."
+ "Set up backup"
+ "Set up backup to protect your account"
+ "Confirm your backup password to maintain access to your message backup and message history."
+ "Enter your backup password"
+ "Forgot your backup password?"
+ "Your message backup is out of sync"
+ "Looks like you\'re using a new device. Confirm it with another connected device to access your encrypted messages."
+
diff --git a/features/home/impl/src/main/res/values-fi/translations.xml b/features/home/impl/src/main/res/values-fi/translations.xml
index 52e8e9b9a2..31b5ff0a1a 100644
--- a/features/home/impl/src/main/res/values-fi/translations.xml
+++ b/features/home/impl/src/main/res/values-fi/translations.xml
@@ -33,6 +33,7 @@ Toistaiseksi voit poistaa suodattimien valinnan, jotta näet muut keskustelut."<
"Kutsut"
"Sinulla ei ole yhtään odottavaa kutsua."
"Matala prioriteetti"
+ "Sinulla ei ole vielä yhtään matalan prioriteetin keskustelua"
"Voit poistaa suodattimien valinnan nähdäksesi muut keskustelusi."
"Sinulla ei ole sopivia keskusteluja tähän valintaan"
"Ihmiset"
diff --git a/features/home/impl/src/main/res/values-nb/translations.xml b/features/home/impl/src/main/res/values-nb/translations.xml
index 558460a732..198bb7112d 100644
--- a/features/home/impl/src/main/res/values-nb/translations.xml
+++ b/features/home/impl/src/main/res/values-nb/translations.xml
@@ -13,6 +13,7 @@
"For å sikre at du aldri går glipp av en viktig samtale, må du endre innstillingene dine for å tillate fullskjermvarsler når telefonen er låst."
"Forbedre samtaleopplevelsen din"
"Chatter"
+ "Områder"
"Er du sikker på at du vil takke nei til invitasjonen til å bli med i %1$s?"
"Avvis invitasjon"
"Er du sikker på at du vil avslå denne private chatten med %1$s?"
diff --git a/features/home/impl/src/main/res/values-pt/translations.xml b/features/home/impl/src/main/res/values-pt/translations.xml
index 2a63000ea0..6c9f5a6fbd 100644
--- a/features/home/impl/src/main/res/values-pt/translations.xml
+++ b/features/home/impl/src/main/res/values-pt/translations.xml
@@ -16,7 +16,7 @@
"Espaços"
"Tens a certeza que queres rejeitar o convite para entra em %1$s?"
"Rejeitar convite"
- "Tem a certeza que queres rejeitar esta conversa privada com %1$s?"
+ "Tens a certeza que queres rejeitar esta conversa privada com %1$s?"
"Rejeitar conversa"
"Sem convites"
"%1$s (%2$s) convidou-te"
@@ -33,6 +33,7 @@ Por enquanto, podes anular a seleção dos filtros para veres as tuas outras con
"Convites"
"Não tens nenhum convite pendente."
"Prioridade baixa"
+ "Ainda não tens conversas de prioridade baixa"
"Podes anular a seleção dos filtros para veres as tuas outras conversas"
"Não tens nenhuma conversa selecionada"
"Pessoas"
diff --git a/features/home/impl/src/main/res/values-zh-rTW/translations.xml b/features/home/impl/src/main/res/values-zh-rTW/translations.xml
index a9f1c932a0..625ce3ceb0 100644
--- a/features/home/impl/src/main/res/values-zh-rTW/translations.xml
+++ b/features/home/impl/src/main/res/values-zh-rTW/translations.xml
@@ -33,6 +33,7 @@
"邀請"
"您沒有任何擱置中的邀請。"
"低優先度"
+ "您尚無任何低優先程度聊天"
"您可以取消選取篩選條件以檢視其他聊天"
"您並無此選擇的聊天"
"夥伴"
diff --git a/features/home/impl/src/test/kotlin/io/element/android/features/home/impl/DefaultHomeEntryPointTest.kt b/features/home/impl/src/test/kotlin/io/element/android/features/home/impl/DefaultHomeEntryPointTest.kt
new file mode 100644
index 0000000000..7d0c95befd
--- /dev/null
+++ b/features/home/impl/src/test/kotlin/io/element/android/features/home/impl/DefaultHomeEntryPointTest.kt
@@ -0,0 +1,58 @@
+/*
+ * Copyright 2025 New Vector Ltd.
+ *
+ * SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial
+ * Please see LICENSE files in the repository root for full details.
+ */
+
+package io.element.android.features.home.impl
+
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import com.bumble.appyx.core.modality.BuildContext
+import com.google.common.truth.Truth.assertThat
+import io.element.android.features.home.api.HomeEntryPoint
+import io.element.android.libraries.matrix.api.core.RoomId
+import io.element.android.libraries.matrix.test.FakeMatrixClient
+import io.element.android.services.analytics.test.FakeAnalyticsService
+import io.element.android.tests.testutils.lambda.lambdaError
+import io.element.android.tests.testutils.node.TestParentNode
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@RunWith(AndroidJUnit4::class)
+class DefaultHomeEntryPointTest {
+ @Test
+ fun `test node builder`() {
+ val entryPoint = DefaultHomeEntryPoint()
+ val parentNode = TestParentNode.create { buildContext, plugins ->
+ HomeFlowNode(
+ buildContext = buildContext,
+ plugins = plugins,
+ matrixClient = FakeMatrixClient(),
+ presenter = createHomePresenter(),
+ inviteFriendsUseCase = { lambdaError() },
+ analyticsService = FakeAnalyticsService(),
+ acceptDeclineInviteView = { _, _, _, _ -> lambdaError() },
+ directLogoutView = { _ -> lambdaError() },
+ reportRoomEntryPoint = { _, _, _ -> lambdaError() },
+ declineInviteAndBlockUserEntryPoint = { _, _, _ -> lambdaError() },
+ changeRoomMemberRolesEntryPoint = { _, _ -> lambdaError() },
+ leaveRoomRenderer = { _, _, _ -> lambdaError() },
+ )
+ }
+ val callback = object : HomeEntryPoint.Callback {
+ override fun onRoomClick(roomId: RoomId) = lambdaError()
+ override fun onStartChatClick() = lambdaError()
+ override fun onSettingsClick() = lambdaError()
+ override fun onSetUpRecoveryClick() = lambdaError()
+ override fun onSessionConfirmRecoveryKeyClick() = lambdaError()
+ override fun onRoomSettingsClick(roomId: RoomId) = lambdaError()
+ override fun onReportBugClick() = lambdaError()
+ }
+ val result = entryPoint.nodeBuilder(parentNode, BuildContext.root(null))
+ .callback(callback)
+ .build()
+ assertThat(result).isInstanceOf(HomeFlowNode::class.java)
+ assertThat(result.plugins).contains(callback)
+ }
+}
diff --git a/features/home/impl/src/test/kotlin/io/element/android/features/home/impl/HomePresenterTest.kt b/features/home/impl/src/test/kotlin/io/element/android/features/home/impl/HomePresenterTest.kt
index 57f270d3d3..a84dbd6309 100644
--- a/features/home/impl/src/test/kotlin/io/element/android/features/home/impl/HomePresenterTest.kt
+++ b/features/home/impl/src/test/kotlin/io/element/android/features/home/impl/HomePresenterTest.kt
@@ -175,24 +175,24 @@ class HomePresenterTest {
assertThat(finalState.showNavigationBar).isFalse()
}
}
-
- private fun createHomePresenter(
- client: MatrixClient = FakeMatrixClient(),
- syncService: SyncService = FakeSyncService(),
- snackbarDispatcher: SnackbarDispatcher = SnackbarDispatcher(),
- rageshakeFeatureAvailability: RageshakeFeatureAvailability = RageshakeFeatureAvailability { flowOf(false) },
- indicatorService: IndicatorService = FakeIndicatorService(),
- featureFlagService: FeatureFlagService = FakeFeatureFlagService(),
- homeSpacesPresenter: Presenter = Presenter { aHomeSpacesState() },
- ) = HomePresenter(
- client = client,
- syncService = syncService,
- snackbarDispatcher = snackbarDispatcher,
- indicatorService = indicatorService,
- logoutPresenter = { aDirectLogoutState() },
- roomListPresenter = { aRoomListState() },
- homeSpacesPresenter = homeSpacesPresenter,
- rageshakeFeatureAvailability = rageshakeFeatureAvailability,
- featureFlagService = featureFlagService,
- )
}
+
+internal fun createHomePresenter(
+ client: MatrixClient = FakeMatrixClient(),
+ syncService: SyncService = FakeSyncService(),
+ snackbarDispatcher: SnackbarDispatcher = SnackbarDispatcher(),
+ rageshakeFeatureAvailability: RageshakeFeatureAvailability = RageshakeFeatureAvailability { flowOf(false) },
+ indicatorService: IndicatorService = FakeIndicatorService(),
+ featureFlagService: FeatureFlagService = FakeFeatureFlagService(),
+ homeSpacesPresenter: Presenter = Presenter { aHomeSpacesState() },
+) = HomePresenter(
+ client = client,
+ syncService = syncService,
+ snackbarDispatcher = snackbarDispatcher,
+ indicatorService = indicatorService,
+ logoutPresenter = { aDirectLogoutState() },
+ roomListPresenter = { aRoomListState() },
+ homeSpacesPresenter = homeSpacesPresenter,
+ rageshakeFeatureAvailability = rageshakeFeatureAvailability,
+ featureFlagService = featureFlagService,
+)
diff --git a/features/invite/api/src/main/kotlin/io/element/android/features/invite/api/InviteData.kt b/features/invite/api/src/main/kotlin/io/element/android/features/invite/api/InviteData.kt
index eb1dfd3df6..fa296edc1c 100644
--- a/features/invite/api/src/main/kotlin/io/element/android/features/invite/api/InviteData.kt
+++ b/features/invite/api/src/main/kotlin/io/element/android/features/invite/api/InviteData.kt
@@ -12,6 +12,7 @@ import io.element.android.libraries.matrix.api.core.RoomId
import io.element.android.libraries.matrix.api.room.RoomInfo
import io.element.android.libraries.matrix.api.room.isDm
import io.element.android.libraries.matrix.api.room.preview.RoomPreviewInfo
+import io.element.android.libraries.matrix.api.spaces.SpaceRoom
import kotlinx.parcelize.Parcelize
@Parcelize
@@ -36,3 +37,11 @@ fun RoomInfo.toInviteData(): InviteData {
isDm = isDm,
)
}
+
+fun SpaceRoom.toInviteData(): InviteData {
+ return InviteData(
+ roomId = roomId,
+ roomName = name ?: roomId.value,
+ isDm = false,
+ )
+}
diff --git a/features/invite/api/src/main/kotlin/io/element/android/features/invite/api/SeenInvitesStore.kt b/features/invite/api/src/main/kotlin/io/element/android/features/invite/api/SeenInvitesStore.kt
index 6c609e3810..682970ffe7 100644
--- a/features/invite/api/src/main/kotlin/io/element/android/features/invite/api/SeenInvitesStore.kt
+++ b/features/invite/api/src/main/kotlin/io/element/android/features/invite/api/SeenInvitesStore.kt
@@ -8,10 +8,7 @@
package io.element.android.features.invite.api
import io.element.android.libraries.matrix.api.core.RoomId
-import io.element.android.libraries.matrix.api.core.SpaceId
-import io.element.android.libraries.matrix.api.core.toSpaceId
import kotlinx.coroutines.flow.Flow
-import kotlinx.coroutines.flow.map
interface SeenInvitesStore {
/**
@@ -38,9 +35,3 @@ interface SeenInvitesStore {
*/
suspend fun clear()
}
-
-fun SeenInvitesStore.seenSpaceIds(): Flow> {
- return seenRoomIds().map { roomIds ->
- roomIds.map { it.toSpaceId() }.toSet()
- }
-}
diff --git a/features/invite/api/src/main/kotlin/io/element/android/features/invite/api/acceptdecline/AcceptDeclineInviteView.kt b/features/invite/api/src/main/kotlin/io/element/android/features/invite/api/acceptdecline/AcceptDeclineInviteView.kt
index 78be5ebd16..a098443c45 100644
--- a/features/invite/api/src/main/kotlin/io/element/android/features/invite/api/acceptdecline/AcceptDeclineInviteView.kt
+++ b/features/invite/api/src/main/kotlin/io/element/android/features/invite/api/acceptdecline/AcceptDeclineInviteView.kt
@@ -11,7 +11,7 @@ import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import io.element.android.libraries.matrix.api.core.RoomId
-interface AcceptDeclineInviteView {
+fun interface AcceptDeclineInviteView {
@Composable
fun Render(
state: AcceptDeclineInviteState,
diff --git a/features/invite/api/src/main/kotlin/io/element/android/features/invite/api/declineandblock/DeclineInviteAndBlockEntryPoint.kt b/features/invite/api/src/main/kotlin/io/element/android/features/invite/api/declineandblock/DeclineInviteAndBlockEntryPoint.kt
index 27080ee354..8517fe2786 100644
--- a/features/invite/api/src/main/kotlin/io/element/android/features/invite/api/declineandblock/DeclineInviteAndBlockEntryPoint.kt
+++ b/features/invite/api/src/main/kotlin/io/element/android/features/invite/api/declineandblock/DeclineInviteAndBlockEntryPoint.kt
@@ -12,6 +12,6 @@ import com.bumble.appyx.core.node.Node
import io.element.android.features.invite.api.InviteData
import io.element.android.libraries.architecture.FeatureEntryPoint
-interface DeclineInviteAndBlockEntryPoint : FeatureEntryPoint {
+fun interface DeclineInviteAndBlockEntryPoint : FeatureEntryPoint {
fun createNode(parentNode: Node, buildContext: BuildContext, inviteData: InviteData): Node
}
diff --git a/features/invite/impl/build.gradle.kts b/features/invite/impl/build.gradle.kts
index 6a1cec8056..4caeafb71f 100644
--- a/features/invite/impl/build.gradle.kts
+++ b/features/invite/impl/build.gradle.kts
@@ -1,4 +1,5 @@
import extension.setupDependencyInjection
+import extension.testCommonDependencies
/*
* Copyright 2023, 2024 New Vector Ltd.
@@ -36,17 +37,9 @@ dependencies {
implementation(projects.services.analytics.api)
implementation(projects.libraries.push.api)
- testImplementation(libs.test.junit)
- testImplementation(libs.coroutines.test)
- testImplementation(libs.molecule.runtime)
- testImplementation(libs.test.truth)
- testImplementation(libs.test.turbine)
- testImplementation(libs.test.robolectric)
+ testCommonDependencies(libs, true)
testImplementation(projects.features.invite.test)
testImplementation(projects.libraries.matrix.test)
testImplementation(projects.libraries.push.test)
testImplementation(projects.services.analytics.test)
- testImplementation(projects.tests.testutils)
- testImplementation(libs.androidx.compose.ui.test.junit)
- testReleaseImplementation(libs.androidx.compose.ui.test.manifest)
}
diff --git a/features/invite/impl/src/main/kotlin/io/element/android/features/invite/impl/declineandblock/DeclineAndBlockPresenter.kt b/features/invite/impl/src/main/kotlin/io/element/android/features/invite/impl/declineandblock/DeclineAndBlockPresenter.kt
index 527a467ba9..f9639f69fe 100644
--- a/features/invite/impl/src/main/kotlin/io/element/android/features/invite/impl/declineandblock/DeclineAndBlockPresenter.kt
+++ b/features/invite/impl/src/main/kotlin/io/element/android/features/invite/impl/declineandblock/DeclineAndBlockPresenter.kt
@@ -35,7 +35,7 @@ class DeclineAndBlockPresenter(
private val snackbarDispatcher: SnackbarDispatcher,
) : Presenter {
@AssistedFactory
- interface Factory {
+ fun interface Factory {
fun create(inviteData: InviteData): DeclineAndBlockPresenter
}
diff --git a/features/invite/impl/src/main/res/values-pt/translations.xml b/features/invite/impl/src/main/res/values-pt/translations.xml
index 34804068a8..513f14eea6 100644
--- a/features/invite/impl/src/main/res/values-pt/translations.xml
+++ b/features/invite/impl/src/main/res/values-pt/translations.xml
@@ -7,7 +7,7 @@
"Rejeitar e bloquear"
"Tens a certeza que queres rejeitar o convite para entra em %1$s?"
"Rejeitar convite"
- "Tem a certeza que queres rejeitar esta conversa privada com %1$s?"
+ "Tens a certeza que queres rejeitar esta conversa privada com %1$s?"
"Rejeitar conversa"
"Sem convites"
"%1$s (%2$s) convidou-te"
diff --git a/features/invite/impl/src/test/kotlin/io/element/android/features/invite/impl/declineandblock/DeclineAndBlockPresenterTest.kt b/features/invite/impl/src/test/kotlin/io/element/android/features/invite/impl/declineandblock/DeclineAndBlockPresenterTest.kt
index c5d2f53c92..651b7bb6bb 100644
--- a/features/invite/impl/src/test/kotlin/io/element/android/features/invite/impl/declineandblock/DeclineAndBlockPresenterTest.kt
+++ b/features/invite/impl/src/test/kotlin/io/element/android/features/invite/impl/declineandblock/DeclineAndBlockPresenterTest.kt
@@ -11,11 +11,11 @@ import com.google.common.truth.Truth.assertThat
import io.element.android.features.invite.api.InviteData
import io.element.android.features.invite.impl.DeclineInvite
import io.element.android.features.invite.impl.fake.FakeDeclineInvite
+import io.element.android.features.invite.test.anInviteData
import io.element.android.libraries.architecture.AsyncAction
import io.element.android.libraries.designsystem.utils.snackbar.SnackbarDispatcher
import io.element.android.libraries.matrix.api.core.RoomId
import io.element.android.libraries.matrix.test.A_ROOM_ID
-import io.element.android.libraries.matrix.test.A_ROOM_NAME
import io.element.android.tests.testutils.WarmUpRule
import io.element.android.tests.testutils.lambda.assert
import io.element.android.tests.testutils.lambda.lambdaRecorder
@@ -148,28 +148,16 @@ class DeclineAndBlockPresenterTest {
.isCalledOnce()
.with(value(A_ROOM_ID), value(true), value(false), value(""))
}
-
- private fun anInviteData(
- roomId: RoomId = A_ROOM_ID,
- name: String = A_ROOM_NAME,
- isDm: Boolean = false,
- ): InviteData {
- return InviteData(
- roomId = roomId,
- roomName = name,
- isDm = isDm,
- )
- }
-
- private fun createDeclineAndBlockPresenter(
- inviteData: InviteData = anInviteData(),
- declineInvite: DeclineInvite = FakeDeclineInvite(),
- snackbarDispatcher: SnackbarDispatcher = SnackbarDispatcher(),
- ): DeclineAndBlockPresenter {
- return DeclineAndBlockPresenter(
- inviteData = inviteData,
- declineInvite = declineInvite,
- snackbarDispatcher = snackbarDispatcher,
- )
- }
+}
+
+internal fun createDeclineAndBlockPresenter(
+ inviteData: InviteData = anInviteData(),
+ declineInvite: DeclineInvite = FakeDeclineInvite(),
+ snackbarDispatcher: SnackbarDispatcher = SnackbarDispatcher(),
+): DeclineAndBlockPresenter {
+ return DeclineAndBlockPresenter(
+ inviteData = inviteData,
+ declineInvite = declineInvite,
+ snackbarDispatcher = snackbarDispatcher,
+ )
}
diff --git a/features/invite/impl/src/test/kotlin/io/element/android/features/invite/impl/declineandblock/DefaultDeclineAndBlockEntryPointTest.kt b/features/invite/impl/src/test/kotlin/io/element/android/features/invite/impl/declineandblock/DefaultDeclineAndBlockEntryPointTest.kt
new file mode 100644
index 0000000000..7cdf208b9a
--- /dev/null
+++ b/features/invite/impl/src/test/kotlin/io/element/android/features/invite/impl/declineandblock/DefaultDeclineAndBlockEntryPointTest.kt
@@ -0,0 +1,41 @@
+/*
+ * Copyright 2025 New Vector Ltd.
+ *
+ * SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial
+ * Please see LICENSE files in the repository root for full details.
+ */
+
+package io.element.android.features.invite.impl.declineandblock
+
+import androidx.arch.core.executor.testing.InstantTaskExecutorRule
+import com.bumble.appyx.core.modality.BuildContext
+import com.google.common.truth.Truth.assertThat
+import io.element.android.features.invite.test.anInviteData
+import io.element.android.tests.testutils.node.TestParentNode
+import org.junit.Rule
+import org.junit.Test
+
+class DefaultDeclineAndBlockEntryPointTest {
+ @get:Rule
+ val instantTaskExecutorRule = InstantTaskExecutorRule()
+
+ @Test
+ fun `test node builder`() {
+ val entryPoint = DefaultDeclineAndBlockEntryPoint()
+ val parentNode = TestParentNode.create { buildContext, plugins ->
+ DeclineAndBlockNode(
+ buildContext = buildContext,
+ plugins = plugins,
+ presenterFactory = { inviteData -> createDeclineAndBlockPresenter() }
+ )
+ }
+ val inviteData = anInviteData()
+ val result = entryPoint.createNode(
+ parentNode = parentNode,
+ buildContext = BuildContext.root(null),
+ inviteData = inviteData
+ )
+ assertThat(result).isInstanceOf(DeclineAndBlockNode::class.java)
+ assertThat(result.plugins).contains(DeclineAndBlockNode.Inputs(inviteData))
+ }
+}
diff --git a/features/invitepeople/api/src/main/kotlin/io/element/android/features/invitepeople/api/InvitePeopleState.kt b/features/invitepeople/api/src/main/kotlin/io/element/android/features/invitepeople/api/InvitePeopleState.kt
index db8b9ffbd2..75fd211295 100644
--- a/features/invitepeople/api/src/main/kotlin/io/element/android/features/invitepeople/api/InvitePeopleState.kt
+++ b/features/invitepeople/api/src/main/kotlin/io/element/android/features/invitepeople/api/InvitePeopleState.kt
@@ -7,8 +7,11 @@
package io.element.android.features.invitepeople.api
+import io.element.android.libraries.architecture.AsyncAction
+
interface InvitePeopleState {
val canInvite: Boolean
val isSearchActive: Boolean
+ val sendInvitesAction: AsyncAction
val eventSink: (InvitePeopleEvents) -> Unit
}
diff --git a/features/invitepeople/api/src/main/kotlin/io/element/android/features/invitepeople/api/InvitePeopleStateProvider.kt b/features/invitepeople/api/src/main/kotlin/io/element/android/features/invitepeople/api/InvitePeopleStateProvider.kt
index b69ad7c225..fdcebb17a2 100644
--- a/features/invitepeople/api/src/main/kotlin/io/element/android/features/invitepeople/api/InvitePeopleStateProvider.kt
+++ b/features/invitepeople/api/src/main/kotlin/io/element/android/features/invitepeople/api/InvitePeopleStateProvider.kt
@@ -8,28 +8,33 @@
package io.element.android.features.invitepeople.api
import androidx.compose.ui.tooling.preview.PreviewParameterProvider
+import io.element.android.libraries.architecture.AsyncAction
class InvitePeopleStateProvider : PreviewParameterProvider {
override val values: Sequence
get() = sequenceOf(
aPreviewInvitePeopleState(),
aPreviewInvitePeopleState(canInvite = true),
- aPreviewInvitePeopleState(isSearchActive = true)
+ aPreviewInvitePeopleState(isSearchActive = true),
+ aPreviewInvitePeopleState(sendInvitesAction = AsyncAction.Loading),
)
}
private data class PreviewInvitePeopleState(
override val canInvite: Boolean,
override val isSearchActive: Boolean,
+ override val sendInvitesAction: AsyncAction,
override val eventSink: (InvitePeopleEvents) -> Unit,
) : InvitePeopleState
private fun aPreviewInvitePeopleState(
canInvite: Boolean = false,
isSearchActive: Boolean = false,
+ sendInvitesAction: AsyncAction = AsyncAction.Uninitialized,
eventSink: (InvitePeopleEvents) -> Unit = {},
) = PreviewInvitePeopleState(
canInvite = canInvite,
isSearchActive = isSearchActive,
+ sendInvitesAction = sendInvitesAction,
eventSink = eventSink
)
diff --git a/features/invitepeople/impl/build.gradle.kts b/features/invitepeople/impl/build.gradle.kts
index 9133700f06..f0fcde6a00 100644
--- a/features/invitepeople/impl/build.gradle.kts
+++ b/features/invitepeople/impl/build.gradle.kts
@@ -1,4 +1,5 @@
import extension.setupDependencyInjection
+import extension.testCommonDependencies
/*
* Copyright 2022-2024 New Vector Ltd.
@@ -37,17 +38,8 @@ dependencies {
implementation(projects.services.apperror.api)
api(projects.features.invitepeople.api)
- testImplementation(libs.test.junit)
- testImplementation(libs.test.mockk)
- testImplementation(libs.coroutines.test)
- testImplementation(libs.molecule.runtime)
- testImplementation(libs.test.truth)
- testImplementation(libs.test.turbine)
- testImplementation(libs.test.robolectric)
+ testCommonDependencies(libs, true)
testImplementation(projects.libraries.matrix.test)
testImplementation(projects.libraries.usersearch.test)
testImplementation(projects.services.apperror.test)
- testImplementation(projects.tests.testutils)
- testImplementation(libs.androidx.compose.ui.test.junit)
- testReleaseImplementation(libs.androidx.compose.ui.test.manifest)
}
diff --git a/features/invitepeople/impl/src/main/kotlin/io/element/android/features/invitepeople/impl/DefaultInvitePeoplePresenter.kt b/features/invitepeople/impl/src/main/kotlin/io/element/android/features/invitepeople/impl/DefaultInvitePeoplePresenter.kt
index e473f5708b..2ce5cd929a 100644
--- a/features/invitepeople/impl/src/main/kotlin/io/element/android/features/invitepeople/impl/DefaultInvitePeoplePresenter.kt
+++ b/features/invitepeople/impl/src/main/kotlin/io/element/android/features/invitepeople/impl/DefaultInvitePeoplePresenter.kt
@@ -23,9 +23,11 @@ import dev.zacsweers.metro.Inject
import io.element.android.features.invitepeople.api.InvitePeopleEvents
import io.element.android.features.invitepeople.api.InvitePeoplePresenter
import io.element.android.features.invitepeople.api.InvitePeopleState
+import io.element.android.libraries.architecture.AsyncAction
import io.element.android.libraries.architecture.AsyncData
import io.element.android.libraries.architecture.map
import io.element.android.libraries.architecture.runCatchingUpdatingState
+import io.element.android.libraries.architecture.runUpdatingState
import io.element.android.libraries.core.coroutine.CoroutineDispatchers
import io.element.android.libraries.designsystem.theme.components.SearchBarResultState
import io.element.android.libraries.di.SessionScope
@@ -73,6 +75,8 @@ class DefaultInvitePeoplePresenter(
var searchQuery by rememberSaveable { mutableStateOf("") }
var searchActive by rememberSaveable { mutableStateOf(false) }
val showSearchLoader = rememberSaveable { mutableStateOf(false) }
+ val sendInvitesAction = remember { mutableStateOf>(AsyncAction.Uninitialized) }
+
val room by produceState(if (joinedRoom != null) AsyncData.Success(joinedRoom) else AsyncData.Loading()) {
if (joinedRoom == null) {
val result = matrixClient.getJoinedRoom(roomId)
@@ -116,7 +120,7 @@ class DefaultInvitePeoplePresenter(
}
is InvitePeopleEvents.SendInvites -> {
room.dataOrNull()?.let {
- sessionCoroutineScope.sendInvites(it, selectedUsers.value)
+ sessionCoroutineScope.sendInvites(it, selectedUsers.value, sendInvitesAction)
}
}
is InvitePeopleEvents.CloseSearch -> {
@@ -128,12 +132,13 @@ class DefaultInvitePeoplePresenter(
return DefaultInvitePeopleState(
room = room.map { },
- canInvite = selectedUsers.value.isNotEmpty(),
+ canInvite = selectedUsers.value.isNotEmpty() && !sendInvitesAction.value.isLoading(),
selectedUsers = selectedUsers.value,
searchQuery = searchQuery,
isSearchActive = searchActive,
searchResults = searchResults.value,
showSearchLoader = showSearchLoader.value,
+ sendInvitesAction = sendInvitesAction.value,
eventSink = ::handleEvents,
)
}
@@ -141,16 +146,21 @@ class DefaultInvitePeoplePresenter(
private fun CoroutineScope.sendInvites(
room: JoinedRoom,
selectedUsers: List,
+ sendInvitesAction: MutableState>,
) = launch {
- val anyInviteFailed = selectedUsers
- .map { room.inviteUserById(it.userId) }
- .any { it.isFailure }
+ sendInvitesAction.runUpdatingState {
+ val anyInviteFailed = selectedUsers
+ .map { room.inviteUserById(it.userId) }
+ .any { it.isFailure }
- if (anyInviteFailed) {
- appErrorStateService.showError(
- titleRes = CommonStrings.common_unable_to_invite_title,
- bodyRes = CommonStrings.common_unable_to_invite_message,
- )
+ if (anyInviteFailed) {
+ appErrorStateService.showError(
+ titleRes = CommonStrings.common_unable_to_invite_title,
+ bodyRes = CommonStrings.common_unable_to_invite_message,
+ )
+ }
+
+ Result.success(Unit)
}
}
diff --git a/features/invitepeople/impl/src/main/kotlin/io/element/android/features/invitepeople/impl/DefaultInvitePeopleState.kt b/features/invitepeople/impl/src/main/kotlin/io/element/android/features/invitepeople/impl/DefaultInvitePeopleState.kt
index 77ba8aad05..5ae51a8698 100644
--- a/features/invitepeople/impl/src/main/kotlin/io/element/android/features/invitepeople/impl/DefaultInvitePeopleState.kt
+++ b/features/invitepeople/impl/src/main/kotlin/io/element/android/features/invitepeople/impl/DefaultInvitePeopleState.kt
@@ -9,6 +9,7 @@ package io.element.android.features.invitepeople.impl
import io.element.android.features.invitepeople.api.InvitePeopleEvents
import io.element.android.features.invitepeople.api.InvitePeopleState
+import io.element.android.libraries.architecture.AsyncAction
import io.element.android.libraries.architecture.AsyncData
import io.element.android.libraries.designsystem.theme.components.SearchBarResultState
import io.element.android.libraries.matrix.api.user.MatrixUser
@@ -22,5 +23,6 @@ data class DefaultInvitePeopleState(
val searchResults: SearchBarResultState>,
val selectedUsers: ImmutableList,
override val isSearchActive: Boolean,
+ override val sendInvitesAction: AsyncAction,
override val eventSink: (InvitePeopleEvents) -> Unit
) : InvitePeopleState
diff --git a/features/invitepeople/impl/src/main/kotlin/io/element/android/features/invitepeople/impl/DefaultInvitePeopleStateProvider.kt b/features/invitepeople/impl/src/main/kotlin/io/element/android/features/invitepeople/impl/DefaultInvitePeopleStateProvider.kt
index 980d32e7fb..ebcd932a55 100644
--- a/features/invitepeople/impl/src/main/kotlin/io/element/android/features/invitepeople/impl/DefaultInvitePeopleStateProvider.kt
+++ b/features/invitepeople/impl/src/main/kotlin/io/element/android/features/invitepeople/impl/DefaultInvitePeopleStateProvider.kt
@@ -8,6 +8,7 @@
package io.element.android.features.invitepeople.impl
import androidx.compose.ui.tooling.preview.PreviewParameterProvider
+import io.element.android.libraries.architecture.AsyncAction
import io.element.android.libraries.architecture.AsyncData
import io.element.android.libraries.designsystem.theme.components.SearchBarResultState
import io.element.android.libraries.matrix.api.user.MatrixUser
@@ -68,6 +69,11 @@ internal class DefaultInvitePeopleStateProvider : PreviewParameterProvider = persistentListOf(),
isSearchActive: Boolean = false,
showSearchLoader: Boolean = false,
+ sendInvitesAction: AsyncAction = AsyncAction.Uninitialized,
): DefaultInvitePeopleState {
return DefaultInvitePeopleState(
room = room,
@@ -102,6 +109,7 @@ private fun aDefaultInvitePeopleState(
selectedUsers = selectedUsers,
isSearchActive = isSearchActive,
showSearchLoader = showSearchLoader,
+ sendInvitesAction = sendInvitesAction,
eventSink = {},
)
}
diff --git a/features/invitepeople/impl/src/test/kotlin/io/element/android/features/invitepeople/impl/DefaultInvitePeoplePresenterTest.kt b/features/invitepeople/impl/src/test/kotlin/io/element/android/features/invitepeople/impl/DefaultInvitePeoplePresenterTest.kt
index 1e438fab8e..e51c3ee352 100644
--- a/features/invitepeople/impl/src/test/kotlin/io/element/android/features/invitepeople/impl/DefaultInvitePeoplePresenterTest.kt
+++ b/features/invitepeople/impl/src/test/kotlin/io/element/android/features/invitepeople/impl/DefaultInvitePeoplePresenterTest.kt
@@ -409,10 +409,23 @@ internal class DefaultInvitePeoplePresenterTest {
assertThat(resultState.searchResults).isInstanceOf(SearchBarResultState.Results::class.java)
// Send invites
initialState.eventSink(InvitePeopleEvents.SendInvites)
+
+ // Can't invite in the loading state
+ awaitItem().run {
+ assertThat(sendInvitesAction.isLoading()).isTrue()
+ assertThat(canInvite).isFalse()
+ }
+
delay(1_000)
inviteUserResult.assertions().isCalledOnce().with(
value(selectedUser.userId)
)
+
+ // Can invite again once the action is finished
+ awaitItem().run {
+ assertThat(sendInvitesAction.isReady()).isTrue()
+ assertThat(canInvite).isTrue()
+ }
}
}
@@ -445,6 +458,13 @@ internal class DefaultInvitePeoplePresenterTest {
assertThat(resultState.searchResults).isInstanceOf(SearchBarResultState.Results::class.java)
// Send invites
initialState.eventSink(InvitePeopleEvents.SendInvites)
+
+ // Can't invite in the loading state
+ awaitItem().run {
+ assertThat(sendInvitesAction.isLoading()).isTrue()
+ assertThat(canInvite).isFalse()
+ }
+
delay(1_000)
inviteUserResult.assertions().isCalledOnce().with(
value(selectedUser.userId)
@@ -455,6 +475,12 @@ internal class DefaultInvitePeoplePresenterTest {
value(CommonStrings.common_unable_to_invite_title),
value(CommonStrings.common_unable_to_invite_message)
)
+
+ // Can invite again once the action is finished
+ awaitItem().run {
+ assertThat(sendInvitesAction.isReady()).isTrue()
+ assertThat(canInvite).isTrue()
+ }
}
}
diff --git a/features/joinroom/impl/build.gradle.kts b/features/joinroom/impl/build.gradle.kts
index 22821a3a84..476aacd863 100644
--- a/features/joinroom/impl/build.gradle.kts
+++ b/features/joinroom/impl/build.gradle.kts
@@ -1,4 +1,5 @@
import extension.setupDependencyInjection
+import extension.testCommonDependencies
/*
* Copyright 2024 New Vector Ltd.
@@ -38,16 +39,9 @@ dependencies {
implementation(projects.libraries.preferences.api)
implementation(projects.appconfig)
- testImplementation(libs.test.junit)
- testImplementation(libs.coroutines.test)
- testImplementation(libs.molecule.runtime)
- testImplementation(libs.test.robolectric)
- testImplementation(libs.test.truth)
- testImplementation(libs.test.turbine)
+ testCommonDependencies(libs, true)
testImplementation(projects.features.invite.test)
testImplementation(projects.libraries.matrix.test)
- testImplementation(projects.tests.testutils)
- testImplementation(libs.androidx.compose.ui.test.junit)
testImplementation(projects.libraries.preferences.test)
- testReleaseImplementation(libs.androidx.compose.ui.test.manifest)
+ testImplementation(projects.libraries.previewutils)
}
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 04e5b904e6..cb7ad57837 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
@@ -23,6 +23,7 @@ import androidx.compose.runtime.setValue
import dev.zacsweers.metro.Assisted
import dev.zacsweers.metro.Inject
import im.vector.app.features.analytics.plan.JoinedRoom
+import io.element.android.features.invite.api.InviteData
import io.element.android.features.invite.api.SeenInvitesStore
import io.element.android.features.invite.api.acceptdecline.AcceptDeclineInviteEvents
import io.element.android.features.invite.api.acceptdecline.AcceptDeclineInviteState
@@ -34,7 +35,6 @@ import io.element.android.features.roomdirectory.api.RoomDescription
import io.element.android.libraries.architecture.AsyncAction
import io.element.android.libraries.architecture.Presenter
import io.element.android.libraries.architecture.runUpdatingState
-import io.element.android.libraries.core.coroutine.mapState
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
@@ -43,16 +43,21 @@ import io.element.android.libraries.matrix.api.exception.ClientException
import io.element.android.libraries.matrix.api.exception.ErrorKind
import io.element.android.libraries.matrix.api.room.CurrentUserMembership
import io.element.android.libraries.matrix.api.room.RoomInfo
-import io.element.android.libraries.matrix.api.room.RoomMember
+import io.element.android.libraries.matrix.api.room.RoomMembershipDetails
import io.element.android.libraries.matrix.api.room.RoomType
import io.element.android.libraries.matrix.api.room.isDm
import io.element.android.libraries.matrix.api.room.join.JoinRoom
import io.element.android.libraries.matrix.api.room.join.JoinRule
import io.element.android.libraries.matrix.api.room.preview.RoomPreviewInfo
+import io.element.android.libraries.matrix.api.spaces.SpaceRoom
import io.element.android.libraries.matrix.ui.model.toInviteSender
+import io.element.android.libraries.matrix.ui.safety.rememberHideInvitesAvatar
+import kotlinx.collections.immutable.persistentListOf
+import kotlinx.collections.immutable.toPersistentList
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.launch
import java.util.Optional
+import kotlin.jvm.optionals.getOrNull
@Inject
class JoinRoomPresenter(
@@ -70,7 +75,7 @@ class JoinRoomPresenter(
private val buildMeta: BuildMeta,
private val seenInvitesStore: SeenInvitesStore,
) : Presenter {
- interface Factory {
+ fun interface Factory {
fun create(
roomId: RoomId,
roomIdOrAlias: RoomIdOrAlias,
@@ -80,6 +85,8 @@ class JoinRoomPresenter(
): JoinRoomPresenter
}
+ private val spaceList = matrixClient.spaceService.spaceRoomList(roomId)
+
@Composable
override fun present(): JoinRoomState {
val coroutineScope = rememberCoroutineScope()
@@ -87,69 +94,53 @@ class JoinRoomPresenter(
val roomInfo by remember {
matrixClient.getRoomInfoFlow(roomId)
}.collectAsState(initial = Optional.empty())
+ val spaceRoom by remember {
+ spaceList.currentSpaceFlow()
+ }.collectAsState()
val joinAction: MutableState> = remember { mutableStateOf(AsyncAction.Uninitialized) }
val knockAction: MutableState> = remember { mutableStateOf(AsyncAction.Uninitialized) }
val cancelKnockAction: MutableState> = remember { mutableStateOf(AsyncAction.Uninitialized) }
val forgetRoomAction: MutableState> = remember { mutableStateOf(AsyncAction.Uninitialized) }
var knockMessage by rememberSaveable { mutableStateOf("") }
var isDismissingContent by remember { mutableStateOf(false) }
- val hideInviteAvatars by remember {
- matrixClient
- .mediaPreviewService()
- .mediaPreviewConfigFlow
- .mapState { config -> config.hideInviteAvatar }
- }.collectAsState()
+ val hideInviteAvatars by matrixClient.rememberHideInvitesAvatar()
val canReportRoom by produceState(false) { value = matrixClient.canReportRoom() }
- val contentState by produceState(
- initialValue = ContentState.Loading,
- key1 = roomInfo,
- key2 = retryCount,
- key3 = isDismissingContent,
- ) {
+ var contentState by remember {
+ mutableStateOf(ContentState.Loading)
+ }
+ LaunchedEffect(roomInfo, retryCount, isDismissingContent, spaceRoom) {
when {
- isDismissingContent -> value = ContentState.Dismissing
+ isDismissingContent -> contentState = ContentState.Dismissing
roomInfo.isPresent -> {
val notJoinedRoom = matrixClient.getRoomPreview(roomIdOrAlias, serverNames).getOrNull()
- val (sender, reason) = when (roomInfo.get().currentUserMembership) {
- CurrentUserMembership.BANNED -> {
- // Workaround to get info about the sender for banned rooms
- // TODO re-do this once we have a better API in the SDK
- val membershipDetails = notJoinedRoom?.membershipDetails()?.getOrNull()
- membershipDetails?.senderMember to membershipDetails?.currentUserMember?.membershipChangeReason
- }
- CurrentUserMembership.INVITED -> {
- roomInfo.get().inviter to null
- }
- else -> null to null
- }
+ val membershipDetails = notJoinedRoom?.membershipDetails()?.getOrNull()
val joinedMembersCountOverride = notJoinedRoom?.previewInfo?.numberOfJoinedMembers
- value = roomInfo.get().toContentState(
- membershipSender = sender,
+ contentState = roomInfo.get().toContentState(
joinedMembersCountOverride = joinedMembersCountOverride,
- reason = reason,
+ membershipDetails = membershipDetails,
+ childrenCount = spaceRoom.getOrNull()?.childrenCount,
)
}
+ spaceRoom.isPresent -> {
+ val spaceRoom = spaceRoom.get()
+ // Only use this state when space is not locally known
+ contentState = if (spaceRoom.state != null) {
+ ContentState.Loading
+ } else {
+ spaceRoom.toContentState()
+ }
+ }
roomDescription.isPresent -> {
- value = roomDescription.get().toContentState()
+ contentState = roomDescription.get().toContentState()
}
else -> {
- value = ContentState.Loading
+ contentState = ContentState.Loading
val result = matrixClient.getRoomPreview(roomIdOrAlias, serverNames)
- value = result.fold(
+ contentState = result.fold(
onSuccess = { preview ->
- val membershipInfo = when (preview.previewInfo.membership) {
- CurrentUserMembership.INVITED,
- CurrentUserMembership.BANNED,
- CurrentUserMembership.KNOCKED -> {
- preview.membershipDetails().getOrNull()
- }
- else -> null
- }
- preview.previewInfo.toContentState(
- senderMember = membershipInfo?.senderMember,
- reason = membershipInfo?.currentUserMember?.membershipChangeReason,
- )
+ val membershipDetails = preview.membershipDetails().getOrNull()
+ preview.previewInfo.toContentState(membershipDetails)
},
onFailure = { throwable ->
if (throwable is ClientException.MatrixApi && (throwable.kind == ErrorKind.NotFound || throwable.kind == ErrorKind.Forbidden)) {
@@ -257,30 +248,56 @@ class JoinRoomPresenter(
}
}
-private fun RoomPreviewInfo.toContentState(senderMember: RoomMember?, reason: String?): ContentState {
+private fun RoomPreviewInfo.toContentState(membershipDetails: RoomMembershipDetails?): ContentState {
return ContentState.Loaded(
roomId = roomId,
name = name,
topic = topic,
alias = canonicalAlias,
numberOfMembers = numberOfJoinedMembers,
- isDm = false,
- roomType = roomType,
roomAvatarUrl = avatarUrl,
- joinAuthorisationStatus = when (membership) {
- CurrentUserMembership.INVITED -> {
- JoinAuthorisationStatus.IsInvited(
- inviteData = toInviteData(),
- inviteSender = senderMember?.toInviteSender()
- )
- }
- CurrentUserMembership.BANNED -> JoinAuthorisationStatus.IsBanned(senderMember?.toInviteSender(), reason)
- CurrentUserMembership.KNOCKED -> JoinAuthorisationStatus.IsKnocked
- else -> joinRule.toJoinAuthorisationStatus()
+ joinAuthorisationStatus = computeJoinAuthorisationStatus(
+ membership,
+ membershipDetails,
+ joinRule,
+ { toInviteData() }
+ ),
+ joinRule = joinRule,
+ details = when (roomType) {
+ is RoomType.Other,
+ RoomType.Room -> LoadedDetails.Room(
+ isDm = false,
+ )
+ RoomType.Space -> LoadedDetails.Space(
+ childrenCount = 0,
+ heroes = persistentListOf(),
+ )
}
)
}
+private fun SpaceRoom.toContentState(): ContentState {
+ return ContentState.Loaded(
+ roomId = roomId,
+ name = name,
+ topic = topic,
+ alias = canonicalAlias,
+ numberOfMembers = numJoinedMembers.toLong(),
+ roomAvatarUrl = avatarUrl,
+ joinAuthorisationStatus = computeJoinAuthorisationStatus(
+ membership = state,
+ membershipDetails = null,
+ joinRule = joinRule,
+ inviteData = { toInviteData() }
+ ),
+ joinRule = joinRule,
+ details = LoadedDetails.Space(
+ childrenCount = childrenCount,
+ heroes = heroes.toPersistentList(),
+ )
+ )
+}
+
@VisibleForTesting
internal fun RoomDescription.toContentState(): ContentState {
return ContentState.Loaded(
@@ -289,22 +306,29 @@ internal fun RoomDescription.toContentState(): ContentState {
topic = topic,
alias = alias,
numberOfMembers = numberOfMembers,
- isDm = false,
- roomType = RoomType.Room,
roomAvatarUrl = avatarUrl,
joinAuthorisationStatus = when (joinRule) {
RoomDescription.JoinRule.KNOCK -> JoinAuthorisationStatus.CanKnock
RoomDescription.JoinRule.PUBLIC -> JoinAuthorisationStatus.CanJoin
else -> JoinAuthorisationStatus.Unknown
- }
+ },
+ joinRule = when (joinRule) {
+ RoomDescription.JoinRule.KNOCK -> JoinRule.Knock
+ RoomDescription.JoinRule.PUBLIC -> JoinRule.Public
+ RoomDescription.JoinRule.RESTRICTED -> JoinRule.Restricted(persistentListOf())
+ RoomDescription.JoinRule.KNOCK_RESTRICTED -> JoinRule.KnockRestricted(persistentListOf())
+ RoomDescription.JoinRule.INVITE -> JoinRule.Invite
+ RoomDescription.JoinRule.UNKNOWN -> null
+ },
+ details = LoadedDetails.Room(isDm = false)
)
}
@VisibleForTesting
internal fun RoomInfo.toContentState(
- membershipSender: RoomMember?,
joinedMembersCountOverride: Long?,
- reason: String?,
+ membershipDetails: RoomMembershipDetails?,
+ childrenCount: Int?,
): ContentState {
return ContentState.Loaded(
roomId = id,
@@ -312,24 +336,49 @@ internal fun RoomInfo.toContentState(
topic = topic,
alias = canonicalAlias,
numberOfMembers = joinedMembersCountOverride ?: joinedMembersCount,
- isDm = isDm,
- roomType = if (isSpace) RoomType.Space else RoomType.Room,
roomAvatarUrl = avatarUrl,
- joinAuthorisationStatus = when (currentUserMembership) {
- CurrentUserMembership.INVITED -> JoinAuthorisationStatus.IsInvited(
- inviteData = toInviteData(),
- inviteSender = membershipSender?.toInviteSender(),
+ joinAuthorisationStatus = computeJoinAuthorisationStatus(
+ membership = currentUserMembership,
+ membershipDetails = membershipDetails,
+ joinRule = joinRule,
+ inviteData = { toInviteData() }
+ ),
+ joinRule = joinRule,
+ details = if (isSpace) {
+ LoadedDetails.Space(
+ childrenCount = childrenCount ?: 0,
+ heroes = heroes,
)
- CurrentUserMembership.BANNED -> JoinAuthorisationStatus.IsBanned(
- banSender = membershipSender?.toInviteSender(),
- reason = reason,
+ } else {
+ LoadedDetails.Room(
+ isDm = isDm,
)
- CurrentUserMembership.KNOCKED -> JoinAuthorisationStatus.IsKnocked
- else -> joinRule.toJoinAuthorisationStatus()
- }
+ },
)
}
+private fun computeJoinAuthorisationStatus(
+ membership: CurrentUserMembership?,
+ membershipDetails: RoomMembershipDetails?,
+ joinRule: JoinRule?,
+ inviteData: () -> InviteData,
+): JoinAuthorisationStatus {
+ return when (membership) {
+ CurrentUserMembership.INVITED -> {
+ JoinAuthorisationStatus.IsInvited(
+ inviteData = inviteData(),
+ inviteSender = membershipDetails?.senderMember?.toInviteSender()
+ )
+ }
+ CurrentUserMembership.BANNED -> JoinAuthorisationStatus.IsBanned(
+ membershipDetails?.senderMember?.toInviteSender(),
+ membershipDetails?.membershipChangeReason
+ )
+ CurrentUserMembership.KNOCKED -> JoinAuthorisationStatus.IsKnocked
+ else -> joinRule.toJoinAuthorisationStatus()
+ }
+}
+
private fun JoinRule?.toJoinAuthorisationStatus(): JoinAuthorisationStatus {
return when (this) {
JoinRule.Knock,
diff --git a/features/joinroom/impl/src/main/kotlin/io/element/android/features/joinroom/impl/JoinRoomState.kt b/features/joinroom/impl/src/main/kotlin/io/element/android/features/joinroom/impl/JoinRoomState.kt
index 5b9f8007a3..f27a290f5d 100644
--- a/features/joinroom/impl/src/main/kotlin/io/element/android/features/joinroom/impl/JoinRoomState.kt
+++ b/features/joinroom/impl/src/main/kotlin/io/element/android/features/joinroom/impl/JoinRoomState.kt
@@ -16,9 +16,11 @@ 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.core.RoomIdOrAlias
-import io.element.android.libraries.matrix.api.room.RoomType
import io.element.android.libraries.matrix.api.room.join.JoinRoom
+import io.element.android.libraries.matrix.api.room.join.JoinRule
+import io.element.android.libraries.matrix.api.user.MatrixUser
import io.element.android.libraries.matrix.ui.model.InviteSender
+import kotlinx.collections.immutable.ImmutableList
internal const val MAX_KNOCK_MESSAGE_LENGTH = 500
@@ -41,9 +43,6 @@ data class JoinRoomState(
val joinAuthorisationStatus = when (contentState) {
is ContentState.Loaded -> {
when {
- contentState.roomType == RoomType.Space -> {
- JoinAuthorisationStatus.IsSpace(applicationName)
- }
isJoinActionUnauthorized -> {
JoinAuthorisationStatus.Unauthorized
}
@@ -77,12 +76,13 @@ sealed interface ContentState {
val topic: String?,
val alias: RoomAlias?,
val numberOfMembers: Long?,
- val isDm: Boolean,
- val roomType: RoomType,
val roomAvatarUrl: String?,
val joinAuthorisationStatus: JoinAuthorisationStatus,
+ val joinRule: JoinRule?,
+ val details: LoadedDetails,
) : ContentState {
val showMemberCount = numberOfMembers != null
+ val isSpace = details is LoadedDetails.Space
fun avatarData(size: AvatarSize): AvatarData {
return AvatarData(
@@ -95,9 +95,20 @@ sealed interface ContentState {
}
}
+@Immutable
+sealed interface LoadedDetails {
+ data class Room(
+ val isDm: Boolean,
+ ) : LoadedDetails
+
+ data class Space(
+ val childrenCount: Int,
+ val heroes: ImmutableList,
+ ) : LoadedDetails
+}
+
sealed interface JoinAuthorisationStatus {
data object None : JoinAuthorisationStatus
- data class IsSpace(val applicationName: String) : JoinAuthorisationStatus
data class IsInvited(val inviteData: InviteData, val inviteSender: InviteSender?) : JoinAuthorisationStatus
data class IsBanned(val banSender: InviteSender?, val reason: String?) : JoinAuthorisationStatus
data object IsKnocked : JoinAuthorisationStatus
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 8f891fe645..8eeecab83c 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
@@ -20,9 +20,11 @@ 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.exception.ClientException
-import io.element.android.libraries.matrix.api.room.RoomType
import io.element.android.libraries.matrix.api.room.join.JoinRoom
+import io.element.android.libraries.matrix.api.room.join.JoinRule
+import io.element.android.libraries.matrix.api.user.MatrixUser
import io.element.android.libraries.matrix.ui.model.InviteSender
+import kotlinx.collections.immutable.toPersistentList
open class JoinRoomStateProvider : PreviewParameterProvider {
override val values: Sequence
@@ -77,13 +79,17 @@ open class JoinRoomStateProvider : PreviewParameterProvider {
name = "A space",
alias = null,
topic = "This is the topic of a space",
- roomType = RoomType.Space,
+ details = aLoadedDetailsSpace(
+ childrenCount = 42,
+ ),
)
),
aJoinRoomState(
contentState = aLoadedContentState(
name = "A DM",
- isDm = true,
+ details = aLoadedDetailsRoom(
+ isDm = true,
+ ),
)
),
aJoinRoomState(
@@ -156,20 +162,34 @@ fun aLoadedContentState(
alias: RoomAlias? = RoomAlias("#exa:matrix.org"),
topic: String? = "Element X is a secure, private and decentralized messenger.",
numberOfMembers: Long? = null,
- isDm: Boolean = false,
- roomType: RoomType = RoomType.Room,
roomAvatarUrl: String? = null,
joinAuthorisationStatus: JoinAuthorisationStatus = JoinAuthorisationStatus.Unknown,
+ joinRule: JoinRule? = null,
+ details: LoadedDetails = aLoadedDetailsRoom(isDm = false),
) = ContentState.Loaded(
roomId = roomId,
name = name,
alias = alias,
topic = topic,
numberOfMembers = numberOfMembers,
- isDm = isDm,
- roomType = roomType,
roomAvatarUrl = roomAvatarUrl,
- joinAuthorisationStatus = joinAuthorisationStatus
+ joinAuthorisationStatus = joinAuthorisationStatus,
+ joinRule = joinRule,
+ details = details,
+)
+
+fun aLoadedDetailsRoom(
+ isDm: Boolean = false,
+) = LoadedDetails.Room(
+ isDm = isDm
+)
+
+fun aLoadedDetailsSpace(
+ childrenCount: Int = 0,
+ heroes: List = emptyList(),
+) = LoadedDetails.Space(
+ childrenCount = childrenCount,
+ heroes = heroes.toPersistentList()
)
fun aJoinRoomState(
diff --git a/features/joinroom/impl/src/main/kotlin/io/element/android/features/joinroom/impl/JoinRoomView.kt b/features/joinroom/impl/src/main/kotlin/io/element/android/features/joinroom/impl/JoinRoomView.kt
index 03598425e9..6da7aadfe7 100644
--- a/features/joinroom/impl/src/main/kotlin/io/element/android/features/joinroom/impl/JoinRoomView.kt
+++ b/features/joinroom/impl/src/main/kotlin/io/element/android/features/joinroom/impl/JoinRoomView.kt
@@ -7,21 +7,20 @@
package io.element.android.features.joinroom.impl
+import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
-import androidx.compose.foundation.layout.BoxWithConstraints
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.PaddingValues
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
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
-import androidx.compose.foundation.layout.sizeIn
import androidx.compose.foundation.rememberScrollState
+import androidx.compose.foundation.shape.CircleShape
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.foundation.verticalScroll
import androidx.compose.material3.ExperimentalMaterial3Api
@@ -38,6 +37,7 @@ import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.tooling.preview.PreviewParameter
import androidx.compose.ui.unit.dp
import io.element.android.compound.theme.ElementTheme
+import io.element.android.compound.tokens.generated.CompoundIcons
import io.element.android.features.invite.api.InviteData
import io.element.android.libraries.designsystem.atomic.atoms.PlaceholderAtom
import io.element.android.libraries.designsystem.atomic.atoms.RoomPreviewDescriptionAtom
@@ -65,14 +65,21 @@ 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.ButtonSize
import io.element.android.libraries.designsystem.theme.components.CircularProgressIndicator
+import io.element.android.libraries.designsystem.theme.components.Icon
+import io.element.android.libraries.designsystem.theme.components.IconSource
import io.element.android.libraries.designsystem.theme.components.OutlinedButton
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.TextField
import io.element.android.libraries.designsystem.theme.components.TopAppBar
+import io.element.android.libraries.designsystem.theme.placeholderBackground
import io.element.android.libraries.matrix.api.core.RoomIdOrAlias
-import io.element.android.libraries.matrix.ui.components.InviteSenderView
+import io.element.android.libraries.matrix.api.room.join.JoinRule
+import io.element.android.libraries.matrix.ui.components.SpaceInfoRow
+import io.element.android.libraries.matrix.ui.components.SpaceMembersView
+import io.element.android.libraries.matrix.ui.model.InviteSender
import io.element.android.libraries.ui.strings.CommonStrings
+import kotlinx.collections.immutable.persistentListOf
@Composable
fun JoinRoomView(
@@ -92,7 +99,7 @@ fun JoinRoomView(
containerColor = Color.Transparent,
contentPadding = PaddingValues(
horizontal = 16.dp,
- vertical = 32.dp
+ vertical = 24.dp
),
topBar = {
JoinRoomTopBar(
@@ -220,12 +227,14 @@ private fun JoinRoomFooter(
onClick = { onDeclineInvite(joinAuthorisationStatus.inviteData, false) },
modifier = Modifier.weight(1f),
size = ButtonSize.LargeLowPadding,
+ leadingIcon = IconSource.Vector(CompoundIcons.Close())
)
Button(
text = stringResource(CommonStrings.action_accept),
onClick = { onAcceptInvite(joinAuthorisationStatus.inviteData) },
modifier = Modifier.weight(1f),
size = ButtonSize.LargeLowPadding,
+ leadingIcon = IconSource.Vector(CompoundIcons.Check())
)
}
Spacer(modifier = Modifier.height(24.dp))
@@ -278,7 +287,6 @@ private fun JoinRoomFooter(
JoinAuthorisationStatus.Unknown -> JoinRestrictedFooter(onJoinRoom)
JoinAuthorisationStatus.Restricted -> JoinRestrictedFooter(onJoinRoom)
JoinAuthorisationStatus.Unauthorized -> JoinUnauthorizedFooter(onGoBack)
- is JoinAuthorisationStatus.IsSpace -> UnsupportedSpaceFooter(joinAuthorisationStatus.applicationName, onGoBack)
JoinAuthorisationStatus.None -> Unit
}
}
@@ -358,28 +366,6 @@ private fun JoinRestrictedFooter(
}
}
-@Composable
-private fun UnsupportedSpaceFooter(
- applicationName: String,
- onGoBack: () -> Unit,
- modifier: Modifier = Modifier,
-) {
- Column(modifier = modifier) {
- Announcement(
- title = stringResource(R.string.screen_join_room_space_not_supported_title),
- description = stringResource(R.string.screen_join_room_space_not_supported_description, applicationName),
- type = AnnouncementType.Informative(),
- )
- Spacer(Modifier.height(24.dp))
- Button(
- text = stringResource(CommonStrings.action_ok),
- onClick = onGoBack,
- modifier = Modifier.fillMaxWidth(),
- size = ButtonSize.Large,
- )
- }
-}
-
@Composable
private fun JoinRoomContent(
roomIdOrAlias: RoomIdOrAlias,
@@ -397,19 +383,40 @@ private fun JoinRoomContent(
IsKnockedLoadedContent()
}
else -> {
- Column(horizontalAlignment = Alignment.CenterHorizontally) {
- val inviteSender = (contentState.joinAuthorisationStatus as? JoinAuthorisationStatus.IsInvited)?.inviteSender
- if (inviteSender != null) {
- InviteSenderView(inviteSender = inviteSender, hideAvatarImage = hideAvatarsImages)
- Spacer(modifier = Modifier.height(32.dp))
- }
+ Column(
+ horizontalAlignment = Alignment.CenterHorizontally,
+ modifier = Modifier.verticalScroll(rememberScrollState())
+ ) {
DefaultLoadedContent(
- modifier = Modifier.verticalScroll(rememberScrollState()),
contentState = contentState,
- knockMessage = knockMessage,
hideAvatarImage = hideAvatarsImages,
- onKnockMessageUpdate = onKnockMessageUpdate
)
+ when (contentState.joinAuthorisationStatus) {
+ is JoinAuthorisationStatus.IsInvited -> {
+ val inviteSender = contentState.joinAuthorisationStatus.inviteSender
+ if (inviteSender != null) {
+ Spacer(Modifier.height(16.dp))
+ InvitedByView(inviteSender, hideAvatarsImages)
+ }
+ }
+ is JoinAuthorisationStatus.CanKnock -> {
+ Spacer(modifier = Modifier.height(24.dp))
+ val supportingText = if (knockMessage.isNotEmpty()) {
+ "${knockMessage.length}/$MAX_KNOCK_MESSAGE_LENGTH"
+ } else {
+ stringResource(R.string.screen_join_room_knock_message_description)
+ }
+ TextField(
+ value = knockMessage,
+ onValueChange = onKnockMessageUpdate,
+ maxLines = 3,
+ minLines = 3,
+ modifier = Modifier.fillMaxWidth(),
+ supportingText = supportingText
+ )
+ }
+ else -> Unit
+ }
}
}
}
@@ -422,6 +429,45 @@ private fun JoinRoomContent(
}
}
+@Composable
+private fun InvitedByView(
+ sender: InviteSender,
+ hideAvatarImage: Boolean,
+ modifier: Modifier = Modifier
+) {
+ Column(
+ modifier
+ .fillMaxWidth()
+ .padding(vertical = 16.dp),
+ horizontalAlignment = Alignment.CenterHorizontally
+ ) {
+ Text(
+ text = stringResource(R.string.screen_join_room_invited_by),
+ style = ElementTheme.typography.fontBodyMdRegular,
+ color = ElementTheme.colors.textSecondary
+ )
+ Spacer(Modifier.height(8.dp))
+ Avatar(
+ avatarData = sender.avatarData,
+ avatarType = AvatarType.User,
+ hideImage = hideAvatarImage,
+ forcedAvatarSize = AvatarSize.RoomPreviewInviter.dp
+ )
+ Spacer(Modifier.height(8.dp))
+ Text(
+ text = sender.displayName,
+ style = ElementTheme.typography.fontBodyLgRegular,
+ color = ElementTheme.colors.textPrimary
+ )
+ Spacer(Modifier.height(4.dp))
+ Text(
+ text = sender.userId.value,
+ style = ElementTheme.typography.fontBodySmRegular,
+ color = ElementTheme.colors.textSecondary
+ )
+ }
+}
+
@Composable
private fun UnknownRoomContent(
modifier: Modifier = Modifier
@@ -429,7 +475,21 @@ private fun UnknownRoomContent(
RoomPreviewOrganism(
modifier = modifier,
avatar = {
- Spacer(modifier = Modifier.size(AvatarSize.RoomHeader.dp))
+ Box(
+ modifier = Modifier
+ .size(AvatarSize.RoomPreviewHeader.dp)
+ .background(
+ color = ElementTheme.colors.placeholderBackground,
+ shape = CircleShape
+ )
+ ) {
+ Icon(
+ modifier = Modifier.align(Alignment.Center),
+ tint = ElementTheme.colors.iconPrimary,
+ imageVector = CompoundIcons.VisibilityOff(),
+ contentDescription = null,
+ )
+ }
},
title = {
RoomPreviewTitleAtom(stringResource(R.string.screen_join_room_title_no_preview))
@@ -448,7 +508,7 @@ private fun IncompleteContent(
RoomPreviewOrganism(
modifier = modifier,
avatar = {
- PlaceholderAtom(width = AvatarSize.RoomHeader.dp, height = AvatarSize.RoomHeader.dp)
+ PlaceholderAtom(width = AvatarSize.RoomPreviewHeader.dp, height = AvatarSize.RoomPreviewHeader.dp)
},
title = {
when (roomIdOrAlias) {
@@ -471,43 +531,32 @@ private fun IncompleteContent(
@Composable
private fun IsKnockedLoadedContent(modifier: Modifier = Modifier) {
- BoxWithConstraints(
- modifier = modifier
- .fillMaxHeight()
- .padding(horizontal = 16.dp),
- contentAlignment = Alignment.Center,
- ) {
- IconTitleSubtitleMolecule(
- modifier = Modifier.sizeIn(minHeight = maxHeight * 0.7f),
- iconStyle = BigIcon.Style.SuccessSolid,
- title = stringResource(R.string.screen_join_room_knock_sent_title),
- subTitle = stringResource(R.string.screen_join_room_knock_sent_description),
- )
- }
+ IconTitleSubtitleMolecule(
+ modifier = modifier.padding(horizontal = 8.dp),
+ iconStyle = BigIcon.Style.SuccessSolid,
+ title = stringResource(R.string.screen_join_room_knock_sent_title),
+ subTitle = stringResource(R.string.screen_join_room_knock_sent_description),
+ )
}
@Composable
private fun DefaultLoadedContent(
contentState: ContentState.Loaded,
- knockMessage: String,
hideAvatarImage: Boolean,
- onKnockMessageUpdate: (String) -> Unit,
modifier: Modifier = Modifier,
) {
RoomPreviewOrganism(
modifier = modifier,
avatar = {
Avatar(
- contentState.avatarData(AvatarSize.RoomHeader),
+ contentState.avatarData(AvatarSize.RoomPreviewHeader),
hideImage = hideAvatarImage,
- avatarType = AvatarType.Room(),
+ avatarType = if (contentState.isSpace) AvatarType.Space() else AvatarType.Room(),
)
},
title = {
if (contentState.name != null) {
- RoomPreviewTitleAtom(
- title = contentState.name,
- )
+ RoomPreviewTitleAtom(title = contentState.name)
} else {
RoomPreviewTitleAtom(
title = stringResource(id = CommonStrings.common_no_room_name),
@@ -516,37 +565,32 @@ private fun DefaultLoadedContent(
}
},
subtitle = {
- if (contentState.alias != null) {
- RoomPreviewSubtitleAtom(contentState.alias.value)
- }
- },
- description = {
- Column(
- horizontalAlignment = Alignment.CenterHorizontally,
- verticalArrangement = Arrangement.spacedBy(8.dp),
- ) {
- RoomPreviewDescriptionAtom(contentState.topic ?: "")
- if (contentState.joinAuthorisationStatus is JoinAuthorisationStatus.CanKnock) {
- Spacer(modifier = Modifier.height(24.dp))
- val supportingText = if (knockMessage.isNotEmpty()) {
- "${knockMessage.length}/$MAX_KNOCK_MESSAGE_LENGTH"
- } else {
- stringResource(R.string.screen_join_room_knock_message_description)
- }
- TextField(
- value = knockMessage,
- onValueChange = onKnockMessageUpdate,
- maxLines = 3,
- minLines = 3,
- modifier = Modifier.fillMaxWidth(),
- supportingText = supportingText
+ when {
+ contentState.details is LoadedDetails.Space -> {
+ SpaceInfoRow(
+ joinRule = contentState.joinRule ?: JoinRule.Public,
+ numberOfRooms = contentState.details.childrenCount,
)
}
+ contentState.alias != null -> {
+ RoomPreviewSubtitleAtom(contentState.alias.value)
+ }
}
},
+ description = {
+ RoomPreviewDescriptionAtom(
+ contentState.topic ?: "",
+ maxLines = if (contentState.joinAuthorisationStatus is JoinAuthorisationStatus.CanJoin) Int.MAX_VALUE else 2
+ )
+ },
memberCount = {
if (contentState.showMemberCount) {
- MembersCountMolecule(memberCount = contentState.numberOfMembers?.toInt() ?: 0)
+ val membersCount = contentState.numberOfMembers?.toInt() ?: 0
+ if (contentState.isSpace) {
+ SpaceMembersView(persistentListOf(), membersCount)
+ } else {
+ MembersCountMolecule(memberCount = membersCount)
+ }
}
}
)
diff --git a/features/joinroom/impl/src/main/res/values-cy/translations.xml b/features/joinroom/impl/src/main/res/values-cy/translations.xml
index b093d94220..480ccdbb6c 100644
--- a/features/joinroom/impl/src/main/res/values-cy/translations.xml
+++ b/features/joinroom/impl/src/main/res/values-cy/translations.xml
@@ -18,6 +18,7 @@
"Ymuno â\'r ystafell"
"Efallai y bydd angen i chi gael eich gwahodd neu fod yn aelod o ofod er mwyn ymuno."
"Anfon cais i ymuno"
+ "Nodau a ganiateir %1$d o %2$d"
"Neges (dewisol)"
"Byddwch yn derbyn gwahoddiad i ymuno â\'r ystafell os caiff eich cais ei dderbyn."
"Anfonwyd y cais i ymuno"
diff --git a/features/joinroom/impl/src/main/res/values-pt/translations.xml b/features/joinroom/impl/src/main/res/values-pt/translations.xml
index 695d3124c3..5bac83b9d2 100644
--- a/features/joinroom/impl/src/main/res/values-pt/translations.xml
+++ b/features/joinroom/impl/src/main/res/values-pt/translations.xml
@@ -20,7 +20,7 @@
"Bater à porta"
"%1$d de %2$d caracteres permitidos"
"Mensagem (opcional)"
- "Irá receber um convite para participar na sala se seu pedido for aceite."
+ "Irás receber um convite para participar na sala se o pedido for aceite."
"Pedido de adesão enviado"
"Não conseguimos exibir a pré-visualização da sala. Isso pode ser devido a problemas de rede ou servidor."
"Não foi possível exibir a pré-visualização desta sala"
diff --git a/features/joinroom/impl/src/main/res/values/localazy.xml b/features/joinroom/impl/src/main/res/values/localazy.xml
index f08807bd40..3d6a319aa6 100644
--- a/features/joinroom/impl/src/main/res/values/localazy.xml
+++ b/features/joinroom/impl/src/main/res/values/localazy.xml
@@ -15,6 +15,7 @@
"This room is either invite-only or there might be restrictions to access at space level."
"Forget this room"
"You need an invite in order to join this room"
+ "Invited by"
"Join room"
"You may need to be invited or be a member of a space in order to join."
"Send request to join"
diff --git a/features/joinroom/impl/src/test/kotlin/io/element/android/features/joinroom/impl/DefaultJoinRoomEntryPointTest.kt b/features/joinroom/impl/src/test/kotlin/io/element/android/features/joinroom/impl/DefaultJoinRoomEntryPointTest.kt
new file mode 100644
index 0000000000..af75fd528c
--- /dev/null
+++ b/features/joinroom/impl/src/test/kotlin/io/element/android/features/joinroom/impl/DefaultJoinRoomEntryPointTest.kt
@@ -0,0 +1,59 @@
+/*
+ * Copyright 2025 New Vector Ltd.
+ *
+ * SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial
+ * Please see LICENSE files in the repository root for full details.
+ */
+
+package io.element.android.features.joinroom.impl
+
+import androidx.arch.core.executor.testing.InstantTaskExecutorRule
+import com.bumble.appyx.core.modality.BuildContext
+import com.bumble.appyx.core.node.Node
+import com.bumble.appyx.testing.junit4.util.MainDispatcherRule
+import com.google.common.truth.Truth.assertThat
+import im.vector.app.features.analytics.plan.JoinedRoom
+import io.element.android.features.invite.api.InviteData
+import io.element.android.features.invite.api.declineandblock.DeclineInviteAndBlockEntryPoint
+import io.element.android.features.joinroom.api.JoinRoomEntryPoint
+import io.element.android.libraries.matrix.api.core.toRoomIdOrAlias
+import io.element.android.libraries.matrix.test.A_ROOM_ID
+import io.element.android.tests.testutils.lambda.lambdaError
+import io.element.android.tests.testutils.node.TestParentNode
+import org.junit.Rule
+import org.junit.Test
+import java.util.Optional
+
+class DefaultJoinRoomEntryPointTest {
+ @get:Rule
+ val instantTaskExecutorRule = InstantTaskExecutorRule()
+
+ @get:Rule
+ val mainDispatcherRule = MainDispatcherRule()
+
+ @Test
+ fun `test node builder`() {
+ val entryPoint = DefaultJoinRoomEntryPoint()
+ val parentNode = TestParentNode.create { buildContext, plugins ->
+ JoinRoomFlowNode(
+ buildContext = buildContext,
+ plugins = plugins,
+ presenterFactory = { _, _, _, _, _ -> createJoinRoomPresenter() },
+ acceptDeclineInviteView = { _, _, _, _ -> lambdaError() },
+ declineAndBlockEntryPoint = object : DeclineInviteAndBlockEntryPoint {
+ override fun createNode(parentNode: Node, buildContext: BuildContext, inviteData: InviteData) = lambdaError()
+ }
+ )
+ }
+ val inputs = JoinRoomEntryPoint.Inputs(
+ roomId = A_ROOM_ID,
+ roomIdOrAlias = A_ROOM_ID.toRoomIdOrAlias(),
+ roomDescription = Optional.ofNullable(null),
+ serverNames = emptyList(),
+ trigger = JoinedRoom.Trigger.RoomDirectory,
+ )
+ val result = entryPoint.createNode(parentNode, BuildContext.root(null), inputs)
+ assertThat(result).isInstanceOf(JoinRoomFlowNode::class.java)
+ assertThat(result.plugins).contains(inputs)
+ }
+}
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 cabab56802..574c310d1f 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
@@ -28,13 +28,11 @@ 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.UserId
import io.element.android.libraries.matrix.api.core.toRoomIdOrAlias
import io.element.android.libraries.matrix.api.exception.ClientException
import io.element.android.libraries.matrix.api.exception.ErrorKind
import io.element.android.libraries.matrix.api.room.CurrentUserMembership
import io.element.android.libraries.matrix.api.room.RoomMembershipDetails
-import io.element.android.libraries.matrix.api.room.RoomType
import io.element.android.libraries.matrix.api.room.join.JoinRoom
import io.element.android.libraries.matrix.api.room.join.JoinRule
import io.element.android.libraries.matrix.test.AN_EXCEPTION
@@ -50,8 +48,12 @@ import io.element.android.libraries.matrix.test.room.aRoomMember
import io.element.android.libraries.matrix.test.room.aRoomPreview
import io.element.android.libraries.matrix.test.room.aRoomPreviewInfo
import io.element.android.libraries.matrix.test.room.join.FakeJoinRoom
+import io.element.android.libraries.matrix.test.spaces.FakeSpaceRoomList
+import io.element.android.libraries.matrix.test.spaces.FakeSpaceService
+import io.element.android.libraries.matrix.ui.components.aMatrixUser
import io.element.android.libraries.matrix.ui.model.InviteSender
import io.element.android.libraries.matrix.ui.model.toInviteSender
+import io.element.android.libraries.previewutils.room.aSpaceRoom
import io.element.android.tests.testutils.WarmUpRule
import io.element.android.tests.testutils.lambda.any
import io.element.android.tests.testutils.lambda.assert
@@ -90,6 +92,9 @@ class JoinRoomPresenterTest {
val roomInfo = aRoomInfo()
val matrixClient = FakeMatrixClient(
getNotJoinedRoomResult = { _, _ -> Result.failure(AN_EXCEPTION) },
+ spaceService = FakeSpaceService(
+ spaceRoomListResult = { FakeSpaceRoomList() },
+ ),
).apply {
getRoomInfoFlowLambda = { _ ->
flowOf(Optional.of(roomInfo))
@@ -107,7 +112,7 @@ class JoinRoomPresenterTest {
assertThat(contentState.topic).isEqualTo(roomInfo.topic)
assertThat(contentState.alias).isEqualTo(roomInfo.canonicalAlias)
assertThat(contentState.numberOfMembers).isEqualTo(roomInfo.joinedMembersCount)
- assertThat(contentState.isDm).isEqualTo(roomInfo.isDirect)
+ assertThat(contentState.details).isEqualTo(aLoadedDetailsRoom(isDm = roomInfo.isDirect))
assertThat(contentState.roomAvatarUrl).isEqualTo(roomInfo.avatarUrl)
}
}
@@ -118,6 +123,9 @@ class JoinRoomPresenterTest {
val roomInfo = aRoomInfo(currentUserMembership = CurrentUserMembership.INVITED)
val matrixClient = FakeMatrixClient(
getNotJoinedRoomResult = { _, _ -> Result.failure(AN_EXCEPTION) },
+ spaceService = FakeSpaceService(
+ spaceRoomListResult = { FakeSpaceRoomList() },
+ ),
).apply {
getRoomInfoFlowLambda = { _ ->
flowOf(Optional.of(roomInfo))
@@ -142,7 +150,7 @@ class JoinRoomPresenterTest {
@Test
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 inviter = aRoomMember(userId = A_USER_ID_2, displayName = "Bob")
val expectedInviteSender = inviter.toInviteSender()
val roomInfo = aRoomInfo(
currentUserMembership = CurrentUserMembership.INVITED,
@@ -151,7 +159,21 @@ class JoinRoomPresenterTest {
)
val inviteData = roomInfo.toInviteData()
val matrixClient = FakeMatrixClient(
- getNotJoinedRoomResult = { _, _ -> Result.failure(AN_EXCEPTION) },
+ getNotJoinedRoomResult = { _, _ ->
+ Result.success(
+ aRoomPreview(
+ info = aRoomPreviewInfo(
+ numberOfJoinedMembers = 5,
+ ),
+ roomMembershipDetails = {
+ Result.success(aRoomMembershipDetails())
+ },
+ )
+ )
+ },
+ spaceService = FakeSpaceService(
+ spaceRoomListResult = { FakeSpaceRoomList() },
+ ),
).apply {
getRoomInfoFlowLambda = { _ ->
flowOf(Optional.of(roomInfo))
@@ -169,6 +191,137 @@ class JoinRoomPresenterTest {
}
}
+ @Test
+ fun `present - when space is invited then join authorization is equal to invited, an inviter is provided`() = runTest {
+ val inviter = aRoomMember(userId = A_USER_ID_2, displayName = "Bob")
+ val expectedInviteSender = inviter.toInviteSender()
+ val spaceHero = aMatrixUser()
+ val roomInfo = aRoomInfo(
+ isSpace = true,
+ currentUserMembership = CurrentUserMembership.INVITED,
+ joinedMembersCount = 5,
+ inviter = inviter,
+ heroes = listOf(spaceHero),
+ )
+ val inviteData = roomInfo.toInviteData()
+ val matrixClient = FakeMatrixClient(
+ getNotJoinedRoomResult = { _, _ ->
+ Result.success(
+ aRoomPreview(
+ info = aRoomPreviewInfo(
+ numberOfJoinedMembers = 5,
+ ),
+ roomMembershipDetails = {
+ Result.success(aRoomMembershipDetails())
+ },
+ )
+ )
+ },
+ spaceService = FakeSpaceService(
+ spaceRoomListResult = {
+ FakeSpaceRoomList(
+ initialSpaceFlowValue = aSpaceRoom(
+ childrenCount = 3,
+ )
+ )
+ },
+ ),
+ ).apply {
+ getRoomInfoFlowLambda = { _ ->
+ flowOf(Optional.of(roomInfo))
+ }
+ }
+ val presenter = createJoinRoomPresenter(
+ matrixClient = matrixClient
+ )
+ presenter.test {
+ skipItems(2)
+ awaitItem().also { state ->
+ assertThat(state.joinAuthorisationStatus).isEqualTo(JoinAuthorisationStatus.IsInvited(inviteData, expectedInviteSender))
+ assertThat((state.contentState as ContentState.Loaded).numberOfMembers).isEqualTo(5)
+ // Space details are provided
+ assertThat(state.contentState.details).isEqualTo(
+ LoadedDetails.Space(
+ childrenCount = 3,
+ heroes = persistentListOf(spaceHero),
+ )
+ )
+ }
+ }
+ }
+
+ @Test
+ fun `present - space is invited - no room info`() = runTest {
+ val spaceHero = aMatrixUser()
+ val spaceRoom = aSpaceRoom(
+ childrenCount = 3,
+ heroes = listOf(spaceHero),
+ )
+ val matrixClient = FakeMatrixClient(
+ getNotJoinedRoomResult = { _, _ ->
+ Result.failure(Exception("Error"))
+ },
+ spaceService = FakeSpaceService(
+ spaceRoomListResult = {
+ FakeSpaceRoomList(
+ initialSpaceFlowValue = spaceRoom,
+ )
+ },
+ ),
+ ).apply {
+ getRoomInfoFlowLambda = { _ ->
+ flowOf(Optional.ofNullable(null))
+ }
+ }
+ val presenter = createJoinRoomPresenter(
+ matrixClient = matrixClient
+ )
+ presenter.test {
+ skipItems(1)
+ awaitItem().also { state ->
+ // Space details are provided
+ assertThat((state.contentState as ContentState.Loaded).details).isEqualTo(
+ LoadedDetails.Space(
+ childrenCount = 3,
+ heroes = persistentListOf(spaceHero),
+ )
+ )
+ }
+ }
+ }
+
+ @Test
+ fun `present - space is invited - no room info - space room state set`() = runTest {
+ val spaceRoom = aSpaceRoom(
+ state = CurrentUserMembership.INVITED,
+ )
+ val matrixClient = FakeMatrixClient(
+ getNotJoinedRoomResult = { _, _ ->
+ Result.failure(Exception("Error"))
+ },
+ spaceService = FakeSpaceService(
+ spaceRoomListResult = {
+ FakeSpaceRoomList(
+ initialSpaceFlowValue = spaceRoom,
+ )
+ },
+ ),
+ ).apply {
+ getRoomInfoFlowLambda = { _ ->
+ flowOf(Optional.ofNullable(null))
+ }
+ }
+ val presenter = createJoinRoomPresenter(
+ matrixClient = matrixClient
+ )
+ presenter.test {
+ awaitItem().also { state ->
+ // Space details are provided
+ assertThat(state.contentState).isInstanceOf(ContentState.Loading::class.java)
+ }
+ }
+ }
+
@Test
fun `present - when room is invited read the number of member from the room preview`() = runTest {
val roomInfo = aRoomInfo(
@@ -182,10 +335,16 @@ class JoinRoomPresenterTest {
aRoomPreview(
info = aRoomPreviewInfo(
numberOfJoinedMembers = 10,
- )
+ ),
+ roomMembershipDetails = {
+ Result.success(aRoomMembershipDetails())
+ },
)
)
},
+ spaceService = FakeSpaceService(
+ spaceRoomListResult = { FakeSpaceRoomList() },
+ ),
).apply {
getRoomInfoFlowLambda = { _ ->
flowOf(Optional.of(roomInfo))
@@ -209,7 +368,11 @@ class JoinRoomPresenterTest {
anAcceptDeclineInviteState(eventSink = eventSinkRecorder)
}
val roomInfo = aRoomInfo(currentUserMembership = CurrentUserMembership.INVITED)
- val matrixClient = FakeMatrixClient().apply {
+ val matrixClient = FakeMatrixClient(
+ spaceService = FakeSpaceService(
+ spaceRoomListResult = { FakeSpaceRoomList() },
+ ),
+ ).apply {
getRoomInfoFlowLambda = { _ ->
flowOf(Optional.of(roomInfo))
}
@@ -244,6 +407,9 @@ class JoinRoomPresenterTest {
}
val matrixClient = FakeMatrixClient(
getNotJoinedRoomResult = { _, _ -> Result.failure(AN_EXCEPTION) },
+ spaceService = FakeSpaceService(
+ spaceRoomListResult = { FakeSpaceRoomList() },
+ ),
)
val presenter = createJoinRoomPresenter(
matrixClient = matrixClient,
@@ -272,6 +438,9 @@ class JoinRoomPresenterTest {
fun `present - when room is joined with error, it is possible to clear the error`() = runTest {
val matrixClient = FakeMatrixClient(
getNotJoinedRoomResult = { _, _ -> Result.failure(AN_EXCEPTION) },
+ spaceService = FakeSpaceService(
+ spaceRoomListResult = { FakeSpaceRoomList() },
+ ),
)
val presenter = createJoinRoomPresenter(
matrixClient = matrixClient,
@@ -334,16 +503,14 @@ class JoinRoomPresenterTest {
currentUserMembership = CurrentUserMembership.BANNED,
),
roomMembershipDetails = {
- Result.success(
- RoomMembershipDetails(
- currentUserMember = aRoomMember(userId = A_USER_ID, displayName = "Alice"),
- senderMember = aRoomMember(userId = A_USER_ID_2, displayName = "Bob"),
- )
- )
+ Result.success(aRoomMembershipDetails())
}
)
)
- }
+ },
+ spaceService = FakeSpaceService(
+ spaceRoomListResult = { FakeSpaceRoomList() },
+ ),
).apply {
getRoomInfoFlowLambda = { _ ->
flowOf(Optional.of(roomInfo))
@@ -371,6 +538,9 @@ class JoinRoomPresenterTest {
val roomInfo = aRoomInfo(currentUserMembership = CurrentUserMembership.LEFT, joinRule = JoinRule.Public)
val matrixClient = FakeMatrixClient(
getNotJoinedRoomResult = { _, _ -> Result.failure(AN_EXCEPTION) },
+ spaceService = FakeSpaceService(
+ spaceRoomListResult = { FakeSpaceRoomList() },
+ ),
).apply {
getRoomInfoFlowLambda = { _ ->
flowOf(Optional.of(roomInfo))
@@ -392,6 +562,9 @@ class JoinRoomPresenterTest {
val roomInfo = aRoomInfo(currentUserMembership = CurrentUserMembership.LEFT, joinRule = null)
val matrixClient = FakeMatrixClient(
getNotJoinedRoomResult = { _, _ -> Result.failure(AN_EXCEPTION) },
+ spaceService = FakeSpaceService(
+ spaceRoomListResult = { FakeSpaceRoomList() },
+ ),
).apply {
getRoomInfoFlowLambda = { _ ->
flowOf(Optional.of(roomInfo))
@@ -423,7 +596,7 @@ class JoinRoomPresenterTest {
assertThat(contentState.topic).isEqualTo(roomDescription.topic)
assertThat(contentState.alias).isEqualTo(roomDescription.alias)
assertThat(contentState.numberOfMembers).isEqualTo(roomDescription.numberOfMembers)
- assertThat(contentState.isDm).isFalse()
+ assertThat(contentState.details).isEqualTo(aLoadedDetailsRoom(isDm = false))
assertThat(contentState.roomAvatarUrl).isEqualTo(roomDescription.avatarUrl)
}
}
@@ -497,6 +670,9 @@ class JoinRoomPresenterTest {
val fakeKnockRoom = FakeKnockRoom(knockRoomSuccess)
val matrixClient = FakeMatrixClient(
getNotJoinedRoomResult = { _, _ -> Result.failure(AN_EXCEPTION) },
+ spaceService = FakeSpaceService(
+ spaceRoomListResult = { FakeSpaceRoomList() },
+ ),
)
val presenter = createJoinRoomPresenter(
matrixClient = matrixClient,
@@ -542,6 +718,9 @@ class JoinRoomPresenterTest {
val cancelKnockRoom = FakeCancelKnockRoom(cancelKnockRoomSuccess)
val matrixClient = FakeMatrixClient(
getNotJoinedRoomResult = { _, _ -> Result.failure(AN_EXCEPTION) },
+ spaceService = FakeSpaceService(
+ spaceRoomListResult = { FakeSpaceRoomList() },
+ ),
)
val presenter = createJoinRoomPresenter(
matrixClient = matrixClient,
@@ -586,6 +765,9 @@ class JoinRoomPresenterTest {
val fakeForgetRoom = FakeForgetRoom(forgetRoomSuccess)
val matrixClient = FakeMatrixClient(
getNotJoinedRoomResult = { _, _ -> Result.failure(AN_EXCEPTION) },
+ spaceService = FakeSpaceService(
+ spaceRoomListResult = { FakeSpaceRoomList() },
+ ),
)
val presenter = createJoinRoomPresenter(
matrixClient = matrixClient,
@@ -634,10 +816,16 @@ class JoinRoomPresenterTest {
isHistoryWorldReadable = false,
joinRule = JoinRule.Public,
currentUserMembership = null,
- )
+ ),
+ roomMembershipDetails = {
+ Result.success(aRoomMembershipDetails())
+ },
)
)
- }
+ },
+ spaceService = FakeSpaceService(
+ spaceRoomListResult = { FakeSpaceRoomList() },
+ ),
)
val presenter = createJoinRoomPresenter(
matrixClient = client
@@ -652,10 +840,10 @@ class JoinRoomPresenterTest {
topic = "Room topic",
alias = RoomAlias("#alias:matrix.org"),
numberOfMembers = 2,
- isDm = false,
- roomType = RoomType.Room,
roomAvatarUrl = "avatarUrl",
- joinAuthorisationStatus = JoinAuthorisationStatus.CanJoin
+ joinAuthorisationStatus = JoinAuthorisationStatus.CanJoin,
+ joinRule = JoinRule.Public,
+ details = aLoadedDetailsRoom(isDm = false),
)
)
}
@@ -681,16 +869,14 @@ class JoinRoomPresenterTest {
currentUserMembership = CurrentUserMembership.INVITED,
),
roomMembershipDetails = {
- Result.success(
- RoomMembershipDetails(
- currentUserMember = aRoomMember(userId = A_USER_ID, displayName = "Alice"),
- senderMember = aRoomMember(userId = A_USER_ID_2, displayName = "Bob"),
- )
- )
+ Result.success(aRoomMembershipDetails())
}
)
)
- }
+ },
+ spaceService = FakeSpaceService(
+ spaceRoomListResult = { FakeSpaceRoomList() },
+ ),
)
val presenter = createJoinRoomPresenter(
matrixClient = client
@@ -705,8 +891,6 @@ class JoinRoomPresenterTest {
topic = "Room topic",
alias = RoomAlias("#alias:matrix.org"),
numberOfMembers = 2,
- isDm = false,
- roomType = RoomType.Room,
roomAvatarUrl = "avatarUrl",
joinAuthorisationStatus = JoinAuthorisationStatus.IsInvited(
inviteData = InviteData(
@@ -724,7 +908,9 @@ class JoinRoomPresenterTest {
),
membershipChangeReason = null,
),
- )
+ ),
+ joinRule = JoinRule.Public,
+ details = aLoadedDetailsRoom(isDm = false),
)
)
}
@@ -751,15 +937,15 @@ class JoinRoomPresenterTest {
),
roomMembershipDetails = {
Result.success(
- RoomMembershipDetails(
- currentUserMember = aRoomMember(userId = A_USER_ID, displayName = "Alice"),
- senderMember = aRoomMember(userId = A_USER_ID_2, displayName = "Bob"),
- )
+ aRoomMembershipDetails(),
)
}
)
)
- }
+ },
+ spaceService = FakeSpaceService(
+ spaceRoomListResult = { FakeSpaceRoomList() },
+ ),
)
val presenter = createJoinRoomPresenter(
matrixClient = client
@@ -774,8 +960,6 @@ class JoinRoomPresenterTest {
topic = "Room topic",
alias = RoomAlias("#alias:matrix.org"),
numberOfMembers = 2,
- isDm = false,
- roomType = RoomType.Room,
roomAvatarUrl = "avatarUrl",
joinAuthorisationStatus = JoinAuthorisationStatus.IsBanned(
banSender = InviteSender(
@@ -789,7 +973,9 @@ class JoinRoomPresenterTest {
membershipChangeReason = null,
),
reason = null,
- )
+ ),
+ joinRule = JoinRule.Public,
+ details = aLoadedDetailsRoom(isDm = false),
)
)
}
@@ -815,16 +1001,14 @@ class JoinRoomPresenterTest {
currentUserMembership = CurrentUserMembership.KNOCKED,
),
roomMembershipDetails = {
- Result.success(
- RoomMembershipDetails(
- currentUserMember = aRoomMember(userId = A_USER_ID, displayName = "Alice"),
- senderMember = aRoomMember(userId = A_USER_ID_2, displayName = "Bob"),
- )
- )
+ Result.success(aRoomMembershipDetails())
}
)
)
- }
+ },
+ spaceService = FakeSpaceService(
+ spaceRoomListResult = { FakeSpaceRoomList() },
+ ),
)
val presenter = createJoinRoomPresenter(
matrixClient = client
@@ -839,10 +1023,10 @@ class JoinRoomPresenterTest {
topic = "Room topic",
alias = RoomAlias("#alias:matrix.org"),
numberOfMembers = 2,
- isDm = false,
- roomType = RoomType.Room,
roomAvatarUrl = "avatarUrl",
- joinAuthorisationStatus = JoinAuthorisationStatus.IsKnocked
+ joinAuthorisationStatus = JoinAuthorisationStatus.IsKnocked,
+ joinRule = JoinRule.Public,
+ details = aLoadedDetailsRoom(isDm = false),
)
)
}
@@ -854,9 +1038,17 @@ class JoinRoomPresenterTest {
val client = FakeMatrixClient(
getNotJoinedRoomResult = { _, _ ->
Result.success(
- aRoomPreview(info = aRoomPreviewInfo(joinRule = JoinRule.Private))
+ aRoomPreview(
+ info = aRoomPreviewInfo(joinRule = JoinRule.Private),
+ roomMembershipDetails = {
+ Result.success(aRoomMembershipDetails())
+ },
+ )
)
- }
+ },
+ spaceService = FakeSpaceService(
+ spaceRoomListResult = { FakeSpaceRoomList() },
+ ),
)
val presenter = createJoinRoomPresenter(
matrixClient = client
@@ -874,9 +1066,17 @@ class JoinRoomPresenterTest {
val client = FakeMatrixClient(
getNotJoinedRoomResult = { _, _ ->
Result.success(
- aRoomPreview(info = aRoomPreviewInfo(joinRule = JoinRule.Custom("custom")))
+ aRoomPreview(
+ info = aRoomPreviewInfo(joinRule = JoinRule.Custom("custom")),
+ roomMembershipDetails = {
+ Result.success(aRoomMembershipDetails())
+ },
+ )
)
- }
+ },
+ spaceService = FakeSpaceService(
+ spaceRoomListResult = { FakeSpaceRoomList() },
+ ),
)
val presenter = createJoinRoomPresenter(
matrixClient = client
@@ -894,9 +1094,17 @@ class JoinRoomPresenterTest {
val client = FakeMatrixClient(
getNotJoinedRoomResult = { _, _ ->
Result.success(
- aRoomPreview(info = aRoomPreviewInfo(joinRule = JoinRule.Invite))
+ aRoomPreview(
+ info = aRoomPreviewInfo(joinRule = JoinRule.Invite),
+ roomMembershipDetails = {
+ Result.success(aRoomMembershipDetails())
+ },
+ )
)
- }
+ },
+ spaceService = FakeSpaceService(
+ spaceRoomListResult = { FakeSpaceRoomList() },
+ ),
)
val presenter = createJoinRoomPresenter(
matrixClient = client
@@ -914,9 +1122,19 @@ class JoinRoomPresenterTest {
val client = FakeMatrixClient(
getNotJoinedRoomResult = { _, _ ->
Result.success(
- aRoomPreview(info = aRoomPreviewInfo(joinRule = JoinRule.KnockRestricted(persistentListOf())))
+ aRoomPreview(
+ info = aRoomPreviewInfo(
+ joinRule = JoinRule.KnockRestricted(persistentListOf())
+ ),
+ roomMembershipDetails = {
+ Result.success(aRoomMembershipDetails())
+ }
+ )
)
- }
+ },
+ spaceService = FakeSpaceService(
+ spaceRoomListResult = { FakeSpaceRoomList() },
+ ),
)
val presenter = createJoinRoomPresenter(
matrixClient = client
@@ -934,9 +1152,17 @@ class JoinRoomPresenterTest {
val client = FakeMatrixClient(
getNotJoinedRoomResult = { _, _ ->
Result.success(
- aRoomPreview(info = aRoomPreviewInfo(joinRule = JoinRule.Restricted(persistentListOf())))
+ aRoomPreview(
+ info = aRoomPreviewInfo(joinRule = JoinRule.Restricted(persistentListOf())),
+ roomMembershipDetails = {
+ Result.success(aRoomMembershipDetails())
+ },
+ )
)
- }
+ },
+ spaceService = FakeSpaceService(
+ spaceRoomListResult = { FakeSpaceRoomList() },
+ ),
)
val presenter = createJoinRoomPresenter(
matrixClient = client
@@ -949,32 +1175,15 @@ class JoinRoomPresenterTest {
}
}
- @Test
- fun `present - when room is not known RoomPreview is loaded as Space`() = runTest {
- val client = FakeMatrixClient(
- getNotJoinedRoomResult = { _, _ ->
- Result.success(
- aRoomPreview(info = aRoomPreviewInfo(isSpace = true))
- )
- }
- )
- val presenter = createJoinRoomPresenter(
- matrixClient = client
- )
- presenter.test {
- skipItems(1)
- awaitItem().also { state ->
- assertThat(state.joinAuthorisationStatus).isEqualTo(JoinAuthorisationStatus.IsSpace("AppName"))
- }
- }
- }
-
@Test
fun `present - when room is not known RoomPreview is loaded with error`() = runTest {
val client = FakeMatrixClient(
getNotJoinedRoomResult = { _, _ ->
Result.failure(AN_EXCEPTION)
- }
+ },
+ spaceService = FakeSpaceService(
+ spaceRoomListResult = { FakeSpaceRoomList() },
+ ),
)
val presenter = createJoinRoomPresenter(
matrixClient = client
@@ -1004,7 +1213,10 @@ class JoinRoomPresenterTest {
val client = FakeMatrixClient(
getNotJoinedRoomResult = { _, _ ->
Result.failure(AN_EXCEPTION)
- }
+ },
+ spaceService = FakeSpaceService(
+ spaceRoomListResult = { FakeSpaceRoomList() },
+ ),
)
val presenter = createJoinRoomPresenter(
matrixClient = client
@@ -1029,7 +1241,10 @@ class JoinRoomPresenterTest {
val client = FakeMatrixClient(
getNotJoinedRoomResult = { _, _ ->
Result.failure(ClientException.MatrixApi(ErrorKind.Forbidden, "403", "Forbidden", null))
- }
+ },
+ spaceService = FakeSpaceService(
+ spaceRoomListResult = { FakeSpaceRoomList() },
+ ),
)
val presenter = createJoinRoomPresenter(
matrixClient = client
@@ -1042,39 +1257,6 @@ class JoinRoomPresenterTest {
}
}
- private fun createJoinRoomPresenter(
- roomId: RoomId = A_ROOM_ID,
- roomDescription: Optional = Optional.empty(),
- serverNames: List = emptyList(),
- trigger: JoinedRoom.Trigger = JoinedRoom.Trigger.Invite,
- matrixClient: MatrixClient = FakeMatrixClient(),
- joinRoomLambda: (RoomIdOrAlias, List, JoinedRoom.Trigger) -> Result = { _, _, _ ->
- Result.success(Unit)
- },
- knockRoom: KnockRoom = FakeKnockRoom(),
- cancelKnockRoom: CancelKnockRoom = FakeCancelKnockRoom(),
- forgetRoom: ForgetRoom = FakeForgetRoom(),
- buildMeta: BuildMeta = aBuildMeta(applicationName = "AppName"),
- acceptDeclineInvitePresenter: Presenter = Presenter { anAcceptDeclineInviteState() },
- seenInvitesStore: SeenInvitesStore = InMemorySeenInvitesStore(),
- ): JoinRoomPresenter {
- return JoinRoomPresenter(
- roomId = roomId,
- roomIdOrAlias = roomId.toRoomIdOrAlias(),
- roomDescription = roomDescription,
- serverNames = serverNames,
- trigger = trigger,
- matrixClient = matrixClient,
- joinRoom = FakeJoinRoom(joinRoomLambda),
- knockRoom = knockRoom,
- cancelKnockRoom = cancelKnockRoom,
- forgetRoom = forgetRoom,
- buildMeta = buildMeta,
- acceptDeclineInvitePresenter = acceptDeclineInvitePresenter,
- seenInvitesStore = seenInvitesStore,
- )
- }
-
private fun aRoomDescription(
roomId: RoomId = A_ROOM_ID,
name: String? = A_ROOM_NAME,
@@ -1095,3 +1277,45 @@ class JoinRoomPresenterTest {
)
}
}
+
+internal fun createJoinRoomPresenter(
+ roomId: RoomId = A_ROOM_ID,
+ roomDescription: Optional = Optional.empty(),
+ serverNames: List = emptyList(),
+ trigger: JoinedRoom.Trigger = JoinedRoom.Trigger.Invite,
+ matrixClient: MatrixClient = FakeMatrixClient(
+ spaceService = FakeSpaceService(
+ spaceRoomListResult = { FakeSpaceRoomList() },
+ ),
+ ),
+ joinRoomLambda: (RoomIdOrAlias, List, JoinedRoom.Trigger) -> Result = { _, _, _ ->
+ Result.success(Unit)
+ },
+ knockRoom: KnockRoom = FakeKnockRoom(),
+ cancelKnockRoom: CancelKnockRoom = FakeCancelKnockRoom(),
+ forgetRoom: ForgetRoom = FakeForgetRoom(),
+ buildMeta: BuildMeta = aBuildMeta(applicationName = "AppName"),
+ acceptDeclineInvitePresenter: Presenter = Presenter { anAcceptDeclineInviteState() },
+ seenInvitesStore: SeenInvitesStore = InMemorySeenInvitesStore(),
+): JoinRoomPresenter {
+ return JoinRoomPresenter(
+ roomId = roomId,
+ roomIdOrAlias = roomId.toRoomIdOrAlias(),
+ roomDescription = roomDescription,
+ serverNames = serverNames,
+ trigger = trigger,
+ matrixClient = matrixClient,
+ joinRoom = FakeJoinRoom(joinRoomLambda),
+ knockRoom = knockRoom,
+ cancelKnockRoom = cancelKnockRoom,
+ forgetRoom = forgetRoom,
+ buildMeta = buildMeta,
+ acceptDeclineInvitePresenter = acceptDeclineInvitePresenter,
+ seenInvitesStore = seenInvitesStore,
+ )
+}
+
+private fun aRoomMembershipDetails() = RoomMembershipDetails(
+ currentUserMember = aRoomMember(userId = A_USER_ID, displayName = "Alice"),
+ senderMember = aRoomMember(userId = A_USER_ID_2, displayName = "Bob"),
+)
diff --git a/features/joinroom/impl/src/test/kotlin/io/element/android/features/joinroom/impl/JoinRoomViewTest.kt b/features/joinroom/impl/src/test/kotlin/io/element/android/features/joinroom/impl/JoinRoomViewTest.kt
index 0205c1cac0..f3487a43b6 100644
--- a/features/joinroom/impl/src/test/kotlin/io/element/android/features/joinroom/impl/JoinRoomViewTest.kt
+++ b/features/joinroom/impl/src/test/kotlin/io/element/android/features/joinroom/impl/JoinRoomViewTest.kt
@@ -14,7 +14,6 @@ import androidx.test.ext.junit.runners.AndroidJUnit4
import io.element.android.features.invite.api.InviteData
import io.element.android.features.invite.test.anInviteData
import io.element.android.libraries.architecture.AsyncAction
-import io.element.android.libraries.matrix.api.room.RoomType
import io.element.android.libraries.matrix.api.room.join.JoinRoom
import io.element.android.libraries.matrix.test.room.aRoomMember
import io.element.android.libraries.matrix.ui.model.toInviteSender
@@ -218,21 +217,6 @@ class JoinRoomViewTest {
eventsRecorder.assertSingle(JoinRoomEvents.RetryFetchingContent)
}
- @Test
- fun `clicking on ok when a space is displayed invokes the expected callback`() {
- val eventsRecorder = EventsRecorder(expectEvents = false)
- ensureCalledOnce {
- rule.setJoinRoomView(
- aJoinRoomState(
- contentState = aLoadedContentState(roomType = RoomType.Space),
- eventSink = eventsRecorder,
- ),
- onBackClick = it
- )
- rule.clickOn(CommonStrings.action_ok)
- }
- }
-
@Test
fun `clicking on ok when user is unauthorized the expected callback`() {
val eventsRecorder = EventsRecorder(expectEvents = false)
diff --git a/features/knockrequests/impl/build.gradle.kts b/features/knockrequests/impl/build.gradle.kts
index 7a93786b08..41fadb00da 100644
--- a/features/knockrequests/impl/build.gradle.kts
+++ b/features/knockrequests/impl/build.gradle.kts
@@ -6,6 +6,7 @@
*/
import extension.setupDependencyInjection
+import extension.testCommonDependencies
plugins {
id("io.element.android-compose-library")
@@ -33,15 +34,7 @@ dependencies {
implementation(projects.libraries.designsystem)
implementation(projects.libraries.featureflag.api)
- testImplementation(libs.test.junit)
- testImplementation(libs.coroutines.test)
- testImplementation(libs.molecule.runtime)
- testImplementation(libs.test.robolectric)
- testImplementation(libs.test.truth)
- testImplementation(libs.test.turbine)
+ testCommonDependencies(libs, true)
testImplementation(projects.libraries.matrix.test)
- testImplementation(projects.tests.testutils)
- testImplementation(libs.androidx.compose.ui.test.junit)
testImplementation(projects.libraries.featureflag.test)
- testReleaseImplementation(libs.androidx.compose.ui.test.manifest)
}
diff --git a/features/knockrequests/impl/src/test/kotlin/io/element/android/features/knockrequests/impl/list/DefaultKnockRequestsListEntryPointTest.kt b/features/knockrequests/impl/src/test/kotlin/io/element/android/features/knockrequests/impl/list/DefaultKnockRequestsListEntryPointTest.kt
new file mode 100644
index 0000000000..b6b6d766c7
--- /dev/null
+++ b/features/knockrequests/impl/src/test/kotlin/io/element/android/features/knockrequests/impl/list/DefaultKnockRequestsListEntryPointTest.kt
@@ -0,0 +1,36 @@
+/*
+ * Copyright 2025 New Vector Ltd.
+ *
+ * SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial
+ * Please see LICENSE files in the repository root for full details.
+ */
+
+package io.element.android.features.knockrequests.impl.list
+
+import androidx.arch.core.executor.testing.InstantTaskExecutorRule
+import com.bumble.appyx.core.modality.BuildContext
+import com.google.common.truth.Truth.assertThat
+import io.element.android.tests.testutils.node.TestParentNode
+import kotlinx.coroutines.test.runTest
+import org.junit.Rule
+import org.junit.Test
+
+class DefaultKnockRequestsListEntryPointTest {
+ @get:Rule
+ val instantTaskExecutorRule = InstantTaskExecutorRule()
+
+ @Test
+ fun `test node builder`() = runTest {
+ val entryPoint = DefaultKnockRequestsListEntryPoint()
+
+ val parentNode = TestParentNode.create { buildContext, plugins ->
+ KnockRequestsListNode(
+ buildContext = buildContext,
+ plugins = plugins,
+ presenter = createKnockRequestsListPresenter(),
+ )
+ }
+ val result = entryPoint.createNode(parentNode, BuildContext.root(null))
+ assertThat(result).isInstanceOf(KnockRequestsListNode::class.java)
+ }
+}
diff --git a/features/knockrequests/impl/src/test/kotlin/io/element/android/features/knockrequests/impl/list/KnockRequestsListPresenterTest.kt b/features/knockrequests/impl/src/test/kotlin/io/element/android/features/knockrequests/impl/list/KnockRequestsListPresenterTest.kt
index 2d33642a06..18269e06f3 100644
--- a/features/knockrequests/impl/src/test/kotlin/io/element/android/features/knockrequests/impl/list/KnockRequestsListPresenterTest.kt
+++ b/features/knockrequests/impl/src/test/kotlin/io/element/android/features/knockrequests/impl/list/KnockRequestsListPresenterTest.kt
@@ -286,19 +286,19 @@ class KnockRequestsListPresenterTest {
assert(acceptFailureLambda).isCalledOnce()
assert(acceptSuccessLambda).isCalledOnce()
}
-
- private fun TestScope.createKnockRequestsListPresenter(
- canAccept: Boolean = true,
- canDecline: Boolean = true,
- canBan: Boolean = true,
- knockRequestsFlow: Flow> = flowOf(emptyList())
- ): KnockRequestsListPresenter {
- val knockRequestsService = KnockRequestsService(
- knockRequestsFlow = knockRequestsFlow,
- coroutineScope = backgroundScope,
- isKnockFeatureEnabledFlow = flowOf(true),
- permissionsFlow = flowOf(KnockRequestPermissions(canAccept, canDecline, canBan)),
- )
- return KnockRequestsListPresenter(knockRequestsService = knockRequestsService)
- }
+}
+
+internal fun TestScope.createKnockRequestsListPresenter(
+ canAccept: Boolean = true,
+ canDecline: Boolean = true,
+ canBan: Boolean = true,
+ knockRequestsFlow: Flow> = flowOf(emptyList())
+): KnockRequestsListPresenter {
+ val knockRequestsService = KnockRequestsService(
+ knockRequestsFlow = knockRequestsFlow,
+ coroutineScope = backgroundScope,
+ isKnockFeatureEnabledFlow = flowOf(true),
+ permissionsFlow = flowOf(KnockRequestPermissions(canAccept, canDecline, canBan)),
+ )
+ return KnockRequestsListPresenter(knockRequestsService = knockRequestsService)
}
diff --git a/features/leaveroom/api/src/main/kotlin/io/element/android/features/leaveroom/api/LeaveRoomRenderer.kt b/features/leaveroom/api/src/main/kotlin/io/element/android/features/leaveroom/api/LeaveRoomRenderer.kt
index 8bd6fe830b..80252a83a6 100644
--- a/features/leaveroom/api/src/main/kotlin/io/element/android/features/leaveroom/api/LeaveRoomRenderer.kt
+++ b/features/leaveroom/api/src/main/kotlin/io/element/android/features/leaveroom/api/LeaveRoomRenderer.kt
@@ -11,7 +11,7 @@ import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import io.element.android.libraries.matrix.api.core.RoomId
-interface LeaveRoomRenderer {
+fun interface LeaveRoomRenderer {
@Composable
fun Render(
state: LeaveRoomState,
diff --git a/features/leaveroom/api/src/main/res/values-cy/translations.xml b/features/leaveroom/api/src/main/res/values-cy/translations.xml
index 1ce4f2f3b4..ea02d4d869 100644
--- a/features/leaveroom/api/src/main/res/values-cy/translations.xml
+++ b/features/leaveroom/api/src/main/res/values-cy/translations.xml
@@ -3,5 +3,8 @@
"Ydych chi\'n siŵr eich bod am adael y sgwrs hon? Dyw\'r sgwrs hon ddim yn gyhoeddus a fyddwch chi ddim yn gallu ailymuno heb wahoddiad."
"Ydych chi\'n siŵr eich bod am adael yr ystafell hon? Chi yw\'r unig berson yma. Os byddwch yn gadael, fydd neb yn gallu ymuno yn y dyfodol, gan gynnwys chi."
"Ydych chi\'n siŵr eich bod am adael yr ystafell hon? Dyw\'r ystafell hon ddim yn gyhoeddus a fyddwch chi ddim yn gallu ailymuno heb wahoddiad."
+ "Dewiswch Berchnogion"
+ "Chi yw unig berchennog yr ystafell hon. Mae angen i chi drosglwyddo perchnogaeth i rywun arall cyn i chi adael yr room."
+ "Trosglwyddo perchnogaeth"
"Ydych chi\'n siŵr eich bod am adael yr ystafell?"
diff --git a/features/leaveroom/impl/build.gradle.kts b/features/leaveroom/impl/build.gradle.kts
index edc663475f..81aedb2025 100644
--- a/features/leaveroom/impl/build.gradle.kts
+++ b/features/leaveroom/impl/build.gradle.kts
@@ -1,4 +1,5 @@
import extension.setupDependencyInjection
+import extension.testCommonDependencies
/*
* Copyright 2022-2024 New Vector Ltd.
@@ -26,13 +27,8 @@ dependencies {
implementation(projects.libraries.uiStrings)
implementation(projects.libraries.push.api)
- testImplementation(libs.test.junit)
- testImplementation(libs.coroutines.test)
+ testCommonDependencies(libs)
testImplementation(libs.coroutines.core)
- testImplementation(libs.molecule.runtime)
- testImplementation(libs.test.truth)
- testImplementation(libs.test.turbine)
testImplementation(projects.libraries.matrix.test)
testImplementation(projects.libraries.push.test)
- testImplementation(projects.tests.testutils)
}
diff --git a/features/licenses/api/src/main/kotlin/io/element/android/features/licenses/api/OpenSourceLicensesEntryPoint.kt b/features/licenses/api/src/main/kotlin/io/element/android/features/licenses/api/OpenSourceLicensesEntryPoint.kt
index e4beebe6ef..a2dbdde60d 100644
--- a/features/licenses/api/src/main/kotlin/io/element/android/features/licenses/api/OpenSourceLicensesEntryPoint.kt
+++ b/features/licenses/api/src/main/kotlin/io/element/android/features/licenses/api/OpenSourceLicensesEntryPoint.kt
@@ -7,9 +7,6 @@
package io.element.android.features.licenses.api
-import com.bumble.appyx.core.modality.BuildContext
-import com.bumble.appyx.core.node.Node
+import io.element.android.libraries.architecture.SimpleFeatureEntryPoint
-interface OpenSourceLicensesEntryPoint {
- fun getNode(node: Node, buildContext: BuildContext): Node
-}
+interface OpenSourceLicensesEntryPoint : SimpleFeatureEntryPoint
diff --git a/features/licenses/impl/build.gradle.kts b/features/licenses/impl/build.gradle.kts
index 1fecb66b90..59ad326b6f 100644
--- a/features/licenses/impl/build.gradle.kts
+++ b/features/licenses/impl/build.gradle.kts
@@ -1,4 +1,5 @@
import extension.setupDependencyInjection
+import extension.testCommonDependencies
/*
* Copyright 2022-2024 New Vector Ltd.
@@ -26,12 +27,8 @@ dependencies {
implementation(projects.libraries.core)
implementation(projects.libraries.uiStrings)
api(projects.features.licenses.api)
- testImplementation(libs.test.junit)
- testImplementation(libs.coroutines.test)
+
+ testCommonDependencies(libs)
testImplementation(libs.coroutines.core)
- testImplementation(libs.molecule.runtime)
- testImplementation(libs.test.truth)
- testImplementation(libs.test.turbine)
testImplementation(projects.libraries.matrix.test)
- testImplementation(projects.tests.testutils)
}
diff --git a/features/licenses/impl/src/main/kotlin/io/element/android/features/licenses/impl/DefaultOpenSourcesLicensesEntryPoint.kt b/features/licenses/impl/src/main/kotlin/io/element/android/features/licenses/impl/DefaultOpenSourcesLicensesEntryPoint.kt
index 425346a90e..8ffbc05ed3 100644
--- a/features/licenses/impl/src/main/kotlin/io/element/android/features/licenses/impl/DefaultOpenSourcesLicensesEntryPoint.kt
+++ b/features/licenses/impl/src/main/kotlin/io/element/android/features/licenses/impl/DefaultOpenSourcesLicensesEntryPoint.kt
@@ -18,7 +18,7 @@ import io.element.android.libraries.architecture.createNode
@ContributesBinding(AppScope::class)
@Inject
class DefaultOpenSourcesLicensesEntryPoint : OpenSourceLicensesEntryPoint {
- override fun getNode(node: Node, buildContext: BuildContext): Node {
- return node.createNode(buildContext)
+ override fun createNode(parentNode: Node, buildContext: BuildContext): Node {
+ return parentNode.createNode(buildContext)
}
}
diff --git a/features/licenses/impl/src/test/kotlin/io/element/android/features/licenses/impl/DefaultOpenSourcesLicensesEntryPointTest.kt b/features/licenses/impl/src/test/kotlin/io/element/android/features/licenses/impl/DefaultOpenSourcesLicensesEntryPointTest.kt
new file mode 100644
index 0000000000..3209e28fe6
--- /dev/null
+++ b/features/licenses/impl/src/test/kotlin/io/element/android/features/licenses/impl/DefaultOpenSourcesLicensesEntryPointTest.kt
@@ -0,0 +1,37 @@
+/*
+ * Copyright 2025 New Vector Ltd.
+ *
+ * SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial
+ * Please see LICENSE files in the repository root for full details.
+ */
+
+package io.element.android.features.licenses.impl
+
+import androidx.arch.core.executor.testing.InstantTaskExecutorRule
+import com.bumble.appyx.core.modality.BuildContext
+import com.bumble.appyx.testing.junit4.util.MainDispatcherRule
+import com.google.common.truth.Truth.assertThat
+import io.element.android.tests.testutils.node.TestParentNode
+import org.junit.Rule
+import org.junit.Test
+
+class DefaultOpenSourcesLicensesEntryPointTest {
+ @get:Rule
+ val instantTaskExecutorRule = InstantTaskExecutorRule()
+
+ @get:Rule
+ val mainDispatcherRule = MainDispatcherRule()
+
+ @Test
+ fun `test node builder`() {
+ val entryPoint = DefaultOpenSourcesLicensesEntryPoint()
+ val parentNode = TestParentNode.create { buildContext, plugins ->
+ DependenciesFlowNode(
+ buildContext = buildContext,
+ plugins = plugins,
+ )
+ }
+ val result = entryPoint.createNode(parentNode, BuildContext.root(null))
+ assertThat(result).isInstanceOf(DependenciesFlowNode::class.java)
+ }
+}
diff --git a/features/location/api/build.gradle.kts b/features/location/api/build.gradle.kts
index 4ce33a748a..e4d5c4e886 100644
--- a/features/location/api/build.gradle.kts
+++ b/features/location/api/build.gradle.kts
@@ -8,6 +8,7 @@
import config.BuildTimeConfig
import extension.buildConfigFieldStr
import extension.readLocalProperty
+import extension.testCommonDependencies
plugins {
id("io.element.android-compose-library")
@@ -70,6 +71,5 @@ dependencies {
implementation(projects.libraries.uiStrings)
implementation(libs.coil.compose)
- testImplementation(libs.test.junit)
- testImplementation(libs.test.truth)
+ testCommonDependencies(libs)
}
diff --git a/features/location/impl/build.gradle.kts b/features/location/impl/build.gradle.kts
index 577132baca..43f6bba0d0 100644
--- a/features/location/impl/build.gradle.kts
+++ b/features/location/impl/build.gradle.kts
@@ -1,4 +1,5 @@
import extension.setupDependencyInjection
+import extension.testCommonDependencies
/*
* Copyright 2022-2024 New Vector Ltd.
@@ -37,17 +38,10 @@ dependencies {
implementation(projects.services.analytics.api)
implementation(libs.accompanist.permission)
implementation(projects.libraries.uiStrings)
- testImplementation(libs.test.junit)
- testImplementation(libs.coroutines.test)
- testImplementation(libs.molecule.runtime)
- testImplementation(libs.test.robolectric)
- testImplementation(libs.test.truth)
- testImplementation(libs.test.turbine)
+
+ testCommonDependencies(libs, true)
testImplementation(projects.libraries.matrix.test)
testImplementation(projects.libraries.testtags)
testImplementation(projects.services.analytics.test)
testImplementation(projects.features.messages.test)
- testImplementation(projects.tests.testutils)
- testImplementation(libs.androidx.compose.ui.test.junit)
- testReleaseImplementation(libs.androidx.compose.ui.test.manifest)
}
diff --git a/features/location/impl/src/main/kotlin/io/element/android/features/location/impl/common/permissions/PermissionsPresenter.kt b/features/location/impl/src/main/kotlin/io/element/android/features/location/impl/common/permissions/PermissionsPresenter.kt
index 410214ec88..82e54ba977 100644
--- a/features/location/impl/src/main/kotlin/io/element/android/features/location/impl/common/permissions/PermissionsPresenter.kt
+++ b/features/location/impl/src/main/kotlin/io/element/android/features/location/impl/common/permissions/PermissionsPresenter.kt
@@ -10,7 +10,7 @@ package io.element.android.features.location.impl.common.permissions
import io.element.android.libraries.architecture.Presenter
interface PermissionsPresenter : Presenter {
- interface Factory {
+ fun interface Factory {
fun create(permissions: List): PermissionsPresenter
}
}
diff --git a/features/location/impl/src/main/kotlin/io/element/android/features/location/impl/send/SendLocationPresenter.kt b/features/location/impl/src/main/kotlin/io/element/android/features/location/impl/send/SendLocationPresenter.kt
index 15f858ecff..f8d78b96e2 100644
--- a/features/location/impl/src/main/kotlin/io/element/android/features/location/impl/send/SendLocationPresenter.kt
+++ b/features/location/impl/src/main/kotlin/io/element/android/features/location/impl/send/SendLocationPresenter.kt
@@ -47,7 +47,7 @@ class SendLocationPresenter(
private val buildMeta: BuildMeta,
) : Presenter {
@AssistedFactory
- interface Factory {
+ fun interface Factory {
fun create(timelineMode: Timeline.Mode): SendLocationPresenter
}
diff --git a/features/location/impl/src/main/kotlin/io/element/android/features/location/impl/show/ShowLocationNode.kt b/features/location/impl/src/main/kotlin/io/element/android/features/location/impl/show/ShowLocationNode.kt
index 053f1864de..c0a6c5b6ad 100644
--- a/features/location/impl/src/main/kotlin/io/element/android/features/location/impl/show/ShowLocationNode.kt
+++ b/features/location/impl/src/main/kotlin/io/element/android/features/location/impl/show/ShowLocationNode.kt
@@ -25,10 +25,10 @@ import io.element.android.services.analytics.api.AnalyticsService
@ContributesNode(RoomScope::class)
@Inject
class ShowLocationNode(
- presenterFactory: ShowLocationPresenter.Factory,
- analyticsService: AnalyticsService,
@Assisted buildContext: BuildContext,
@Assisted plugins: List,
+ presenterFactory: ShowLocationPresenter.Factory,
+ analyticsService: AnalyticsService,
) : Node(buildContext, plugins = plugins) {
init {
lifecycle.subscribe(
diff --git a/features/location/impl/src/main/kotlin/io/element/android/features/location/impl/show/ShowLocationPresenter.kt b/features/location/impl/src/main/kotlin/io/element/android/features/location/impl/show/ShowLocationPresenter.kt
index af89331c6f..b304505367 100644
--- a/features/location/impl/src/main/kotlin/io/element/android/features/location/impl/show/ShowLocationPresenter.kt
+++ b/features/location/impl/src/main/kotlin/io/element/android/features/location/impl/show/ShowLocationPresenter.kt
@@ -28,14 +28,14 @@ import io.element.android.libraries.core.meta.BuildMeta
@Inject
class ShowLocationPresenter(
+ @Assisted private val location: Location,
+ @Assisted private val description: String?,
permissionsPresenterFactory: PermissionsPresenter.Factory,
private val locationActions: LocationActions,
private val buildMeta: BuildMeta,
- @Assisted private val location: Location,
- @Assisted private val description: String?
) : Presenter {
@AssistedFactory
- interface Factory {
+ fun interface Factory {
fun create(location: Location, description: String?): ShowLocationPresenter
}
diff --git a/features/location/impl/src/test/kotlin/io/element/android/features/location/impl/send/DefaultSendLocationEntryPointTest.kt b/features/location/impl/src/test/kotlin/io/element/android/features/location/impl/send/DefaultSendLocationEntryPointTest.kt
new file mode 100644
index 0000000000..9be79c7092
--- /dev/null
+++ b/features/location/impl/src/test/kotlin/io/element/android/features/location/impl/send/DefaultSendLocationEntryPointTest.kt
@@ -0,0 +1,55 @@
+/*
+ * Copyright 2025 New Vector Ltd.
+ *
+ * SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial
+ * Please see LICENSE files in the repository root for full details.
+ */
+
+package io.element.android.features.location.impl.send
+
+import androidx.arch.core.executor.testing.InstantTaskExecutorRule
+import com.bumble.appyx.core.modality.BuildContext
+import com.google.common.truth.Truth.assertThat
+import io.element.android.features.location.impl.common.actions.FakeLocationActions
+import io.element.android.features.location.impl.common.permissions.FakePermissionsPresenter
+import io.element.android.features.messages.test.FakeMessageComposerContext
+import io.element.android.libraries.matrix.api.timeline.Timeline
+import io.element.android.libraries.matrix.test.core.aBuildMeta
+import io.element.android.libraries.matrix.test.room.FakeJoinedRoom
+import io.element.android.services.analytics.test.FakeAnalyticsService
+import io.element.android.tests.testutils.node.TestParentNode
+import org.junit.Rule
+import org.junit.Test
+
+class DefaultSendLocationEntryPointTest {
+ @get:Rule
+ val instantTaskExecutorRule = InstantTaskExecutorRule()
+
+ @Test
+ fun `test node builder`() {
+ val entryPoint = DefaultSendLocationEntryPoint()
+ val parentNode = TestParentNode.create { buildContext, plugins ->
+ SendLocationNode(
+ buildContext = buildContext,
+ plugins = plugins,
+ presenterFactory = { timelineMode: Timeline.Mode ->
+ SendLocationPresenter(
+ permissionsPresenterFactory = { FakePermissionsPresenter() },
+ room = FakeJoinedRoom(),
+ timelineMode = timelineMode,
+ analyticsService = FakeAnalyticsService(),
+ messageComposerContext = FakeMessageComposerContext(),
+ locationActions = FakeLocationActions(),
+ buildMeta = aBuildMeta(),
+ )
+ },
+ analyticsService = FakeAnalyticsService(),
+ )
+ }
+ val timelineMode = Timeline.Mode.Live
+ val result = entryPoint.builder(timelineMode)
+ .build(parentNode, BuildContext.root(null))
+ assertThat(result).isInstanceOf(SendLocationNode::class.java)
+ assertThat(result.plugins).contains(SendLocationNode.Inputs(timelineMode))
+ }
+}
diff --git a/features/location/impl/src/test/kotlin/io/element/android/features/location/impl/show/DefaultShowLocationEntryPointTest.kt b/features/location/impl/src/test/kotlin/io/element/android/features/location/impl/show/DefaultShowLocationEntryPointTest.kt
new file mode 100644
index 0000000000..d31ef0c0e4
--- /dev/null
+++ b/features/location/impl/src/test/kotlin/io/element/android/features/location/impl/show/DefaultShowLocationEntryPointTest.kt
@@ -0,0 +1,58 @@
+/*
+ * Copyright 2025 New Vector Ltd.
+ *
+ * SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial
+ * Please see LICENSE files in the repository root for full details.
+ */
+
+package io.element.android.features.location.impl.show
+
+import androidx.arch.core.executor.testing.InstantTaskExecutorRule
+import com.bumble.appyx.core.modality.BuildContext
+import com.google.common.truth.Truth.assertThat
+import io.element.android.features.location.api.Location
+import io.element.android.features.location.api.ShowLocationEntryPoint
+import io.element.android.features.location.impl.common.actions.FakeLocationActions
+import io.element.android.features.location.impl.common.permissions.FakePermissionsPresenter
+import io.element.android.libraries.matrix.test.core.aBuildMeta
+import io.element.android.services.analytics.test.FakeAnalyticsService
+import io.element.android.tests.testutils.node.TestParentNode
+import org.junit.Rule
+import org.junit.Test
+
+class DefaultShowLocationEntryPointTest {
+ @get:Rule
+ val instantTaskExecutorRule = InstantTaskExecutorRule()
+
+ @Test
+ fun `test node builder`() {
+ val entryPoint = DefaultShowLocationEntryPoint()
+ val parentNode = TestParentNode.create { buildContext, plugins ->
+ ShowLocationNode(
+ buildContext = buildContext,
+ plugins = plugins,
+ presenterFactory = { location: Location, description: String? ->
+ ShowLocationPresenter(
+ permissionsPresenterFactory = { FakePermissionsPresenter() },
+ locationActions = FakeLocationActions(),
+ buildMeta = aBuildMeta(),
+ location = location,
+ description = description,
+ )
+ },
+ analyticsService = FakeAnalyticsService(),
+ )
+ }
+ val inputs = ShowLocationEntryPoint.Inputs(
+ location = Location(37.4219983, -122.084, 10f),
+ description = "My location",
+ )
+ val result = entryPoint.createNode(
+ parentNode,
+ BuildContext.root(null),
+ inputs = inputs,
+ )
+ assertThat(result).isInstanceOf(ShowLocationNode::class.java)
+ assertThat(result.plugins).contains(inputs)
+ }
+}
diff --git a/features/location/impl/src/test/kotlin/io/element/android/features/location/impl/show/ShowLocationPresenterTest.kt b/features/location/impl/src/test/kotlin/io/element/android/features/location/impl/show/ShowLocationPresenterTest.kt
index 937d1d475e..cc53badbb2 100644
--- a/features/location/impl/src/test/kotlin/io/element/android/features/location/impl/show/ShowLocationPresenterTest.kt
+++ b/features/location/impl/src/test/kotlin/io/element/android/features/location/impl/show/ShowLocationPresenterTest.kt
@@ -37,10 +37,10 @@ class ShowLocationPresenterTest {
permissionsPresenterFactory = object : PermissionsPresenter.Factory {
override fun create(permissions: List): PermissionsPresenter = fakePermissionsPresenter
},
- fakeLocationActions,
- fakeBuildMeta,
- location,
- A_DESCRIPTION,
+ locationActions = fakeLocationActions,
+ buildMeta = fakeBuildMeta,
+ location = location,
+ description = A_DESCRIPTION,
)
@Test
diff --git a/features/location/test/src/main/kotlin/io/element/android/features/location/test/FakeLocationService.kt b/features/location/test/src/main/kotlin/io/element/android/features/location/test/FakeLocationService.kt
index 8ba29a65aa..69a3331ffb 100644
--- a/features/location/test/src/main/kotlin/io/element/android/features/location/test/FakeLocationService.kt
+++ b/features/location/test/src/main/kotlin/io/element/android/features/location/test/FakeLocationService.kt
@@ -10,7 +10,7 @@ package io.element.android.features.location.test
import io.element.android.features.location.api.LocationService
class FakeLocationService(
- private val isServiceAvailable: Boolean,
+ private val isServiceAvailable: Boolean = false,
) : LocationService {
override fun isServiceAvailable() = isServiceAvailable
}
diff --git a/features/lockscreen/impl/build.gradle.kts b/features/lockscreen/impl/build.gradle.kts
index ff5f629e86..011d4919e7 100644
--- a/features/lockscreen/impl/build.gradle.kts
+++ b/features/lockscreen/impl/build.gradle.kts
@@ -1,4 +1,5 @@
import extension.setupDependencyInjection
+import extension.testCommonDependencies
/*
* Copyright 2023, 2024 New Vector Ltd.
@@ -44,21 +45,12 @@ dependencies {
implementation(libs.androidx.datastore.preferences)
implementation(libs.androidx.biometric)
- testImplementation(libs.test.junit)
- testImplementation(libs.coroutines.test)
- testImplementation(libs.molecule.runtime)
- testImplementation(libs.test.truth)
- testImplementation(libs.test.turbine)
- testImplementation(libs.test.robolectric)
- testImplementation(libs.androidx.compose.ui.test.junit)
- testImplementation(libs.androidx.test.ext.junit)
+ testCommonDependencies(libs, true)
testImplementation(projects.libraries.matrix.test)
- testImplementation(projects.tests.testutils)
testImplementation(projects.libraries.cryptography.test)
testImplementation(projects.libraries.cryptography.impl)
testImplementation(projects.libraries.featureflag.test)
testImplementation(projects.libraries.sessionStorage.test)
testImplementation(projects.services.appnavstate.test)
testImplementation(projects.features.logout.test)
- testReleaseImplementation(libs.androidx.compose.ui.test.manifest)
}
diff --git a/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/unlock/PinUnlockPresenter.kt b/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/unlock/PinUnlockPresenter.kt
index cf0f864f66..fc2e61d404 100644
--- a/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/unlock/PinUnlockPresenter.kt
+++ b/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/unlock/PinUnlockPresenter.kt
@@ -174,7 +174,7 @@ class PinUnlockPresenter(
private fun CoroutineScope.signOut(signOutAction: MutableState>) = launch {
suspend {
- logoutUseCase.logout(ignoreSdkError = true)
+ logoutUseCase.logoutAll(ignoreSdkError = true)
}.runCatchingUpdatingState(signOutAction)
}
}
diff --git a/features/lockscreen/impl/src/main/res/values-fi/translations.xml b/features/lockscreen/impl/src/main/res/values-fi/translations.xml
index ae2abef6e8..02df7528e5 100644
--- a/features/lockscreen/impl/src/main/res/values-fi/translations.xml
+++ b/features/lockscreen/impl/src/main/res/values-fi/translations.xml
@@ -9,7 +9,7 @@
"Salli biometrinen tunnistus"
"Poista PIN-koodi"
"Haluatko varmasti poistaa PIN-koodin?"
- "Poista PIN-koodi?"
+ "Poistetaanko PIN-koodi?"
"Salli %1$s"
"Käytän mieluummin PIN-koodia"
"Säästä aikaa ja ota käyttöön %1$s"
diff --git a/features/lockscreen/impl/src/test/kotlin/io/element/android/features/lockscreen/impl/DefaultLockScreenEntryPointIntentTest.kt b/features/lockscreen/impl/src/test/kotlin/io/element/android/features/lockscreen/impl/DefaultLockScreenEntryPointIntentTest.kt
new file mode 100644
index 0000000000..995140b87b
--- /dev/null
+++ b/features/lockscreen/impl/src/test/kotlin/io/element/android/features/lockscreen/impl/DefaultLockScreenEntryPointIntentTest.kt
@@ -0,0 +1,25 @@
+/*
+ * Copyright 2025 New Vector Ltd.
+ *
+ * SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial
+ * Please see LICENSE files in the repository root for full details.
+ */
+
+package io.element.android.features.lockscreen.impl
+
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.platform.app.InstrumentationRegistry
+import com.google.common.truth.Truth.assertThat
+import io.element.android.features.lockscreen.impl.unlock.activity.PinUnlockActivity
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@RunWith(AndroidJUnit4::class)
+class DefaultLockScreenEntryPointIntentTest {
+ @Test
+ fun `test pin unlock intent`() {
+ val entryPoint = DefaultLockScreenEntryPoint()
+ val result = entryPoint.pinUnlockIntent(InstrumentationRegistry.getInstrumentation().context)
+ assertThat(result.component?.className).isEqualTo(PinUnlockActivity::class.qualifiedName)
+ }
+}
diff --git a/features/lockscreen/impl/src/test/kotlin/io/element/android/features/lockscreen/impl/DefaultLockScreenEntryPointTest.kt b/features/lockscreen/impl/src/test/kotlin/io/element/android/features/lockscreen/impl/DefaultLockScreenEntryPointTest.kt
new file mode 100644
index 0000000000..822d275063
--- /dev/null
+++ b/features/lockscreen/impl/src/test/kotlin/io/element/android/features/lockscreen/impl/DefaultLockScreenEntryPointTest.kt
@@ -0,0 +1,68 @@
+/*
+ * Copyright 2025 New Vector Ltd.
+ *
+ * SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial
+ * Please see LICENSE files in the repository root for full details.
+ */
+
+package io.element.android.features.lockscreen.impl
+
+import androidx.arch.core.executor.testing.InstantTaskExecutorRule
+import com.bumble.appyx.core.modality.BuildContext
+import com.bumble.appyx.testing.junit4.util.MainDispatcherRule
+import com.google.common.truth.Truth.assertThat
+import io.element.android.features.lockscreen.api.LockScreenEntryPoint
+import io.element.android.tests.testutils.lambda.lambdaError
+import io.element.android.tests.testutils.node.TestParentNode
+import org.junit.Rule
+import org.junit.Test
+
+class DefaultLockScreenEntryPointTest {
+ @get:Rule
+ val instantTaskExecutorRule = InstantTaskExecutorRule()
+
+ @get:Rule
+ val mainDispatcherRule = MainDispatcherRule()
+
+ @Test
+ fun `test node builder Setup`() {
+ val entryPoint = DefaultLockScreenEntryPoint()
+ val parentNode = TestParentNode.create { buildContext, plugins ->
+ LockScreenFlowNode(
+ buildContext = buildContext,
+ plugins = plugins,
+ )
+ }
+ val callback = object : LockScreenEntryPoint.Callback {
+ override fun onSetupDone() = lambdaError()
+ }
+ val navTarget = LockScreenEntryPoint.Target.Setup
+ val result = entryPoint.nodeBuilder(parentNode, BuildContext.root(null), navTarget)
+ .callback(callback)
+ .build()
+ assertThat(result).isInstanceOf(LockScreenFlowNode::class.java)
+ assertThat(result.plugins).contains(LockScreenFlowNode.Inputs(LockScreenFlowNode.NavTarget.Setup))
+ assertThat(result.plugins).contains(callback)
+ }
+
+ @Test
+ fun `test node builder Settings`() {
+ val entryPoint = DefaultLockScreenEntryPoint()
+ val parentNode = TestParentNode.create { buildContext, plugins ->
+ LockScreenFlowNode(
+ buildContext = buildContext,
+ plugins = plugins,
+ )
+ }
+ val callback = object : LockScreenEntryPoint.Callback {
+ override fun onSetupDone() = lambdaError()
+ }
+ val navTarget = LockScreenEntryPoint.Target.Settings
+ val result = entryPoint.nodeBuilder(parentNode, BuildContext.root(null), navTarget)
+ .callback(callback)
+ .build()
+ assertThat(result).isInstanceOf(LockScreenFlowNode::class.java)
+ assertThat(result.plugins).contains(LockScreenFlowNode.Inputs(LockScreenFlowNode.NavTarget.Settings))
+ assertThat(result.plugins).contains(callback)
+ }
+}
diff --git a/features/login/impl/build.gradle.kts b/features/login/impl/build.gradle.kts
index 3873ea70d7..314907c04a 100644
--- a/features/login/impl/build.gradle.kts
+++ b/features/login/impl/build.gradle.kts
@@ -1,4 +1,5 @@
import extension.setupDependencyInjection
+import extension.testCommonDependencies
/*
* Copyright 2022-2024 New Vector Ltd.
@@ -48,14 +49,7 @@ dependencies {
implementation(libs.serialization.json)
api(projects.features.login.api)
- testImplementation(libs.test.junit)
- testImplementation(libs.androidx.compose.ui.test.junit)
- testImplementation(libs.androidx.test.ext.junit)
- testImplementation(libs.coroutines.test)
- testImplementation(libs.molecule.runtime)
- testImplementation(libs.test.robolectric)
- testImplementation(libs.test.truth)
- testImplementation(libs.test.turbine)
+ testCommonDependencies(libs, true)
testImplementation(projects.features.login.test)
testImplementation(projects.features.enterprise.test)
testImplementation(projects.libraries.featureflag.test)
@@ -63,6 +57,4 @@ dependencies {
testImplementation(projects.libraries.oidc.test)
testImplementation(projects.libraries.permissions.test)
testImplementation(projects.libraries.wellknown.test)
- testImplementation(projects.tests.testutils)
- testReleaseImplementation(libs.androidx.compose.ui.test.manifest)
}
diff --git a/features/login/impl/src/main/res/values-cy/translations.xml b/features/login/impl/src/main/res/values-cy/translations.xml
index a9e4b61541..b8988a9889 100644
--- a/features/login/impl/src/main/res/values-cy/translations.xml
+++ b/features/login/impl/src/main/res/values-cy/translations.xml
@@ -13,6 +13,9 @@
"Arall"
"Defnyddiwch ddarparwr cyfrif gwahanol, fel eich gweinydd preifat eich hun neu gyfrif gwaith."
"Newid darparwr cyfrif"
+ "Google Play"
+ "Mae angen yr ap Element Pro ar %1$s. Llwythwch ef o\'r siop."
+ "Mae angen Element Pro"
"Doedd dim modd i ni gyrraedd y gweinydd cartref hwn. Gwiriwch eich bod wedi rhoi URL y gweinydd cartref yn gywir. Os yw\'r URL yn gywir, cysylltwch â gweinyddwr eich gweinydd cartref am ragor o help."
"Dyw cydweddu llithrig ddim ar gael oherwydd problem yn y ffeil .well-known:
%1$s"
diff --git a/features/login/impl/src/main/res/values-eo/translations.xml b/features/login/impl/src/main/res/values-eo/translations.xml
new file mode 100644
index 0000000000..47e9b3830a
--- /dev/null
+++ b/features/login/impl/src/main/res/values-eo/translations.xml
@@ -0,0 +1,4 @@
+
+
+ "A secure connection could not be made to the new device. Your existing connected devices are still safe and you don\'t need to worry about them."
+
diff --git a/features/login/impl/src/main/res/values-nb/translations.xml b/features/login/impl/src/main/res/values-nb/translations.xml
index e5c4343f1b..10f554ab91 100644
--- a/features/login/impl/src/main/res/values-nb/translations.xml
+++ b/features/login/impl/src/main/res/values-nb/translations.xml
@@ -13,6 +13,7 @@
"Annet"
"Bruk en annen kontotilbyder, for eksempel din egen private server eller en arbeidskonto."
"Bytt kontotilbyder"
+ "Google Play"
"Element Pro-appen er nødvendig på %1$s. Last den ned fra butikken."
"Element Pro kreves"
"Vi kunne ikke nå denne hjemmeserveren. Kontroller at du har skrevet inn hjemmeserverens URL riktig. Hvis URL-en er riktig, kontakt administratoren for hjemmeserveren din for å få mer hjelp."
diff --git a/features/login/impl/src/main/res/values-pt/translations.xml b/features/login/impl/src/main/res/values-pt/translations.xml
index 08bacffa92..a2a7bdc688 100644
--- a/features/login/impl/src/main/res/values-pt/translations.xml
+++ b/features/login/impl/src/main/res/values-pt/translations.xml
@@ -74,7 +74,7 @@ Tenta iniciar a sessão manualmente ou digitaliza o código QR com outro disposi
"Seleciona %1$s"
"“Ligar novo dispositivo”"
"Lê o código QR com este dispositivo"
- "Disponível apenas se o seu fornecedor de conta o suportar."
+ "Disponível apenas se o teu operador de conta o permitir."
"Abre a %1$s noutro dispositivo para obteres o código QR"
"Lê o código QR apresentado no outro dispositivo."
"Tentar novamente"
diff --git a/features/login/impl/src/test/kotlin/io/element/android/features/login/impl/DefaultLoginEntryPointTest.kt b/features/login/impl/src/test/kotlin/io/element/android/features/login/impl/DefaultLoginEntryPointTest.kt
new file mode 100644
index 0000000000..c10d22c51a
--- /dev/null
+++ b/features/login/impl/src/test/kotlin/io/element/android/features/login/impl/DefaultLoginEntryPointTest.kt
@@ -0,0 +1,56 @@
+/*
+ * Copyright 2025 New Vector Ltd.
+ *
+ * SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial
+ * Please see LICENSE files in the repository root for full details.
+ */
+
+package io.element.android.features.login.impl
+
+import androidx.arch.core.executor.testing.InstantTaskExecutorRule
+import com.bumble.appyx.core.modality.BuildContext
+import com.bumble.appyx.testing.junit4.util.MainDispatcherRule
+import com.google.common.truth.Truth.assertThat
+import io.element.android.features.enterprise.test.FakeEnterpriseService
+import io.element.android.features.login.api.LoginEntryPoint
+import io.element.android.features.login.impl.accountprovider.AccountProviderDataSource
+import io.element.android.libraries.oidc.test.customtab.FakeOidcActionFlow
+import io.element.android.tests.testutils.lambda.lambdaError
+import io.element.android.tests.testutils.node.TestParentNode
+import org.junit.Rule
+import org.junit.Test
+
+class DefaultLoginEntryPointTest {
+ @get:Rule
+ val instantTaskExecutorRule = InstantTaskExecutorRule()
+
+ @get:Rule
+ val mainDispatcherRule = MainDispatcherRule()
+
+ @Test
+ fun `test node builder`() {
+ val entryPoint = DefaultLoginEntryPoint()
+ val parentNode = TestParentNode.create { buildContext, plugins ->
+ LoginFlowNode(
+ buildContext = buildContext,
+ plugins = plugins,
+ accountProviderDataSource = AccountProviderDataSource(FakeEnterpriseService()),
+ oidcActionFlow = FakeOidcActionFlow(),
+ )
+ }
+ val callback = object : LoginEntryPoint.Callback {
+ override fun onReportProblem() = lambdaError()
+ }
+ val params = LoginEntryPoint.Params(
+ accountProvider = "ac",
+ loginHint = "lh",
+ )
+ val result = entryPoint.nodeBuilder(parentNode, BuildContext.root(null))
+ .params(params)
+ .callback(callback)
+ .build()
+ assertThat(result).isInstanceOf(LoginFlowNode::class.java)
+ assertThat(result.plugins).contains(LoginFlowNode.Params(params.accountProvider, params.loginHint))
+ assertThat(result.plugins).contains(callback)
+ }
+}
diff --git a/features/logout/api/src/main/kotlin/io/element/android/features/logout/api/LogoutUseCase.kt b/features/logout/api/src/main/kotlin/io/element/android/features/logout/api/LogoutUseCase.kt
index 6f265ec88c..3d980fe44b 100644
--- a/features/logout/api/src/main/kotlin/io/element/android/features/logout/api/LogoutUseCase.kt
+++ b/features/logout/api/src/main/kotlin/io/element/android/features/logout/api/LogoutUseCase.kt
@@ -8,16 +8,12 @@
package io.element.android.features.logout.api
/**
- * Used to trigger a log out of the current user from any part of the app.
+ * Used to trigger a log out of the current user(s) from any part of the app.
*/
interface LogoutUseCase {
/**
- * Log out the current user and then perform any needed cleanup tasks.
+ * Log out the current user(s) and then perform any needed cleanup tasks.
* @param ignoreSdkError if true, the SDK error will be ignored and the user will be logged out anyway.
*/
- suspend fun logout(ignoreSdkError: Boolean)
-
- interface Factory {
- fun create(sessionId: String): LogoutUseCase
- }
+ suspend fun logoutAll(ignoreSdkError: Boolean)
}
diff --git a/features/logout/api/src/main/kotlin/io/element/android/features/logout/api/direct/DirectLogoutView.kt b/features/logout/api/src/main/kotlin/io/element/android/features/logout/api/direct/DirectLogoutView.kt
index 4d6b6df3d2..08a7047c1c 100644
--- a/features/logout/api/src/main/kotlin/io/element/android/features/logout/api/direct/DirectLogoutView.kt
+++ b/features/logout/api/src/main/kotlin/io/element/android/features/logout/api/direct/DirectLogoutView.kt
@@ -9,7 +9,7 @@ package io.element.android.features.logout.api.direct
import androidx.compose.runtime.Composable
-interface DirectLogoutView {
+fun interface DirectLogoutView {
@Composable
fun Render(state: DirectLogoutState)
}
diff --git a/features/logout/impl/build.gradle.kts b/features/logout/impl/build.gradle.kts
index 09fdc1bd96..215c273913 100644
--- a/features/logout/impl/build.gradle.kts
+++ b/features/logout/impl/build.gradle.kts
@@ -1,4 +1,5 @@
import extension.setupDependencyInjection
+import extension.testCommonDependencies
/*
* Copyright 2022-2024 New Vector Ltd.
@@ -35,15 +36,8 @@ dependencies {
implementation(projects.libraries.dateformatter.api)
api(projects.features.logout.api)
- testImplementation(libs.test.junit)
- testImplementation(libs.coroutines.test)
- testImplementation(libs.molecule.runtime)
- testImplementation(libs.test.truth)
- testImplementation(libs.test.turbine)
- testImplementation(libs.test.robolectric)
- testImplementation(libs.androidx.compose.ui.test.junit)
- testReleaseImplementation(libs.androidx.compose.ui.test.manifest)
+ testCommonDependencies(libs, true)
testImplementation(projects.libraries.matrix.test)
testImplementation(projects.libraries.featureflag.test)
- testImplementation(projects.tests.testutils)
+ testImplementation(projects.libraries.sessionStorage.test)
}
diff --git a/features/logout/impl/src/main/kotlin/io/element/android/features/logout/impl/DefaultLogoutUseCase.kt b/features/logout/impl/src/main/kotlin/io/element/android/features/logout/impl/DefaultLogoutUseCase.kt
index 06a79a8d2d..52e295ba3e 100644
--- a/features/logout/impl/src/main/kotlin/io/element/android/features/logout/impl/DefaultLogoutUseCase.kt
+++ b/features/logout/impl/src/main/kotlin/io/element/android/features/logout/impl/DefaultLogoutUseCase.kt
@@ -12,22 +12,31 @@ import dev.zacsweers.metro.ContributesBinding
import dev.zacsweers.metro.Inject
import io.element.android.features.logout.api.LogoutUseCase
import io.element.android.libraries.matrix.api.MatrixClientProvider
-import io.element.android.libraries.matrix.api.auth.MatrixAuthenticationService
+import io.element.android.libraries.matrix.api.core.SessionId
+import io.element.android.libraries.sessionstorage.api.SessionStore
+import timber.log.Timber
@ContributesBinding(AppScope::class)
@Inject
class DefaultLogoutUseCase(
- private val authenticationService: MatrixAuthenticationService,
+ private val sessionStore: SessionStore,
private val matrixClientProvider: MatrixClientProvider,
) : LogoutUseCase {
- override suspend fun logout(ignoreSdkError: Boolean) {
- val currentSession = authenticationService.getLatestSessionId()
- if (currentSession != null) {
- matrixClientProvider.getOrRestore(currentSession)
- .getOrThrow()
- .logout(userInitiated = true, ignoreSdkError = true)
- } else {
- error("No session to sign out")
- }
+ override suspend fun logoutAll(ignoreSdkError: Boolean) {
+ sessionStore.getAllSessions()
+ .map { sessionData ->
+ SessionId(sessionData.userId)
+ }
+ .forEach { sessionId ->
+ Timber.d("Logging out sessionId: $sessionId")
+ matrixClientProvider.getOrRestore(sessionId).fold(
+ onSuccess = { client ->
+ client.logout(userInitiated = true, ignoreSdkError = ignoreSdkError)
+ },
+ onFailure = { error ->
+ Timber.e(error, "Failed to get or restore MatrixClient for sessionId: $sessionId")
+ }
+ )
+ }
}
}
diff --git a/features/logout/impl/src/main/res/values-eo/translations.xml b/features/logout/impl/src/main/res/values-eo/translations.xml
new file mode 100644
index 0000000000..5ba5aa6e48
--- /dev/null
+++ b/features/logout/impl/src/main/res/values-eo/translations.xml
@@ -0,0 +1,8 @@
+
+
+ "Your messages were still being backed up when you went offline. Reconnect so that your messages can be backed up before signing out."
+ "Your messages are still being backed up"
+ "Your messages are still being backed up"
+ "Backup not set up"
+ "Have you saved your backup password?"
+
diff --git a/features/logout/impl/src/test/kotlin/io/element/android/features/logout/impl/DefaultLogoutEntryPointTest.kt b/features/logout/impl/src/test/kotlin/io/element/android/features/logout/impl/DefaultLogoutEntryPointTest.kt
new file mode 100644
index 0000000000..01d1bfc6ca
--- /dev/null
+++ b/features/logout/impl/src/test/kotlin/io/element/android/features/logout/impl/DefaultLogoutEntryPointTest.kt
@@ -0,0 +1,43 @@
+/*
+ * Copyright 2025 New Vector Ltd.
+ *
+ * SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial
+ * Please see LICENSE files in the repository root for full details.
+ */
+
+package io.element.android.features.logout.impl
+
+import androidx.arch.core.executor.testing.InstantTaskExecutorRule
+import com.bumble.appyx.core.modality.BuildContext
+import com.google.common.truth.Truth.assertThat
+import io.element.android.features.logout.api.LogoutEntryPoint
+import io.element.android.tests.testutils.lambda.lambdaError
+import io.element.android.tests.testutils.node.TestParentNode
+import org.junit.Rule
+import org.junit.Test
+
+class DefaultLogoutEntryPointTest {
+ @get:Rule
+ val instantTaskExecutorRule = InstantTaskExecutorRule()
+
+ @Test
+ fun `test node builder`() {
+ val entryPoint = DefaultLogoutEntryPoint()
+
+ val parentNode = TestParentNode.create { buildContext, plugins ->
+ LogoutNode(
+ buildContext = buildContext,
+ plugins = plugins,
+ presenter = createLogoutPresenter(),
+ )
+ }
+ val callback = object : LogoutEntryPoint.Callback {
+ override fun onChangeRecoveryKeyClick() = lambdaError()
+ }
+ val result = entryPoint.nodeBuilder(parentNode, BuildContext.root(null))
+ .callback(callback)
+ .build()
+ assertThat(result).isInstanceOf(LogoutNode::class.java)
+ assertThat(result.plugins).contains(callback)
+ }
+}
diff --git a/features/logout/impl/src/test/kotlin/io/element/android/features/logout/impl/DefaultLogoutUseCaseTest.kt b/features/logout/impl/src/test/kotlin/io/element/android/features/logout/impl/DefaultLogoutUseCaseTest.kt
new file mode 100644
index 0000000000..a17e7285de
--- /dev/null
+++ b/features/logout/impl/src/test/kotlin/io/element/android/features/logout/impl/DefaultLogoutUseCaseTest.kt
@@ -0,0 +1,120 @@
+/*
+ * Copyright 2025 New Vector Ltd.
+ *
+ * SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial
+ * Please see LICENSE files in the repository root for full details.
+ */
+
+@file:OptIn(ExperimentalCoroutinesApi::class)
+
+package io.element.android.features.logout.impl
+
+import io.element.android.libraries.matrix.test.A_USER_ID
+import io.element.android.libraries.matrix.test.A_USER_ID_2
+import io.element.android.libraries.matrix.test.FakeMatrixClient
+import io.element.android.libraries.matrix.test.FakeMatrixClientProvider
+import io.element.android.libraries.sessionstorage.test.InMemorySessionStore
+import io.element.android.libraries.sessionstorage.test.aSessionData
+import io.element.android.tests.testutils.lambda.lambdaRecorder
+import io.element.android.tests.testutils.lambda.value
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.test.runTest
+import org.junit.Test
+
+class DefaultLogoutUseCaseTest {
+ @Test
+ fun `test logout from one session`() = runTest {
+ val logoutLambda1 = lambdaRecorder { _, _ -> }
+ val client1 = FakeMatrixClient(A_USER_ID).apply {
+ logoutLambda = logoutLambda1
+ }
+ val sut = DefaultLogoutUseCase(
+ sessionStore = InMemorySessionStore(
+ initialList = listOf(
+ aSessionData(sessionId = A_USER_ID.value),
+ )
+ ),
+ matrixClientProvider = FakeMatrixClientProvider(
+ getClient = { sessionId ->
+ when (sessionId) {
+ A_USER_ID -> Result.success(client1)
+ else -> error("Unexpected sessionId")
+ }
+ }
+ ),
+ )
+ sut.logoutAll(ignoreSdkError = true)
+ logoutLambda1.assertions().isCalledOnce().with(value(true), value(true))
+ }
+
+ @Test
+ fun `test logout from several sessions`() = runTest {
+ val logoutLambda1 = lambdaRecorder { _, _ -> }
+ val logoutLambda2 = lambdaRecorder { _, _ -> }
+ val client1 = FakeMatrixClient(A_USER_ID).apply {
+ logoutLambda = logoutLambda1
+ }
+ val client2 = FakeMatrixClient(A_USER_ID_2).apply {
+ logoutLambda = logoutLambda2
+ }
+ val sut = DefaultLogoutUseCase(
+ sessionStore = InMemorySessionStore(
+ initialList = listOf(
+ aSessionData(sessionId = A_USER_ID.value),
+ aSessionData(sessionId = A_USER_ID_2.value),
+ )
+ ),
+ matrixClientProvider = FakeMatrixClientProvider(
+ getClient = { sessionId ->
+ when (sessionId) {
+ A_USER_ID -> Result.success(client1)
+ A_USER_ID_2 -> Result.success(client2)
+ else -> error("Unexpected sessionId")
+ }
+ }
+ ),
+ )
+ sut.logoutAll(ignoreSdkError = true)
+ logoutLambda1.assertions().isCalledOnce().with(value(true), value(true))
+ logoutLambda2.assertions().isCalledOnce().with(value(true), value(true))
+ }
+
+ @Test
+ fun `test logout session not found is ignored`() = runTest {
+ val sut = DefaultLogoutUseCase(
+ sessionStore = InMemorySessionStore(
+ initialList = listOf(
+ aSessionData(sessionId = A_USER_ID.value),
+ )
+ ),
+ matrixClientProvider = FakeMatrixClientProvider(
+ getClient = { sessionId ->
+ when (sessionId) {
+ A_USER_ID -> Result.failure(Exception("Session not found"))
+ else -> error("Unexpected sessionId")
+ }
+ }
+ ),
+ )
+ sut.logoutAll(ignoreSdkError = true)
+ // No error
+ }
+
+ @Test
+ fun `test logout no sessions`() = runTest {
+ val sut = DefaultLogoutUseCase(
+ sessionStore = InMemorySessionStore(
+ initialList = emptyList()
+ ),
+ matrixClientProvider = FakeMatrixClientProvider(
+ getClient = { sessionId ->
+ when (sessionId) {
+ else -> error("Unexpected sessionId")
+ }
+ }
+ ),
+ )
+ sut.logoutAll(ignoreSdkError = true)
+ // No error
+ }
+}
diff --git a/features/logout/impl/src/test/kotlin/io/element/android/features/logout/impl/LogoutPresenterTest.kt b/features/logout/impl/src/test/kotlin/io/element/android/features/logout/impl/LogoutPresenterTest.kt
index 3a309ab7b9..34406aa098 100644
--- a/features/logout/impl/src/test/kotlin/io/element/android/features/logout/impl/LogoutPresenterTest.kt
+++ b/features/logout/impl/src/test/kotlin/io/element/android/features/logout/impl/LogoutPresenterTest.kt
@@ -225,12 +225,12 @@ class LogoutPresenterTest {
skipItems(2)
return awaitItem()
}
-
- private fun createLogoutPresenter(
- matrixClient: MatrixClient = FakeMatrixClient(),
- encryptionService: EncryptionService = FakeEncryptionService(),
- ): LogoutPresenter = LogoutPresenter(
- matrixClient = matrixClient,
- encryptionService = encryptionService,
- )
}
+
+internal fun createLogoutPresenter(
+ matrixClient: MatrixClient = FakeMatrixClient(),
+ encryptionService: EncryptionService = FakeEncryptionService(),
+): LogoutPresenter = LogoutPresenter(
+ matrixClient = matrixClient,
+ encryptionService = encryptionService,
+)
diff --git a/features/logout/test/src/main/kotlin/io/element/android/features/logout/test/FakeLogoutUseCase.kt b/features/logout/test/src/main/kotlin/io/element/android/features/logout/test/FakeLogoutUseCase.kt
index e71266b596..dd3ded4ef9 100644
--- a/features/logout/test/src/main/kotlin/io/element/android/features/logout/test/FakeLogoutUseCase.kt
+++ b/features/logout/test/src/main/kotlin/io/element/android/features/logout/test/FakeLogoutUseCase.kt
@@ -14,7 +14,7 @@ import io.element.android.tests.testutils.simulateLongTask
class FakeLogoutUseCase(
var logoutLambda: (Boolean) -> Unit = { lambdaError() }
) : LogoutUseCase {
- override suspend fun logout(ignoreSdkError: Boolean) = simulateLongTask {
+ override suspend fun logoutAll(ignoreSdkError: Boolean) = simulateLongTask {
logoutLambda(ignoreSdkError)
}
}
diff --git a/features/messages/impl/build.gradle.kts b/features/messages/impl/build.gradle.kts
index 15e087bac4..d05ede00ab 100644
--- a/features/messages/impl/build.gradle.kts
+++ b/features/messages/impl/build.gradle.kts
@@ -1,4 +1,5 @@
import extension.setupDependencyInjection
+import extension.testCommonDependencies
/*
* Copyright 2022-2024 New Vector Ltd.
@@ -70,11 +71,7 @@ dependencies {
implementation(projects.features.knockrequests.api)
implementation(projects.features.roommembermoderation.api)
- testImplementation(libs.test.junit)
- testImplementation(libs.coroutines.test)
- testImplementation(libs.molecule.runtime)
- testImplementation(libs.test.truth)
- testImplementation(libs.test.turbine)
+ testCommonDependencies(libs, true)
testImplementation(projects.libraries.matrix.test)
testImplementation(projects.libraries.dateformatter.test)
testImplementation(projects.libraries.push.test)
@@ -83,7 +80,6 @@ dependencies {
testImplementation(projects.features.messages.test)
testImplementation(projects.services.analytics.test)
testImplementation(projects.services.toolbox.test)
- testImplementation(projects.tests.testutils)
testImplementation(projects.libraries.featureflag.test)
testImplementation(projects.libraries.mediaupload.test)
testImplementation(projects.libraries.mediapickers.test)
@@ -93,10 +89,6 @@ dependencies {
testImplementation(projects.libraries.mediaplayer.test)
testImplementation(projects.libraries.mediaviewer.test)
testImplementation(projects.libraries.testtags)
- testImplementation(libs.test.mockk)
- testImplementation(libs.test.robolectric)
testImplementation(projects.features.poll.test)
- testImplementation(libs.androidx.compose.ui.test.junit)
testImplementation(projects.libraries.eventformatter.test)
- testReleaseImplementation(libs.androidx.compose.ui.test.manifest)
}
diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/MessagesFlowNode.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/MessagesFlowNode.kt
index 2f563395f7..5cbce99701 100644
--- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/MessagesFlowNode.kt
+++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/MessagesFlowNode.kt
@@ -15,7 +15,6 @@ import androidx.lifecycle.lifecycleScope
import com.bumble.appyx.core.lifecycle.subscribe
import com.bumble.appyx.core.modality.BuildContext
import com.bumble.appyx.core.node.Node
-import com.bumble.appyx.core.node.node
import com.bumble.appyx.core.plugin.Plugin
import com.bumble.appyx.core.plugin.plugins
import com.bumble.appyx.navmodel.backstack.BackStack
@@ -126,9 +125,6 @@ class MessagesFlowNode(
plugins = plugins
) {
sealed interface NavTarget : Parcelable {
- @Parcelize
- data object Empty : NavTarget
-
@Parcelize
data class Messages(val focusedEventId: EventId?) : NavTarget
@@ -399,9 +395,6 @@ class MessagesFlowNode(
}
createNode(buildContext, plugins = listOf(callback))
}
- NavTarget.Empty -> {
- node(buildContext) {}
- }
NavTarget.KnockRequestsList -> {
knockRequestsListEntryPoint.createNode(this, buildContext)
}
diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/MessagesPresenter.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/MessagesPresenter.kt
index 1d576472a3..04a456d71b 100644
--- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/MessagesPresenter.kt
+++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/MessagesPresenter.kt
@@ -43,6 +43,7 @@ import io.element.android.features.messages.impl.timeline.components.customreact
import io.element.android.features.messages.impl.timeline.components.reactionsummary.ReactionSummaryState
import io.element.android.features.messages.impl.timeline.components.receipt.bottomsheet.ReadReceiptBottomSheetState
import io.element.android.features.messages.impl.timeline.model.TimelineItem
+import io.element.android.features.messages.impl.timeline.model.TimelineItemThreadInfo
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemEventContentWithAttachment
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemPollContent
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemStateContent
@@ -328,7 +329,10 @@ class MessagesPresenter(
val displayThreads = featureFlagService.isFeatureEnabled(FeatureFlags.Threads)
if (displayThreads) {
// Get either the thread id this event is in, or the event id if it's not in a thread so we can start one
- val threadId = targetEvent.threadInfo.threadRootId ?: targetEvent.eventId!!.toThreadId()
+ val threadId = when (targetEvent.threadInfo) {
+ is TimelineItemThreadInfo.ThreadResponse -> targetEvent.threadInfo.threadRootId
+ is TimelineItemThreadInfo.ThreadRoot, null -> targetEvent.eventId?.toThreadId()
+ } ?: return@launch
navigator.onOpenThread(threadId, null)
} else {
handleActionReply(targetEvent, composerState, timelineProtectionState)
diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/MessagesStateProvider.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/MessagesStateProvider.kt
index 8217cb977c..e20526d083 100644
--- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/MessagesStateProvider.kt
+++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/MessagesStateProvider.kt
@@ -36,7 +36,6 @@ import io.element.android.features.messages.impl.timeline.protection.TimelinePro
import io.element.android.features.messages.impl.timeline.protection.aTimelineProtectionState
import io.element.android.features.roomcall.api.RoomCallState
import io.element.android.features.roomcall.api.aStandByCallState
-import io.element.android.features.roomcall.api.anOngoingCallState
import io.element.android.features.roommembermoderation.api.RoomMemberModerationEvents
import io.element.android.features.roommembermoderation.api.RoomMemberModerationState
import io.element.android.libraries.architecture.AsyncData
@@ -60,36 +59,29 @@ open class MessagesStateProvider : PreviewParameterProvider {
aMessagesState(composerState = aMessageComposerState(showAttachmentSourcePicker = true)),
aMessagesState(userEventPermissions = aUserEventPermissions(canSendMessage = false)),
aMessagesState(showReinvitePrompt = true),
- aMessagesState(roomName = null),
aMessagesState(composerState = aMessageComposerState(showTextFormatting = true)),
aMessagesState(
voiceMessageComposerState = aVoiceMessageComposerState(showPermissionRationaleDialog = true),
),
- aMessagesState(
- roomCallState = anOngoingCallState(),
- ),
aMessagesState(
voiceMessageComposerState = aVoiceMessageComposerState(
voiceMessageState = aVoiceMessagePreviewState(),
showSendFailureDialog = true
),
),
- aMessagesState(
- roomCallState = aStandByCallState(canStartCall = false),
- ),
aMessagesState(
pinnedMessagesBannerState = aLoadedPinnedMessagesBannerState(
knownPinnedMessagesCount = 4,
currentPinnedMessageIndex = 0,
),
),
- aMessagesState(roomName = "A DM with a very looong name", dmUserVerificationState = IdentityState.Verified),
- aMessagesState(roomName = "A DM with a very looong name", dmUserVerificationState = IdentityState.VerificationViolation),
aMessagesState(successorRoom = SuccessorRoom(RoomId("!id:domain"), null)),
- aMessagesState(timelineState = aTimelineState(
- timelineMode = Timeline.Mode.Thread(threadRootId = ThreadId("\$a-thread-id")),
- timelineItems = aTimelineItemList(aTimelineItemTextContent()),
- )),
+ aMessagesState(
+ timelineState = aTimelineState(
+ timelineMode = Timeline.Mode.Thread(threadRootId = ThreadId("\$a-thread-id")),
+ timelineItems = aTimelineItemList(aTimelineItemTextContent()),
+ )
+ ),
)
}
diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/MessagesView.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/MessagesView.kt
index 6a436adabc..07fc178721 100644
--- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/MessagesView.kt
+++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/MessagesView.kt
@@ -11,12 +11,10 @@ import androidx.compose.animation.AnimatedVisibility
import androidx.compose.animation.expandVertically
import androidx.compose.animation.shrinkVertically
import androidx.compose.foundation.background
-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.Row
-import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.WindowInsets
import androidx.compose.foundation.layout.consumeWindowInsets
import androidx.compose.foundation.layout.fillMaxSize
@@ -27,30 +25,23 @@ import androidx.compose.foundation.layout.navigationBarsPadding
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.statusBars
import androidx.compose.foundation.layout.systemBarsPadding
-import androidx.compose.foundation.layout.width
-import androidx.compose.foundation.shape.RoundedCornerShape
-import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.MaterialTheme
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
-import androidx.compose.ui.draw.clip
import androidx.compose.ui.draw.shadow
import androidx.compose.ui.graphics.RectangleShape
import androidx.compose.ui.platform.LocalView
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.semantics.Role
-import androidx.compose.ui.semantics.heading
import androidx.compose.ui.semantics.onClick
import androidx.compose.ui.semantics.role
import androidx.compose.ui.semantics.semantics
import androidx.compose.ui.text.font.FontStyle
import androidx.compose.ui.text.style.TextAlign
-import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.tooling.preview.PreviewParameter
import androidx.compose.ui.unit.dp
import io.element.android.compound.theme.ElementTheme
-import io.element.android.compound.tokens.generated.CompoundIcons
import io.element.android.features.messages.api.timeline.voicemessages.composer.VoiceMessageComposerEvents
import io.element.android.features.messages.impl.actionlist.ActionListEvents
import io.element.android.features.messages.impl.actionlist.ActionListView
@@ -69,7 +60,6 @@ import io.element.android.features.messages.impl.pinned.banner.PinnedMessagesBan
import io.element.android.features.messages.impl.timeline.FOCUS_ON_PINNED_EVENT_DEBOUNCE_DURATION_IN_MILLIS
import io.element.android.features.messages.impl.timeline.TimelineEvents
import io.element.android.features.messages.impl.timeline.TimelineView
-import io.element.android.features.messages.impl.timeline.components.CallMenuItem
import io.element.android.features.messages.impl.timeline.components.customreaction.CustomReactionBottomSheet
import io.element.android.features.messages.impl.timeline.components.customreaction.CustomReactionEvents
import io.element.android.features.messages.impl.timeline.components.reactionsummary.ReactionSummaryEvents
@@ -77,28 +67,23 @@ import io.element.android.features.messages.impl.timeline.components.reactionsum
import io.element.android.features.messages.impl.timeline.components.receipt.bottomsheet.ReadReceiptBottomSheet
import io.element.android.features.messages.impl.timeline.components.receipt.bottomsheet.ReadReceiptBottomSheetEvents
import io.element.android.features.messages.impl.timeline.model.TimelineItem
+import io.element.android.features.messages.impl.topbars.MessagesViewTopBar
+import io.element.android.features.messages.impl.topbars.ThreadTopBar
import io.element.android.features.messages.impl.voicemessages.composer.VoiceMessagePermissionRationaleDialog
import io.element.android.features.messages.impl.voicemessages.composer.VoiceMessageSendingFailedDialog
import io.element.android.features.networkmonitor.api.ui.ConnectivityIndicatorView
-import io.element.android.features.roomcall.api.RoomCallState
import io.element.android.libraries.androidutils.ui.hideKeyboard
import io.element.android.libraries.designsystem.atomic.molecules.ComposerAlertMolecule
import io.element.android.libraries.designsystem.components.ExpandableBottomSheetLayout
import io.element.android.libraries.designsystem.components.ExpandableBottomSheetLayoutState
-import io.element.android.libraries.designsystem.components.avatar.Avatar
-import io.element.android.libraries.designsystem.components.avatar.AvatarData
-import io.element.android.libraries.designsystem.components.avatar.AvatarType
-import io.element.android.libraries.designsystem.components.button.BackButton
import io.element.android.libraries.designsystem.components.dialogs.ConfirmationDialog
import io.element.android.libraries.designsystem.components.rememberExpandableBottomSheetLayoutState
import io.element.android.libraries.designsystem.preview.ElementPreview
import io.element.android.libraries.designsystem.preview.PreviewsDayNight
import io.element.android.libraries.designsystem.text.toAnnotatedString
import io.element.android.libraries.designsystem.theme.components.BottomSheetDragHandle
-import io.element.android.libraries.designsystem.theme.components.Icon
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.designsystem.utils.HideKeyboardWhenDisposed
import io.element.android.libraries.designsystem.utils.KeepScreenOn
import io.element.android.libraries.designsystem.utils.OnLifecycleEvent
@@ -114,7 +99,6 @@ import io.element.android.libraries.matrix.api.user.MatrixUser
import io.element.android.libraries.textcomposer.model.TextEditorState
import io.element.android.libraries.ui.strings.CommonStrings
import io.element.android.wysiwyg.link.Link
-import kotlinx.collections.immutable.ImmutableList
import timber.log.Timber
import kotlin.time.Duration.Companion.milliseconds
@@ -202,7 +186,13 @@ fun MessagesView(
Column {
ConnectivityIndicatorView(isOnline = state.hasNetworkConnection)
if (state.timelineState.timelineMode is Timeline.Mode.Thread) {
- ThreadTopBar(onBackClick = onBackClick)
+ ThreadTopBar(
+ roomName = state.roomName,
+ roomAvatarData = state.roomAvatar,
+ heroes = state.heroes,
+ isTombstoned = state.isTombstoned,
+ onBackClick = onBackClick,
+ )
} else {
MessagesViewTopBar(
roomName = state.roomName,
@@ -505,120 +495,6 @@ private fun MessagesViewComposerBottomSheetContents(
}
}
-@OptIn(ExperimentalMaterial3Api::class)
-@Composable
-private fun MessagesViewTopBar(
- roomName: String?,
- roomAvatar: AvatarData,
- isTombstoned: Boolean,
- heroes: ImmutableList,
- roomCallState: RoomCallState,
- dmUserIdentityState: IdentityState?,
- onRoomDetailsClick: () -> Unit,
- onJoinCallClick: () -> Unit,
- onBackClick: () -> Unit,
-) {
- TopAppBar(
- navigationIcon = {
- BackButton(onClick = onBackClick)
- },
- title = {
- val roundedCornerShape = RoundedCornerShape(8.dp)
- Row(
- modifier = Modifier
- .clip(roundedCornerShape)
- .clickable { onRoomDetailsClick() },
- horizontalArrangement = Arrangement.spacedBy(4.dp),
- verticalAlignment = Alignment.CenterVertically,
- ) {
- val titleModifier = Modifier.weight(1f, fill = false)
- RoomAvatarAndNameRow(
- roomName = roomName,
- roomAvatar = roomAvatar,
- isTombstoned = isTombstoned,
- heroes = heroes,
- modifier = titleModifier
- )
-
- when (dmUserIdentityState) {
- IdentityState.Verified -> {
- Icon(
- imageVector = CompoundIcons.Verified(),
- tint = ElementTheme.colors.iconSuccessPrimary,
- contentDescription = null,
- )
- }
- IdentityState.VerificationViolation -> {
- Icon(
- imageVector = CompoundIcons.ErrorSolid(),
- tint = ElementTheme.colors.iconCriticalPrimary,
- contentDescription = null,
- )
- }
- else -> Unit
- }
- }
- },
- actions = {
- CallMenuItem(
- roomCallState = roomCallState,
- onJoinCallClick = onJoinCallClick,
- )
- Spacer(Modifier.width(8.dp))
- },
- windowInsets = WindowInsets(0.dp)
- )
-}
-
-@OptIn(ExperimentalMaterial3Api::class)
-@Composable
-private fun ThreadTopBar(
- onBackClick: () -> Unit,
-) {
- TopAppBar(
- navigationIcon = {
- BackButton(onClick = onBackClick)
- },
- title = {
- Text(stringResource(CommonStrings.common_thread))
- }
- )
-}
-
-@Composable
-private fun RoomAvatarAndNameRow(
- roomName: String?,
- roomAvatar: AvatarData,
- heroes: ImmutableList,
- isTombstoned: Boolean,
- modifier: Modifier = Modifier
-) {
- Row(
- modifier = modifier,
- verticalAlignment = Alignment.CenterVertically
- ) {
- Avatar(
- avatarData = roomAvatar,
- avatarType = AvatarType.Room(
- heroes = heroes,
- isTombstoned = isTombstoned,
- ),
- )
- Text(
- modifier = Modifier
- .padding(horizontal = 8.dp)
- .semantics {
- heading()
- },
- text = roomName ?: stringResource(CommonStrings.common_no_room_name),
- style = ElementTheme.typography.fontBodyLgMedium,
- fontStyle = FontStyle.Italic.takeIf { roomName == null },
- maxLines = 1,
- overflow = TextOverflow.Ellipsis
- )
- }
-}
-
@Composable
private fun CantSendMessageBanner() {
Row(
diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/actionlist/ActionListPresenter.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/actionlist/ActionListPresenter.kt
index 6263576c53..20dc45ccc8 100644
--- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/actionlist/ActionListPresenter.kt
+++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/actionlist/ActionListPresenter.kt
@@ -25,12 +25,13 @@ import io.element.android.features.messages.impl.actionlist.model.TimelineItemAc
import io.element.android.features.messages.impl.crypto.sendfailure.VerifiedUserSendFailure
import io.element.android.features.messages.impl.crypto.sendfailure.VerifiedUserSendFailureFactory
import io.element.android.features.messages.impl.timeline.model.TimelineItem
-import io.element.android.features.messages.impl.timeline.model.event.TimelineItemCallNotifyContent
+import io.element.android.features.messages.impl.timeline.model.TimelineItemThreadInfo
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemEventContent
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemEventContentWithAttachment
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemLegacyCallInviteContent
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemPollContent
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemRedactedContent
+import io.element.android.features.messages.impl.timeline.model.event.TimelineItemRtcNotificationContent
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemStateContent
import io.element.android.features.messages.impl.timeline.model.event.canBeCopied
import io.element.android.features.messages.impl.timeline.model.event.canBeForwarded
@@ -174,7 +175,7 @@ class DefaultActionListPresenter(
add(TimelineItemAction.ReplyInThread)
add(TimelineItemAction.Reply)
} else {
- if (!isThreadsEnabled && timelineItem.threadInfo.threadRootId != null) {
+ if (!isThreadsEnabled && timelineItem.threadInfo is TimelineItemThreadInfo.ThreadResponse) {
// If threads are not enabled, we can reply in a thread if the item is already in the thread
add(TimelineItemAction.ReplyInThread)
} else {
@@ -242,7 +243,7 @@ class DefaultActionListPresenter(
private fun Iterable.postFilter(content: TimelineItemEventContent): Iterable {
return filter { action ->
when (content) {
- is TimelineItemCallNotifyContent,
+ is TimelineItemRtcNotificationContent,
is TimelineItemLegacyCallInviteContent,
is TimelineItemStateContent -> action == TimelineItemAction.ViewSource
is TimelineItemRedactedContent -> {
diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/actionlist/ActionListView.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/actionlist/ActionListView.kt
index 78b4b43112..bb57cc82d4 100644
--- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/actionlist/ActionListView.kt
+++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/actionlist/ActionListView.kt
@@ -56,7 +56,6 @@ import io.element.android.features.messages.impl.timeline.a11y.a11yReactionActio
import io.element.android.features.messages.impl.timeline.components.MessageShieldView
import io.element.android.features.messages.impl.timeline.model.TimelineItem
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemAudioContent
-import io.element.android.features.messages.impl.timeline.model.event.TimelineItemCallNotifyContent
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemEncryptedContent
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemFileContent
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemImageContent
@@ -64,6 +63,7 @@ import io.element.android.features.messages.impl.timeline.model.event.TimelineIt
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemLocationContent
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemPollContent
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemRedactedContent
+import io.element.android.features.messages.impl.timeline.model.event.TimelineItemRtcNotificationContent
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemStateContent
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemStickerContent
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemTextBasedContent
@@ -306,7 +306,7 @@ private fun MessageSummary(
is TimelineItemLegacyCallInviteContent -> {
content = { ContentForBody(textContent) }
}
- is TimelineItemCallNotifyContent -> {
+ is TimelineItemRtcNotificationContent -> {
content = { ContentForBody(stringResource(CommonStrings.common_call_started)) }
}
}
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 99a72e06a2..0f0480f404 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
@@ -155,7 +155,6 @@ internal fun SuggestionsPickerViewPreview() {
membership = RoomMembershipState.JOIN,
isNameAmbiguous = false,
powerLevel = 0L,
- normalizedPowerLevel = 0L,
isIgnored = false,
role = RoomMember.Role.User,
membershipChangeReason = null,
diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/TimelineStateProvider.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/TimelineStateProvider.kt
index 3c03f4a7b0..e7dc71f185 100644
--- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/TimelineStateProvider.kt
+++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/TimelineStateProvider.kt
@@ -16,6 +16,7 @@ import io.element.android.features.messages.impl.timeline.model.TimelineItem
import io.element.android.features.messages.impl.timeline.model.TimelineItemGroupPosition
import io.element.android.features.messages.impl.timeline.model.TimelineItemReactions
import io.element.android.features.messages.impl.timeline.model.TimelineItemReadReceipts
+import io.element.android.features.messages.impl.timeline.model.TimelineItemThreadInfo
import io.element.android.features.messages.impl.timeline.model.anAggregatedReaction
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemEventContent
import io.element.android.features.messages.impl.timeline.model.event.aTimelineItemStateEventContent
@@ -32,7 +33,6 @@ import io.element.android.libraries.matrix.api.core.UniqueId
import io.element.android.libraries.matrix.api.core.UserId
import io.element.android.libraries.matrix.api.room.tombstone.PredecessorRoom
import io.element.android.libraries.matrix.api.timeline.Timeline
-import io.element.android.libraries.matrix.api.timeline.item.EventThreadInfo
import io.element.android.libraries.matrix.api.timeline.item.TimelineItemDebugInfo
import io.element.android.libraries.matrix.api.timeline.item.event.LocalEventSendState
import io.element.android.libraries.matrix.api.timeline.item.event.MessageShield
@@ -146,7 +146,7 @@ internal fun aTimelineItemEvent(
groupPosition: TimelineItemGroupPosition = TimelineItemGroupPosition.None,
sendState: LocalEventSendState? = null,
inReplyTo: InReplyToDetails? = null,
- threadInfo: EventThreadInfo = EventThreadInfo(threadRootId = null, threadSummary = null),
+ threadInfo: TimelineItemThreadInfo? = null,
debugInfo: TimelineItemDebugInfo = aTimelineItemDebugInfo(),
timelineItemReactions: TimelineItemReactions = aTimelineItemReactions(),
readReceiptState: TimelineItemReadReceipts = aTimelineItemReadReceipts(),
diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/MessageEventBubble.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/MessageEventBubble.kt
index 04fe0cb481..1dbe5d3a24 100644
--- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/MessageEventBubble.kt
+++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/MessageEventBubble.kt
@@ -53,8 +53,6 @@ import io.element.android.libraries.ui.utils.time.isTalkbackActive
private val BUBBLE_RADIUS = 12.dp
private val avatarRadius = AvatarSize.TimelineSender.dp / 2
-// Design says: The maximum width of a bubble is still 3/4 of the screen width. But try with 78% now.
-private const val BUBBLE_WIDTH_RATIO = 0.78f
private val MIN_BUBBLE_WIDTH = 80.dp
@Composable
@@ -66,34 +64,6 @@ fun MessageEventBubble(
modifier: Modifier = Modifier,
content: @Composable BoxScope.() -> Unit = {},
) {
- fun bubbleShape(): Shape {
- val topLeftCorner = if (state.cutTopStart) 0.dp else BUBBLE_RADIUS
- return when (state.groupPosition) {
- TimelineItemGroupPosition.First -> if (state.isMine) {
- RoundedCornerShape(BUBBLE_RADIUS, BUBBLE_RADIUS, 0.dp, BUBBLE_RADIUS)
- } else {
- RoundedCornerShape(topLeftCorner, BUBBLE_RADIUS, BUBBLE_RADIUS, 0.dp)
- }
- TimelineItemGroupPosition.Middle -> if (state.isMine) {
- RoundedCornerShape(BUBBLE_RADIUS, 0.dp, 0.dp, BUBBLE_RADIUS)
- } else {
- RoundedCornerShape(0.dp, BUBBLE_RADIUS, BUBBLE_RADIUS, 0.dp)
- }
- TimelineItemGroupPosition.Last -> if (state.isMine) {
- RoundedCornerShape(BUBBLE_RADIUS, 0.dp, BUBBLE_RADIUS, BUBBLE_RADIUS)
- } else {
- RoundedCornerShape(0.dp, BUBBLE_RADIUS, BUBBLE_RADIUS, BUBBLE_RADIUS)
- }
- TimelineItemGroupPosition.None ->
- RoundedCornerShape(
- topLeftCorner,
- BUBBLE_RADIUS,
- BUBBLE_RADIUS,
- BUBBLE_RADIUS
- )
- }
- }
-
val clickableModifier = if (isTalkbackActive()) {
Modifier
} else {
@@ -108,11 +78,8 @@ fun MessageEventBubble(
}
// Ignore state.isHighlighted for now, we need a design decision on it.
- val backgroundBubbleColor = when {
- state.isMine -> ElementTheme.colors.messageFromMeBackground
- else -> ElementTheme.colors.messageFromOtherBackground
- }
- val bubbleShape = bubbleShape()
+ val backgroundBubbleColor = MessageEventBubbleDefaults.backgroundBubbleColor(state.isMine)
+ val bubbleShape = remember(state) { MessageEventBubbleDefaults.shape(state.cutTopStart, state.groupPosition, state.isMine) }
val radiusPx = (avatarRadius + SENDER_AVATAR_BORDER_WIDTH).toPx()
val yOffsetPx = -(NEGATIVE_MARGIN_FOR_BUBBLE + avatarRadius).toPx()
val isRtl = LocalLayoutDirection.current == LayoutDirection.Rtl
@@ -147,7 +114,7 @@ fun MessageEventBubble(
.testTag(TestTags.messageBubble)
.widthIn(
min = MIN_BUBBLE_WIDTH,
- max = (constraints.maxWidth * BUBBLE_WIDTH_RATIO)
+ max = (constraints.maxWidth * MessageEventBubbleDefaults.BUBBLE_WIDTH_RATIO)
.toInt()
.toDp()
)
@@ -157,6 +124,48 @@ fun MessageEventBubble(
}
}
+object MessageEventBubbleDefaults {
+ fun shape(cutTopStart: Boolean, groupPosition: TimelineItemGroupPosition, isMine: Boolean): Shape {
+ val topLeftCorner = if (cutTopStart) 0.dp else BUBBLE_RADIUS
+ return when (groupPosition) {
+ TimelineItemGroupPosition.First -> if (isMine) {
+ RoundedCornerShape(BUBBLE_RADIUS, BUBBLE_RADIUS, 0.dp, BUBBLE_RADIUS)
+ } else {
+ RoundedCornerShape(topLeftCorner, BUBBLE_RADIUS, BUBBLE_RADIUS, 0.dp)
+ }
+ TimelineItemGroupPosition.Middle -> if (isMine) {
+ RoundedCornerShape(BUBBLE_RADIUS, 0.dp, 0.dp, BUBBLE_RADIUS)
+ } else {
+ RoundedCornerShape(0.dp, BUBBLE_RADIUS, BUBBLE_RADIUS, 0.dp)
+ }
+ TimelineItemGroupPosition.Last -> if (isMine) {
+ RoundedCornerShape(BUBBLE_RADIUS, 0.dp, BUBBLE_RADIUS, BUBBLE_RADIUS)
+ } else {
+ RoundedCornerShape(0.dp, BUBBLE_RADIUS, BUBBLE_RADIUS, BUBBLE_RADIUS)
+ }
+ TimelineItemGroupPosition.None ->
+ RoundedCornerShape(
+ topLeftCorner,
+ BUBBLE_RADIUS,
+ BUBBLE_RADIUS,
+ BUBBLE_RADIUS
+ )
+ }
+ }
+
+ @Composable
+ fun backgroundBubbleColor(isMine: Boolean): Color {
+ return if (isMine) {
+ ElementTheme.colors.messageFromMeBackground
+ } else {
+ ElementTheme.colors.messageFromOtherBackground
+ }
+ }
+
+ // Design says: The maximum width of a bubble is still 3/4 of the screen width. But try with 78% now.
+ const val BUBBLE_WIDTH_RATIO = 0.78f
+}
+
@PreviewsDayNight
@Composable
internal fun MessageEventBubblePreview(@PreviewParameter(BubbleStateProvider::class) state: BubbleState) = ElementPreview {
diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/TimelineItemCallNotifyView.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/TimelineItemCallNotifyView.kt
index 6cbd22c3fa..aaebfb4957 100644
--- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/TimelineItemCallNotifyView.kt
+++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/TimelineItemCallNotifyView.kt
@@ -29,7 +29,7 @@ import io.element.android.compound.theme.ElementTheme
import io.element.android.compound.tokens.generated.CompoundIcons
import io.element.android.features.messages.impl.timeline.aTimelineItemEvent
import io.element.android.features.messages.impl.timeline.model.TimelineItem
-import io.element.android.features.messages.impl.timeline.model.event.TimelineItemCallNotifyContent
+import io.element.android.features.messages.impl.timeline.model.event.TimelineItemRtcNotificationContent
import io.element.android.features.roomcall.api.RoomCallState
import io.element.android.features.roomcall.api.RoomCallStateProvider
import io.element.android.libraries.designsystem.components.avatar.Avatar
@@ -119,7 +119,7 @@ internal fun TimelineItemCallNotifyViewPreview() = ElementPreview {
.filter { it !is RoomCallState.Unavailable }
.forEach { roomCallState ->
TimelineItemCallNotifyView(
- event = aTimelineItemEvent(content = TimelineItemCallNotifyContent()),
+ event = aTimelineItemEvent(content = TimelineItemRtcNotificationContent()),
roomCallState = roomCallState,
onLongClick = {},
onJoinCallClick = {},
diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/TimelineItemEventRow.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/TimelineItemEventRow.kt
index de4cfe2c2a..1503bf236b 100644
--- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/TimelineItemEventRow.kt
+++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/TimelineItemEventRow.kt
@@ -15,6 +15,7 @@ import androidx.compose.foundation.gestures.draggable
import androidx.compose.foundation.interaction.MutableInteractionSource
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
+import androidx.compose.foundation.layout.BoxWithConstraints
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
@@ -23,6 +24,8 @@ import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
+import androidx.compose.foundation.layout.width
+import androidx.compose.foundation.layout.widthIn
import androidx.compose.foundation.layout.wrapContentHeight
import androidx.compose.foundation.shape.CircleShape
import androidx.compose.foundation.shape.RoundedCornerShape
@@ -34,6 +37,7 @@ import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
+import androidx.compose.ui.graphics.graphicsLayer
import androidx.compose.ui.platform.LocalViewConfiguration
import androidx.compose.ui.platform.ViewConfiguration
import androidx.compose.ui.res.pluralStringResource
@@ -43,6 +47,7 @@ import androidx.compose.ui.semantics.hideFromAccessibility
import androidx.compose.ui.semantics.isTraversalGroup
import androidx.compose.ui.semantics.semantics
import androidx.compose.ui.semantics.traversalIndex
+import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.unit.DpOffset
import androidx.compose.ui.unit.IntOffset
import androidx.compose.ui.unit.dp
@@ -61,6 +66,7 @@ import io.element.android.features.messages.impl.timeline.components.receipt.Rea
import io.element.android.features.messages.impl.timeline.components.receipt.TimelineItemReadReceiptView
import io.element.android.features.messages.impl.timeline.model.TimelineItem
import io.element.android.features.messages.impl.timeline.model.TimelineItemGroupPosition
+import io.element.android.features.messages.impl.timeline.model.TimelineItemThreadInfo
import io.element.android.features.messages.impl.timeline.model.bubble.BubbleState
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemImageContent
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemLocationContent
@@ -78,25 +84,28 @@ import io.element.android.libraries.designsystem.colors.AvatarColorsProvider
import io.element.android.libraries.designsystem.components.EqualWidthColumn
import io.element.android.libraries.designsystem.components.avatar.Avatar
import io.element.android.libraries.designsystem.components.avatar.AvatarData
+import io.element.android.libraries.designsystem.components.avatar.AvatarSize
import io.element.android.libraries.designsystem.components.avatar.AvatarType
+import io.element.android.libraries.designsystem.modifiers.niceClickable
import io.element.android.libraries.designsystem.preview.ElementPreview
import io.element.android.libraries.designsystem.preview.PreviewsDayNight
import io.element.android.libraries.designsystem.swipe.SwipeableActionsState
import io.element.android.libraries.designsystem.swipe.rememberSwipeableActionsState
import io.element.android.libraries.designsystem.text.toPx
-import io.element.android.libraries.designsystem.theme.components.Button
-import io.element.android.libraries.designsystem.theme.components.ButtonSize
import io.element.android.libraries.designsystem.theme.components.Icon
import io.element.android.libraries.designsystem.theme.components.Text
import io.element.android.libraries.matrix.api.core.EventId
-import io.element.android.libraries.matrix.api.core.ThreadId
import io.element.android.libraries.matrix.api.core.UserId
import io.element.android.libraries.matrix.api.core.toThreadId
import io.element.android.libraries.matrix.api.timeline.Timeline
-import io.element.android.libraries.matrix.api.timeline.item.EventThreadInfo
+import io.element.android.libraries.matrix.api.timeline.item.EmbeddedEventInfo
import io.element.android.libraries.matrix.api.timeline.item.ThreadSummary
+import io.element.android.libraries.matrix.api.timeline.item.event.EventOrTransactionId
+import io.element.android.libraries.matrix.api.timeline.item.event.MessageContent
import io.element.android.libraries.matrix.api.timeline.item.event.ProfileTimelineDetails
+import io.element.android.libraries.matrix.api.timeline.item.event.TextMessageType
import io.element.android.libraries.matrix.api.timeline.item.event.getAvatarUrl
+import io.element.android.libraries.matrix.api.timeline.item.event.getDisambiguatedDisplayName
import io.element.android.libraries.matrix.api.timeline.item.event.getDisplayName
import io.element.android.libraries.matrix.api.user.MatrixUser
import io.element.android.libraries.matrix.ui.messages.reply.InReplyToDetails
@@ -256,22 +265,22 @@ fun TimelineItemEventRow(
)
}
- if (displayThreadSummaries && timelineMode !is Timeline.Mode.Thread) {
- event.threadInfo.threadSummary?.let { threadSummary ->
- val threadPart = stringResource(CommonStrings.common_thread)
- val numberOfReplies = threadSummary.numberOfReplies.toInt().let { replies ->
- pluralStringResource(CommonPlurals.common_replies, replies, replies)
+ if (displayThreadSummaries && timelineMode !is Timeline.Mode.Thread && event.threadInfo is TimelineItemThreadInfo.ThreadRoot) {
+ ThreadSummaryView(
+ modifier = if (event.isMine) {
+ Modifier.align(Alignment.End).padding(end = 16.dp)
+ } else {
+ if (timelineRoomInfo.isDm) Modifier else Modifier.padding(start = 16.dp)
+ }.padding(top = 2.dp),
+ threadSummary = event.threadInfo.summary,
+ latestEventText = event.threadInfo.latestEventText,
+ isOutgoing = event.isMine,
+ onClick = {
+ event.eventId?.let {
+ eventSink(TimelineEvents.OpenThread(it.toThreadId(), null))
+ }
}
- Button(
- modifier = Modifier.padding(horizontal = 24.dp, vertical = 2.dp)
- .align(if (event.isMine) Alignment.End else Alignment.Start),
- text = "$threadPart - $numberOfReplies",
- size = ButtonSize.Small,
- onClick = {
- eventSink(TimelineEvents.OpenThread(event.eventId!!.toThreadId(), null))
- },
- )
- }
+ )
}
// Read receipts / Send state
@@ -288,6 +297,81 @@ fun TimelineItemEventRow(
}
}
+@Composable
+private fun ThreadSummaryView(
+ threadSummary: ThreadSummary,
+ latestEventText: String?,
+ isOutgoing: Boolean,
+ onClick: () -> Unit,
+ modifier: Modifier = Modifier,
+) {
+ BoxWithConstraints(modifier = modifier) {
+ Row(
+ modifier = Modifier
+ .then(if (!isOutgoing) Modifier.padding(start = 16.dp) else Modifier)
+ .graphicsLayer {
+ shape = RoundedCornerShape(8.dp)
+ clip = true
+ }
+ .background(MessageEventBubbleDefaults.backgroundBubbleColor(isOutgoing))
+ .niceClickable(onClick)
+ .padding(horizontal = 12.dp, vertical = 10.dp)
+ .widthIn(max = (maxWidth - 24.dp) * MessageEventBubbleDefaults.BUBBLE_WIDTH_RATIO),
+ verticalAlignment = Alignment.CenterVertically,
+ ) {
+ Icon(
+ modifier = Modifier.size(20.dp),
+ imageVector = CompoundIcons.ThreadsSolid(),
+ contentDescription = null,
+ tint = ElementTheme.colors.iconSecondary,
+ )
+ Spacer(modifier = Modifier.width(4.dp))
+ Text(
+ text = pluralStringResource(CommonPlurals.common_replies, threadSummary.numberOfReplies.toInt(), threadSummary.numberOfReplies),
+ style = ElementTheme.typography.fontBodySmMedium,
+ color = ElementTheme.colors.textSecondary,
+ )
+
+ Spacer(modifier = Modifier.width(8.dp))
+
+ threadSummary.latestEvent.dataOrNull()?.let { latestEvent ->
+ val avatarData = AvatarData(
+ id = latestEvent.senderId.value,
+ name = latestEvent.senderProfile.getDisplayName(),
+ url = latestEvent.senderProfile.getAvatarUrl(),
+ size = AvatarSize.TimelineThreadLatestEventSender,
+ )
+ Avatar(
+ avatarData = avatarData,
+ avatarType = AvatarType.User,
+ )
+
+ Spacer(modifier = Modifier.width(8.dp))
+
+ Text(
+ text = latestEvent.senderProfile.getDisambiguatedDisplayName(latestEvent.senderId),
+ style = ElementTheme.typography.fontBodySmMedium,
+ color = ElementTheme.colors.textSecondary,
+ maxLines = 1,
+ overflow = TextOverflow.Ellipsis,
+ )
+
+ Spacer(modifier = Modifier.width(4.dp))
+
+ latestEventText?.let {
+ Text(
+ text = it,
+ style = ElementTheme.typography.fontBodySmRegular,
+ color = ElementTheme.colors.textSecondary,
+ overflow = TextOverflow.Ellipsis,
+ maxLines = 1,
+ )
+ }
+ }
+ }
+ }
+}
+
/**
* Impact ViewConfiguration.touchSlop by [sensitivityFactor].
* Inspired from https://issuetracker.google.com/u/1/issues/269627294.
@@ -694,7 +778,7 @@ private fun MessageEventBubbleContent(
else -> ContentPadding.Textual
}
CommonLayout(
- showThreadDecoration = timelineMode !is Timeline.Mode.Thread && event.threadInfo.threadRootId != null,
+ showThreadDecoration = timelineMode !is Timeline.Mode.Thread && event.threadInfo is TimelineItemThreadInfo.ThreadResponse,
timestampPosition = timestampPosition,
paddingBehaviour = paddingBehaviour,
inReplyToDetails = event.inReplyTo,
@@ -746,9 +830,27 @@ internal fun TimelineItemEventRowWithThreadSummaryPreview() = ElementPreview {
" hopefully can be manually adjusted to test different behaviors."
),
groupPosition = TimelineItemGroupPosition.First,
- threadInfo = EventThreadInfo(
- threadRootId = ThreadId("\$thread-root-id"),
- threadSummary = ThreadSummary(AsyncData.Uninitialized, numberOfReplies = 20L)
+ threadInfo = TimelineItemThreadInfo.ThreadRoot(
+ latestEventText = "This is the latest message in the thread",
+ summary = ThreadSummary(AsyncData.Success(
+ EmbeddedEventInfo(
+ eventOrTransactionId = EventOrTransactionId.Event(EventId("\$event-id")),
+ content = MessageContent(
+ body = "This is the latest message in the thread",
+ inReplyTo = null,
+ isEdited = false,
+ threadInfo = null,
+ type = TextMessageType("This is the latest message in the thread", null)
+ ),
+ senderId = UserId("@user:id"),
+ senderProfile = ProfileTimelineDetails.Ready(
+ displayName = "Alice",
+ avatarUrl = null,
+ displayNameAmbiguous = false,
+ ),
+ timestamp = 0L,
+ )
+ ), numberOfReplies = 20L)
)
),
displayThreadSummaries = true,
@@ -756,3 +858,40 @@ internal fun TimelineItemEventRowWithThreadSummaryPreview() = ElementPreview {
}
}
}
+
+@PreviewsDayNight
+@Composable
+internal fun ThreadSummaryViewPreview() {
+ ElementPreview {
+ val body = "This is the latest message in the thread"
+ val threadSummary = ThreadSummary(
+ AsyncData.Success(
+ EmbeddedEventInfo(
+ eventOrTransactionId = EventOrTransactionId.Event(EventId("\$event-id")),
+ content = MessageContent(
+ body = body,
+ inReplyTo = null,
+ isEdited = false,
+ threadInfo = null,
+ type = TextMessageType(body, null)
+ ),
+ senderId = UserId("@user:id"),
+ senderProfile = ProfileTimelineDetails.Ready(
+ displayName = "Alice",
+ avatarUrl = null,
+ displayNameAmbiguous = true,
+ ),
+ timestamp = 0L,
+ )
+ ),
+ numberOfReplies = 12,
+ )
+
+ ThreadSummaryView(
+ threadSummary = threadSummary,
+ latestEventText = "Some event with a very long text that should get clipped",
+ isOutgoing = true,
+ onClick = {},
+ )
+ }
+}
diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/TimelineItemEventRowWithReplyPreview.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/TimelineItemEventRowWithReplyPreview.kt
index 61e86a8d59..7cc1843466 100644
--- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/TimelineItemEventRowWithReplyPreview.kt
+++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/TimelineItemEventRowWithReplyPreview.kt
@@ -13,12 +13,12 @@ import androidx.compose.ui.tooling.preview.PreviewParameter
import io.element.android.features.messages.impl.timeline.aTimelineItemEvent
import io.element.android.features.messages.impl.timeline.aTimelineItemReactions
import io.element.android.features.messages.impl.timeline.model.TimelineItemGroupPosition
+import io.element.android.features.messages.impl.timeline.model.TimelineItemThreadInfo
import io.element.android.features.messages.impl.timeline.model.event.aTimelineItemImageContent
import io.element.android.features.messages.impl.timeline.model.event.aTimelineItemTextContent
import io.element.android.libraries.designsystem.preview.ElementPreview
import io.element.android.libraries.designsystem.preview.PreviewsDayNight
import io.element.android.libraries.matrix.api.core.ThreadId
-import io.element.android.libraries.matrix.api.timeline.item.EventThreadInfo
import io.element.android.libraries.matrix.ui.messages.reply.InReplyToDetails
import io.element.android.libraries.matrix.ui.messages.reply.InReplyToDetailsProvider
@@ -58,10 +58,7 @@ internal fun TimelineItemEventRowWithReplyContentToPreview(
),
inReplyTo = inReplyToDetails,
displayNameAmbiguous = displayNameAmbiguous,
- threadInfo = EventThreadInfo(
- threadRootId = ThreadId("\$thread-root-id"),
- threadSummary = null,
- ),
+ threadInfo = TimelineItemThreadInfo.ThreadResponse(threadRootId = ThreadId("\$thread-root-id")),
groupPosition = TimelineItemGroupPosition.Last,
),
)
diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/TimelineItemRow.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/TimelineItemRow.kt
index 11d7b91e1e..119a235cf8 100644
--- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/TimelineItemRow.kt
+++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/TimelineItemRow.kt
@@ -30,9 +30,9 @@ import io.element.android.features.messages.impl.timeline.TimelineRoomInfo
import io.element.android.features.messages.impl.timeline.components.event.TimelineItemEventContentView
import io.element.android.features.messages.impl.timeline.components.layout.ContentAvoidingLayoutData
import io.element.android.features.messages.impl.timeline.model.TimelineItem
-import io.element.android.features.messages.impl.timeline.model.event.TimelineItemCallNotifyContent
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemLegacyCallInviteContent
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemPollContent
+import io.element.android.features.messages.impl.timeline.model.event.TimelineItemRtcNotificationContent
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemStateContent
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemVoiceContent
import io.element.android.features.messages.impl.timeline.protection.TimelineProtectionEvent
@@ -123,7 +123,7 @@ internal fun TimelineItemRow(
eventSink = eventSink,
)
}
- is TimelineItemCallNotifyContent -> {
+ is TimelineItemRtcNotificationContent -> {
TimelineItemCallNotifyView(
modifier = Modifier.padding(start = 16.dp, end = 16.dp, top = 16.dp),
event = timelineItem,
diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/event/TimelineItemEventContentView.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/event/TimelineItemEventContentView.kt
index 332f58777c..8660d82e7c 100644
--- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/event/TimelineItemEventContentView.kt
+++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/event/TimelineItemEventContentView.kt
@@ -14,7 +14,6 @@ import io.element.android.features.messages.impl.timeline.components.layout.Cont
import io.element.android.features.messages.impl.timeline.di.LocalTimelineItemPresenterFactories
import io.element.android.features.messages.impl.timeline.di.rememberPresenter
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemAudioContent
-import io.element.android.features.messages.impl.timeline.model.event.TimelineItemCallNotifyContent
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemEncryptedContent
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemEventContent
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemFileContent
@@ -23,6 +22,7 @@ import io.element.android.features.messages.impl.timeline.model.event.TimelineIt
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemLocationContent
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemPollContent
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemRedactedContent
+import io.element.android.features.messages.impl.timeline.model.event.TimelineItemRtcNotificationContent
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemStateContent
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemStickerContent
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemTextBasedContent
@@ -133,6 +133,6 @@ fun TimelineItemEventContentView(
modifier = modifier
)
}
- is TimelineItemCallNotifyContent -> error("This shouldn't be rendered as the content of a bubble")
+ is TimelineItemRtcNotificationContent -> error("This shouldn't be rendered as the content of a bubble")
}
}
diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/factories/event/TimelineItemContentFactory.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/factories/event/TimelineItemContentFactory.kt
index 499c5349ae..8047acd09a 100644
--- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/factories/event/TimelineItemContentFactory.kt
+++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/factories/event/TimelineItemContentFactory.kt
@@ -8,11 +8,14 @@
package io.element.android.features.messages.impl.timeline.factories.event
import dev.zacsweers.metro.Inject
-import io.element.android.features.messages.impl.timeline.model.event.TimelineItemCallNotifyContent
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemEventContent
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemLegacyCallInviteContent
+import io.element.android.features.messages.impl.timeline.model.event.TimelineItemRtcNotificationContent
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemUnknownContent
+import io.element.android.libraries.matrix.api.core.EventId
+import io.element.android.libraries.matrix.api.core.UserId
import io.element.android.libraries.matrix.api.timeline.item.event.CallNotifyContent
+import io.element.android.libraries.matrix.api.timeline.item.event.EventContent
import io.element.android.libraries.matrix.api.timeline.item.event.EventTimelineItem
import io.element.android.libraries.matrix.api.timeline.item.event.FailedToParseMessageLikeContent
import io.element.android.libraries.matrix.api.timeline.item.event.FailedToParseStateContent
@@ -20,6 +23,7 @@ import io.element.android.libraries.matrix.api.timeline.item.event.LegacyCallInv
import io.element.android.libraries.matrix.api.timeline.item.event.MessageContent
import io.element.android.libraries.matrix.api.timeline.item.event.PollContent
import io.element.android.libraries.matrix.api.timeline.item.event.ProfileChangeContent
+import io.element.android.libraries.matrix.api.timeline.item.event.ProfileTimelineDetails
import io.element.android.libraries.matrix.api.timeline.item.event.RedactedContent
import io.element.android.libraries.matrix.api.timeline.item.event.RoomMembershipContent
import io.element.android.libraries.matrix.api.timeline.item.event.StateContent
@@ -27,6 +31,7 @@ import io.element.android.libraries.matrix.api.timeline.item.event.StickerConten
import io.element.android.libraries.matrix.api.timeline.item.event.UnableToDecryptContent
import io.element.android.libraries.matrix.api.timeline.item.event.UnknownContent
import io.element.android.libraries.matrix.api.timeline.item.event.getDisambiguatedDisplayName
+import io.element.android.libraries.matrix.api.user.CurrentSessionIdHolder
@Inject
class TimelineItemContentFactory(
@@ -40,28 +45,55 @@ class TimelineItemContentFactory(
private val stateFactory: TimelineItemContentStateFactory,
private val failedToParseMessageFactory: TimelineItemContentFailedToParseMessageFactory,
private val failedToParseStateFactory: TimelineItemContentFailedToParseStateFactory,
+ private val currentSessionIdHolder: CurrentSessionIdHolder,
) {
suspend fun create(eventTimelineItem: EventTimelineItem): TimelineItemEventContent {
- return when (val itemContent = eventTimelineItem.content) {
+ return create(
+ itemContent = eventTimelineItem.content,
+ eventId = eventTimelineItem.eventId,
+ isEditable = eventTimelineItem.isEditable,
+ sender = eventTimelineItem.sender,
+ senderProfile = eventTimelineItem.senderProfile,
+ )
+ }
+
+ suspend fun create(
+ itemContent: EventContent,
+ eventId: EventId?,
+ isEditable: Boolean,
+ sender: UserId,
+ senderProfile: ProfileTimelineDetails,
+ ): TimelineItemEventContent {
+ val isOutgoing = currentSessionIdHolder.current == sender
+ return when (itemContent) {
is FailedToParseMessageLikeContent -> failedToParseMessageFactory.create(itemContent)
is FailedToParseStateContent -> failedToParseStateFactory.create(itemContent)
is MessageContent -> {
- val senderDisambiguatedDisplayName = eventTimelineItem.senderProfile.getDisambiguatedDisplayName(eventTimelineItem.sender)
+ val senderDisambiguatedDisplayName = senderProfile.getDisambiguatedDisplayName(sender)
messageFactory.create(
content = itemContent,
senderDisambiguatedDisplayName = senderDisambiguatedDisplayName,
- eventId = eventTimelineItem.eventId,
+ eventId = eventId,
)
}
- is ProfileChangeContent -> profileChangeFactory.create(eventTimelineItem)
+ is ProfileChangeContent -> {
+ val senderDisambiguatedDisplayName = senderProfile.getDisambiguatedDisplayName(sender)
+ profileChangeFactory.create(itemContent, isOutgoing, sender, senderDisambiguatedDisplayName)
+ }
is RedactedContent -> redactedMessageFactory.create(itemContent)
- is RoomMembershipContent -> roomMembershipFactory.create(eventTimelineItem)
+ is RoomMembershipContent -> {
+ val senderDisambiguatedDisplayName = senderProfile.getDisambiguatedDisplayName(sender)
+ roomMembershipFactory.create(itemContent, isOutgoing, sender, senderDisambiguatedDisplayName)
+ }
is LegacyCallInviteContent -> TimelineItemLegacyCallInviteContent
- is StateContent -> stateFactory.create(eventTimelineItem)
+ is StateContent -> {
+ val senderDisambiguatedDisplayName = senderProfile.getDisambiguatedDisplayName(sender)
+ stateFactory.create(itemContent, isOutgoing, sender, senderDisambiguatedDisplayName)
+ }
is StickerContent -> stickerFactory.create(itemContent)
- is PollContent -> pollFactory.create(eventTimelineItem, itemContent)
+ is PollContent -> pollFactory.create(eventId, isEditable, isOutgoing, itemContent)
is UnableToDecryptContent -> utdFactory.create(itemContent)
- is CallNotifyContent -> TimelineItemCallNotifyContent()
+ is CallNotifyContent -> TimelineItemRtcNotificationContent()
is UnknownContent -> TimelineItemUnknownContent
}
}
diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/factories/event/TimelineItemContentPollFactory.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/factories/event/TimelineItemContentPollFactory.kt
index bb2f7fe138..ec2eba6544 100644
--- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/factories/event/TimelineItemContentPollFactory.kt
+++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/factories/event/TimelineItemContentPollFactory.kt
@@ -11,7 +11,7 @@ import dev.zacsweers.metro.Inject
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemEventContent
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemPollContent
import io.element.android.features.poll.api.pollcontent.PollContentStateFactory
-import io.element.android.libraries.matrix.api.timeline.item.event.EventTimelineItem
+import io.element.android.libraries.matrix.api.core.EventId
import io.element.android.libraries.matrix.api.timeline.item.event.PollContent
@Inject
@@ -19,14 +19,16 @@ class TimelineItemContentPollFactory(
private val pollContentStateFactory: PollContentStateFactory,
) {
suspend fun create(
- event: EventTimelineItem,
+ eventId: EventId?,
+ isEditable: Boolean,
+ isOwn: Boolean,
content: PollContent,
): TimelineItemEventContent {
- val pollContentState = pollContentStateFactory.create(event, content)
+ val pollContentState = pollContentStateFactory.create(eventId, isEditable, isOwn, content)
return TimelineItemPollContent(
isMine = pollContentState.isMine,
isEditable = pollContentState.isPollEditable,
- eventId = event.eventId,
+ eventId = eventId,
question = pollContentState.question,
answerItems = pollContentState.answerItems,
pollKind = pollContentState.pollKind,
diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/factories/event/TimelineItemContentProfileChangeFactory.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/factories/event/TimelineItemContentProfileChangeFactory.kt
index b01a19bf41..a0a0b1f357 100644
--- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/factories/event/TimelineItemContentProfileChangeFactory.kt
+++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/factories/event/TimelineItemContentProfileChangeFactory.kt
@@ -12,14 +12,15 @@ import io.element.android.features.messages.impl.timeline.model.event.TimelineIt
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemProfileChangeContent
import io.element.android.libraries.core.extensions.orEmpty
import io.element.android.libraries.eventformatter.api.TimelineEventFormatter
-import io.element.android.libraries.matrix.api.timeline.item.event.EventTimelineItem
+import io.element.android.libraries.matrix.api.core.UserId
+import io.element.android.libraries.matrix.api.timeline.item.event.EventContent
@Inject
class TimelineItemContentProfileChangeFactory(
private val timelineEventFormatter: TimelineEventFormatter,
) {
- fun create(eventTimelineItem: EventTimelineItem): TimelineItemEventContent {
- val text = timelineEventFormatter.format(eventTimelineItem)
+ fun create(content: EventContent, isOutgoing: Boolean, sender: UserId, senderDisambiguatedDisplayName: String): TimelineItemEventContent {
+ val text = timelineEventFormatter.format(content, isOutgoing, sender, senderDisambiguatedDisplayName)
return TimelineItemProfileChangeContent(text.orEmpty().toString())
}
}
diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/factories/event/TimelineItemContentRoomMembershipFactory.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/factories/event/TimelineItemContentRoomMembershipFactory.kt
index 3fbd7357e6..a602e5274b 100644
--- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/factories/event/TimelineItemContentRoomMembershipFactory.kt
+++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/factories/event/TimelineItemContentRoomMembershipFactory.kt
@@ -12,14 +12,15 @@ import io.element.android.features.messages.impl.timeline.model.event.TimelineIt
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemRoomMembershipContent
import io.element.android.libraries.core.extensions.orEmpty
import io.element.android.libraries.eventformatter.api.TimelineEventFormatter
-import io.element.android.libraries.matrix.api.timeline.item.event.EventTimelineItem
+import io.element.android.libraries.matrix.api.core.UserId
+import io.element.android.libraries.matrix.api.timeline.item.event.EventContent
@Inject
class TimelineItemContentRoomMembershipFactory(
private val timelineEventFormatter: TimelineEventFormatter,
) {
- fun create(eventTimelineItem: EventTimelineItem): TimelineItemEventContent {
- val text = timelineEventFormatter.format(eventTimelineItem)
+ fun create(eventContent: EventContent, isOutgoing: Boolean, sender: UserId, senderDisambiguatedDisplayName: String): TimelineItemEventContent {
+ val text = timelineEventFormatter.format(eventContent, isOutgoing, sender, senderDisambiguatedDisplayName)
return TimelineItemRoomMembershipContent(text.orEmpty().toString())
}
}
diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/factories/event/TimelineItemContentStateFactory.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/factories/event/TimelineItemContentStateFactory.kt
index 38d41f9341..6716a7ff83 100644
--- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/factories/event/TimelineItemContentStateFactory.kt
+++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/factories/event/TimelineItemContentStateFactory.kt
@@ -12,14 +12,15 @@ import io.element.android.features.messages.impl.timeline.model.event.TimelineIt
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemStateEventContent
import io.element.android.libraries.core.extensions.orEmpty
import io.element.android.libraries.eventformatter.api.TimelineEventFormatter
-import io.element.android.libraries.matrix.api.timeline.item.event.EventTimelineItem
+import io.element.android.libraries.matrix.api.core.UserId
+import io.element.android.libraries.matrix.api.timeline.item.event.EventContent
@Inject
class TimelineItemContentStateFactory(
private val timelineEventFormatter: TimelineEventFormatter,
) {
- fun create(eventTimelineItem: EventTimelineItem): TimelineItemEventContent {
- val text = timelineEventFormatter.format(eventTimelineItem)
+ fun create(eventContent: EventContent, isOutgoing: Boolean, sender: UserId, senderDisambiguatedDisplayName: String): TimelineItemEventContent {
+ val text = timelineEventFormatter.format(eventContent, isOutgoing, sender, senderDisambiguatedDisplayName)
return TimelineItemStateEventContent(text.orEmpty().toString())
}
}
diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/factories/event/TimelineItemEventFactory.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/factories/event/TimelineItemEventFactory.kt
index 814f966f8b..d3b3c5d679 100644
--- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/factories/event/TimelineItemEventFactory.kt
+++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/factories/event/TimelineItemEventFactory.kt
@@ -19,6 +19,9 @@ import io.element.android.features.messages.impl.timeline.model.TimelineItem
import io.element.android.features.messages.impl.timeline.model.TimelineItemGroupPosition
import io.element.android.features.messages.impl.timeline.model.TimelineItemReactions
import io.element.android.features.messages.impl.timeline.model.TimelineItemReadReceipts
+import io.element.android.features.messages.impl.timeline.model.TimelineItemThreadInfo
+import io.element.android.features.messages.impl.utils.messagesummary.MessageSummaryFormatter
+import io.element.android.libraries.architecture.map
import io.element.android.libraries.core.bool.orTrue
import io.element.android.libraries.dateformatter.api.DateFormatter
import io.element.android.libraries.dateformatter.api.DateFormatterMode
@@ -43,6 +46,7 @@ class TimelineItemEventFactory(
private val matrixClient: MatrixClient,
private val dateFormatter: DateFormatter,
private val permalinkParser: PermalinkParser,
+ private val summaryFormatter: MessageSummaryFormatter,
) {
@AssistedFactory
interface Creator {
@@ -69,6 +73,29 @@ class TimelineItemEventFactory(
url = senderProfile.getAvatarUrl(),
size = AvatarSize.TimelineSender
)
+ val mappedThreadInfo = when (val threadInfo = currentTimelineItem.event.threadInfo()) {
+ is EventThreadInfo.ThreadResponse -> {
+ TimelineItemThreadInfo.ThreadResponse(threadInfo.threadRootId)
+ }
+ is EventThreadInfo.ThreadRoot -> {
+ TimelineItemThreadInfo.ThreadRoot(
+ summary = threadInfo.summary,
+ latestEventText = threadInfo.summary.latestEvent.dataOrNull()
+ ?.let {
+ contentFactory.create(
+ itemContent = it.content,
+ eventId = it.eventOrTransactionId.eventId,
+ isEditable = false,
+ sender = it.senderId,
+ senderProfile = it.senderProfile,
+ )
+ }
+ ?.let(summaryFormatter::format)
+ )
+ }
+ null -> null
+ }
+
return TimelineItem.Event(
id = currentTimelineItem.uniqueId,
eventId = currentTimelineItem.eventId,
@@ -87,7 +114,7 @@ class TimelineItemEventFactory(
readReceiptState = currentTimelineItem.computeReadReceiptState(roomMembers),
localSendState = currentTimelineItem.event.localSendState,
inReplyTo = currentTimelineItem.event.inReplyTo()?.map(permalinkParser = permalinkParser),
- threadInfo = currentTimelineItem.event.threadInfo() ?: EventThreadInfo(threadRootId = null, threadSummary = null),
+ threadInfo = mappedThreadInfo,
origin = currentTimelineItem.event.origin,
timelineItemDebugInfoProvider = currentTimelineItem.event.timelineItemDebugInfoProvider,
messageShieldProvider = currentTimelineItem.event.messageShieldProvider,
diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/groups/Groupability.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/groups/Groupability.kt
index 67a4d3da0d..a56a4d09e9 100644
--- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/groups/Groupability.kt
+++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/groups/Groupability.kt
@@ -9,7 +9,6 @@ package io.element.android.features.messages.impl.timeline.groups
import io.element.android.features.messages.impl.timeline.model.TimelineItem
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemAudioContent
-import io.element.android.features.messages.impl.timeline.model.event.TimelineItemCallNotifyContent
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemEncryptedContent
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemFileContent
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemImageContent
@@ -19,6 +18,7 @@ import io.element.android.features.messages.impl.timeline.model.event.TimelineIt
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemProfileChangeContent
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemRedactedContent
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemRoomMembershipContent
+import io.element.android.features.messages.impl.timeline.model.event.TimelineItemRtcNotificationContent
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemStateEventContent
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemStickerContent
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemTextBasedContent
@@ -60,7 +60,7 @@ internal fun TimelineItem.Event.canBeGrouped(): Boolean {
TimelineItemRedactedContent,
TimelineItemUnknownContent,
is TimelineItemLegacyCallInviteContent,
- is TimelineItemCallNotifyContent -> false
+ is TimelineItemRtcNotificationContent -> false
is TimelineItemProfileChangeContent,
is TimelineItemRoomMembershipContent,
is TimelineItemStateEventContent -> true
diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/model/TimelineItem.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/model/TimelineItem.kt
index 94e04dd1d8..5591616517 100644
--- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/model/TimelineItem.kt
+++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/model/TimelineItem.kt
@@ -17,10 +17,11 @@ import io.element.android.features.messages.impl.timeline.model.virtual.Timeline
import io.element.android.libraries.designsystem.components.avatar.AvatarData
import io.element.android.libraries.matrix.api.core.EventId
import io.element.android.libraries.matrix.api.core.SendHandle
+import io.element.android.libraries.matrix.api.core.ThreadId
import io.element.android.libraries.matrix.api.core.TransactionId
import io.element.android.libraries.matrix.api.core.UniqueId
import io.element.android.libraries.matrix.api.core.UserId
-import io.element.android.libraries.matrix.api.timeline.item.EventThreadInfo
+import io.element.android.libraries.matrix.api.timeline.item.ThreadSummary
import io.element.android.libraries.matrix.api.timeline.item.TimelineItemDebugInfo
import io.element.android.libraries.matrix.api.timeline.item.event.EventOrTransactionId
import io.element.android.libraries.matrix.api.timeline.item.event.LocalEventSendState
@@ -82,7 +83,7 @@ sealed interface TimelineItem {
val readReceiptState: TimelineItemReadReceipts,
val localSendState: LocalEventSendState?,
val inReplyTo: InReplyToDetails?,
- val threadInfo: EventThreadInfo,
+ val threadInfo: TimelineItemThreadInfo?,
val origin: TimelineItemEventOrigin?,
val timelineItemDebugInfoProvider: TimelineItemDebugInfoProvider,
val messageShieldProvider: MessageShieldProvider,
@@ -130,3 +131,8 @@ sealed interface TimelineItem {
val aggregatedReadReceipts: ImmutableList,
) : TimelineItem
}
+
+sealed interface TimelineItemThreadInfo {
+ data class ThreadRoot(val summary: ThreadSummary, val latestEventText: String?) : TimelineItemThreadInfo
+ data class ThreadResponse(val threadRootId: ThreadId) : TimelineItemThreadInfo
+}
diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/model/event/TimelineItemEventContent.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/model/event/TimelineItemEventContent.kt
index d011865964..be7c47439a 100644
--- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/model/event/TimelineItemEventContent.kt
+++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/model/event/TimelineItemEventContent.kt
@@ -81,7 +81,7 @@ fun TimelineItemEventContent.canReact(): Boolean =
is TimelineItemStateContent,
is TimelineItemRedactedContent,
is TimelineItemLegacyCallInviteContent,
- is TimelineItemCallNotifyContent,
+ is TimelineItemRtcNotificationContent,
TimelineItemUnknownContent -> false
}
diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/model/event/TimelineItemCallNotifyContent.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/model/event/TimelineItemRtcNotificationContent.kt
similarity index 65%
rename from features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/model/event/TimelineItemCallNotifyContent.kt
rename to features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/model/event/TimelineItemRtcNotificationContent.kt
index 75d070d025..0c2f21fc5b 100644
--- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/model/event/TimelineItemCallNotifyContent.kt
+++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/model/event/TimelineItemRtcNotificationContent.kt
@@ -7,6 +7,6 @@
package io.element.android.features.messages.impl.timeline.model.event
-class TimelineItemCallNotifyContent : TimelineItemEventContent {
- override val type: String = "m.call.notify"
+class TimelineItemRtcNotificationContent : TimelineItemEventContent {
+ override val type: String = "org.matrix.msc4075.rtc.notification"
}
diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/protection/TimelineItem.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/protection/TimelineItem.kt
index 279a542081..1f306c74ea 100644
--- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/protection/TimelineItem.kt
+++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/protection/TimelineItem.kt
@@ -9,7 +9,6 @@ package io.element.android.features.messages.impl.timeline.protection
import io.element.android.features.messages.impl.timeline.model.TimelineItem
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemAudioContent
-import io.element.android.features.messages.impl.timeline.model.event.TimelineItemCallNotifyContent
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemEmoteContent
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemEncryptedContent
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemFileContent
@@ -21,6 +20,7 @@ import io.element.android.features.messages.impl.timeline.model.event.TimelineIt
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemProfileChangeContent
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemRedactedContent
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemRoomMembershipContent
+import io.element.android.features.messages.impl.timeline.model.event.TimelineItemRtcNotificationContent
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemStateEventContent
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemStickerContent
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemTextContent
@@ -38,7 +38,7 @@ fun TimelineItem.mustBeProtected(): Boolean {
is TimelineItemVideoContent,
is TimelineItemStickerContent -> true
is TimelineItemAudioContent,
- is TimelineItemCallNotifyContent,
+ is TimelineItemRtcNotificationContent,
is TimelineItemEncryptedContent,
is TimelineItemFileContent,
TimelineItemLegacyCallInviteContent,
diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/topbars/MessagesViewTopBar.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/topbars/MessagesViewTopBar.kt
new file mode 100644
index 0000000000..62c9c3e206
--- /dev/null
+++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/topbars/MessagesViewTopBar.kt
@@ -0,0 +1,211 @@
+/*
+ * Copyright 2025 New Vector Ltd.
+ *
+ * SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial
+ * Please see LICENSE files in the repository root for full details.
+ */
+
+package io.element.android.features.messages.impl.topbars
+
+import androidx.compose.foundation.clickable
+import androidx.compose.foundation.layout.Arrangement
+import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.Row
+import androidx.compose.foundation.layout.Spacer
+import androidx.compose.foundation.layout.WindowInsets
+import androidx.compose.foundation.layout.padding
+import androidx.compose.foundation.layout.width
+import androidx.compose.foundation.shape.RoundedCornerShape
+import androidx.compose.material3.ExperimentalMaterial3Api
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.Alignment
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.draw.clip
+import androidx.compose.ui.res.stringResource
+import androidx.compose.ui.semantics.heading
+import androidx.compose.ui.semantics.semantics
+import androidx.compose.ui.text.font.FontStyle
+import androidx.compose.ui.text.style.TextOverflow
+import androidx.compose.ui.unit.dp
+import io.element.android.compound.theme.ElementTheme
+import io.element.android.compound.tokens.generated.CompoundIcons
+import io.element.android.features.messages.impl.timeline.components.CallMenuItem
+import io.element.android.features.roomcall.api.RoomCallState
+import io.element.android.features.roomcall.api.aStandByCallState
+import io.element.android.features.roomcall.api.anOngoingCallState
+import io.element.android.libraries.designsystem.components.avatar.Avatar
+import io.element.android.libraries.designsystem.components.avatar.AvatarData
+import io.element.android.libraries.designsystem.components.avatar.AvatarSize
+import io.element.android.libraries.designsystem.components.avatar.AvatarType
+import io.element.android.libraries.designsystem.components.avatar.anAvatarData
+import io.element.android.libraries.designsystem.components.button.BackButton
+import io.element.android.libraries.designsystem.preview.ElementPreview
+import io.element.android.libraries.designsystem.preview.PreviewsDayNight
+import io.element.android.libraries.designsystem.theme.components.HorizontalDivider
+import io.element.android.libraries.designsystem.theme.components.Icon
+import io.element.android.libraries.designsystem.theme.components.Text
+import io.element.android.libraries.designsystem.theme.components.TopAppBar
+import io.element.android.libraries.matrix.api.encryption.identity.IdentityState
+import io.element.android.libraries.matrix.ui.components.aMatrixUserList
+import io.element.android.libraries.matrix.ui.model.getAvatarData
+import io.element.android.libraries.ui.strings.CommonStrings
+import kotlinx.collections.immutable.ImmutableList
+import kotlinx.collections.immutable.persistentListOf
+import kotlinx.collections.immutable.toImmutableList
+
+@OptIn(ExperimentalMaterial3Api::class)
+@Composable
+internal fun MessagesViewTopBar(
+ roomName: String?,
+ roomAvatar: AvatarData,
+ isTombstoned: Boolean,
+ heroes: ImmutableList,
+ roomCallState: RoomCallState,
+ dmUserIdentityState: IdentityState?,
+ onRoomDetailsClick: () -> Unit,
+ onJoinCallClick: () -> Unit,
+ onBackClick: () -> Unit,
+ modifier: Modifier = Modifier,
+) {
+ TopAppBar(
+ modifier = modifier,
+ navigationIcon = {
+ BackButton(onClick = onBackClick)
+ },
+ title = {
+ val roundedCornerShape = RoundedCornerShape(8.dp)
+ Row(
+ modifier = Modifier
+ .clip(roundedCornerShape)
+ .clickable { onRoomDetailsClick() },
+ horizontalArrangement = Arrangement.spacedBy(4.dp),
+ verticalAlignment = Alignment.CenterVertically,
+ ) {
+ val titleModifier = Modifier.weight(1f, fill = false)
+ RoomAvatarAndNameRow(
+ roomName = roomName,
+ roomAvatar = roomAvatar,
+ isTombstoned = isTombstoned,
+ heroes = heroes,
+ modifier = titleModifier
+ )
+
+ when (dmUserIdentityState) {
+ IdentityState.Verified -> {
+ Icon(
+ imageVector = CompoundIcons.Verified(),
+ tint = ElementTheme.colors.iconSuccessPrimary,
+ contentDescription = null,
+ )
+ }
+ IdentityState.VerificationViolation -> {
+ Icon(
+ imageVector = CompoundIcons.ErrorSolid(),
+ tint = ElementTheme.colors.iconCriticalPrimary,
+ contentDescription = null,
+ )
+ }
+ else -> Unit
+ }
+ }
+ },
+ actions = {
+ CallMenuItem(
+ roomCallState = roomCallState,
+ onJoinCallClick = onJoinCallClick,
+ )
+ Spacer(Modifier.width(8.dp))
+ },
+ windowInsets = WindowInsets(0.dp)
+ )
+}
+
+@Composable
+private fun RoomAvatarAndNameRow(
+ roomName: String?,
+ roomAvatar: AvatarData,
+ heroes: ImmutableList,
+ isTombstoned: Boolean,
+ modifier: Modifier = Modifier
+) {
+ Row(
+ modifier = modifier,
+ verticalAlignment = Alignment.CenterVertically
+ ) {
+ Avatar(
+ avatarData = roomAvatar,
+ avatarType = AvatarType.Room(
+ heroes = heroes,
+ isTombstoned = isTombstoned,
+ ),
+ )
+ Text(
+ modifier = Modifier
+ .padding(horizontal = 8.dp)
+ .semantics {
+ heading()
+ },
+ text = roomName ?: stringResource(CommonStrings.common_no_room_name),
+ style = ElementTheme.typography.fontBodyLgMedium,
+ fontStyle = FontStyle.Italic.takeIf { roomName == null },
+ maxLines = 1,
+ overflow = TextOverflow.Ellipsis
+ )
+ }
+}
+
+@PreviewsDayNight
+@Composable
+internal fun MessagesViewTopBarPreview() = ElementPreview {
+ @Composable
+ fun AMessagesViewTopBar(
+ roomName: String? = "Room name",
+ roomAvatar: AvatarData = anAvatarData(
+ name = "Room name",
+ size = AvatarSize.TimelineRoom,
+ ),
+ isTombstoned: Boolean = false,
+ heroes: ImmutableList = persistentListOf(),
+ roomCallState: RoomCallState = RoomCallState.Unavailable,
+ dmUserIdentityState: IdentityState? = null,
+ ) = MessagesViewTopBar(
+ roomName = roomName,
+ roomAvatar = roomAvatar,
+ isTombstoned = isTombstoned,
+ heroes = heroes,
+ roomCallState = roomCallState,
+ dmUserIdentityState = dmUserIdentityState,
+ onRoomDetailsClick = {},
+ onJoinCallClick = {},
+ onBackClick = {},
+ )
+ Column {
+ AMessagesViewTopBar()
+ HorizontalDivider()
+ AMessagesViewTopBar(
+ heroes = aMatrixUserList().map { it.getAvatarData(AvatarSize.TimelineRoom) }.toImmutableList(),
+ roomCallState = anOngoingCallState(),
+ )
+ HorizontalDivider()
+ AMessagesViewTopBar(
+ roomName = null,
+ roomCallState = anOngoingCallState(canJoinCall = false),
+ )
+ HorizontalDivider()
+ AMessagesViewTopBar(
+ roomName = "A DM with a very very very long name",
+ roomAvatar = anAvatarData(
+ size = AvatarSize.TimelineRoom,
+ url = "https://some-avatar.jpg"
+ ),
+ roomCallState = aStandByCallState(canStartCall = false),
+ dmUserIdentityState = IdentityState.Verified
+ )
+ HorizontalDivider()
+ AMessagesViewTopBar(
+ roomName = "A DM with a very very very long name",
+ isTombstoned = true,
+ dmUserIdentityState = IdentityState.VerificationViolation
+ )
+ }
+}
diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/topbars/ThreadTopBar.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/topbars/ThreadTopBar.kt
new file mode 100644
index 0000000000..5a95c2c4b2
--- /dev/null
+++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/topbars/ThreadTopBar.kt
@@ -0,0 +1,135 @@
+/*
+ * Copyright 2025 New Vector Ltd.
+ *
+ * SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial
+ * Please see LICENSE files in the repository root for full details.
+ */
+
+package io.element.android.features.messages.impl.topbars
+
+import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.Row
+import androidx.compose.foundation.layout.fillMaxWidth
+import androidx.compose.foundation.layout.padding
+import androidx.compose.material3.ExperimentalMaterial3Api
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.Alignment
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.res.stringResource
+import androidx.compose.ui.semantics.heading
+import androidx.compose.ui.semantics.semantics
+import androidx.compose.ui.text.font.FontStyle
+import androidx.compose.ui.text.style.TextOverflow
+import androidx.compose.ui.unit.dp
+import io.element.android.compound.theme.ElementTheme
+import io.element.android.libraries.designsystem.components.avatar.Avatar
+import io.element.android.libraries.designsystem.components.avatar.AvatarData
+import io.element.android.libraries.designsystem.components.avatar.AvatarSize
+import io.element.android.libraries.designsystem.components.avatar.AvatarType
+import io.element.android.libraries.designsystem.components.avatar.anAvatarData
+import io.element.android.libraries.designsystem.components.button.BackButton
+import io.element.android.libraries.designsystem.preview.ElementPreview
+import io.element.android.libraries.designsystem.preview.PreviewsDayNight
+import io.element.android.libraries.designsystem.theme.components.HorizontalDivider
+import io.element.android.libraries.designsystem.theme.components.Text
+import io.element.android.libraries.designsystem.theme.components.TopAppBar
+import io.element.android.libraries.matrix.ui.components.aMatrixUserList
+import io.element.android.libraries.matrix.ui.model.getAvatarData
+import io.element.android.libraries.ui.strings.CommonStrings
+import kotlinx.collections.immutable.ImmutableList
+import kotlinx.collections.immutable.persistentListOf
+import kotlinx.collections.immutable.toImmutableList
+
+@OptIn(ExperimentalMaterial3Api::class)
+@Composable
+internal fun ThreadTopBar(
+ roomName: String?,
+ roomAvatarData: AvatarData,
+ heroes: ImmutableList,
+ isTombstoned: Boolean,
+ onBackClick: () -> Unit,
+ modifier: Modifier = Modifier,
+) {
+ TopAppBar(
+ modifier = modifier,
+ navigationIcon = {
+ BackButton(onClick = onBackClick)
+ },
+ title = {
+ Row(verticalAlignment = Alignment.CenterVertically) {
+ Avatar(
+ avatarData = roomAvatarData,
+ avatarType = AvatarType.Room(
+ heroes = heroes,
+ isTombstoned = isTombstoned,
+ ),
+ )
+ Column(
+ modifier = Modifier
+ .fillMaxWidth()
+ .padding(horizontal = 8.dp)
+ .semantics {
+ heading()
+ },
+ ) {
+ Text(
+ text = stringResource(CommonStrings.common_thread),
+ style = ElementTheme.typography.fontBodyLgMedium,
+ )
+ Text(
+ text = roomName ?: stringResource(CommonStrings.common_no_room_name),
+ style = ElementTheme.typography.fontBodySmRegular,
+ fontStyle = FontStyle.Italic.takeIf { roomName == null },
+ color = ElementTheme.colors.textSecondary,
+ maxLines = 1,
+ overflow = TextOverflow.Ellipsis
+ )
+ }
+ }
+ }
+ )
+}
+
+@PreviewsDayNight
+@Composable
+internal fun ThreadTopBarPreview() = ElementPreview {
+ @Composable
+ fun AThreadTopBar(
+ roomName: String? = "Room name",
+ roomAvatarData: AvatarData = anAvatarData(
+ name = "Room name",
+ size = AvatarSize.TimelineRoom,
+ ),
+ isTombstoned: Boolean = false,
+ heroes: ImmutableList = persistentListOf(),
+ ) = ThreadTopBar(
+ roomName = roomName,
+ roomAvatarData = roomAvatarData,
+ isTombstoned = isTombstoned,
+ heroes = heroes,
+ onBackClick = {},
+ )
+ Column {
+ AThreadTopBar()
+ HorizontalDivider()
+ AThreadTopBar(
+ heroes = aMatrixUserList().map { it.getAvatarData(AvatarSize.TimelineRoom) }.toImmutableList(),
+ )
+ HorizontalDivider()
+ AThreadTopBar(
+ roomName = null,
+ )
+ HorizontalDivider()
+ AThreadTopBar(
+ roomAvatarData = anAvatarData(
+ name = "Room name",
+ url = "https://some-avatar.jpg",
+ size = AvatarSize.TimelineRoom,
+ ),
+ )
+ HorizontalDivider()
+ AThreadTopBar(
+ isTombstoned = true,
+ )
+ }
+}
diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/utils/messagesummary/DefaultMessageSummaryFormatter.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/utils/messagesummary/DefaultMessageSummaryFormatter.kt
index aacdfeb0e8..1f1619e3f6 100644
--- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/utils/messagesummary/DefaultMessageSummaryFormatter.kt
+++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/utils/messagesummary/DefaultMessageSummaryFormatter.kt
@@ -10,10 +10,9 @@ package io.element.android.features.messages.impl.utils.messagesummary
import android.content.Context
import dev.zacsweers.metro.ContributesBinding
import dev.zacsweers.metro.Inject
-import io.element.android.features.messages.impl.timeline.model.TimelineItem
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemAudioContent
-import io.element.android.features.messages.impl.timeline.model.event.TimelineItemCallNotifyContent
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemEncryptedContent
+import io.element.android.features.messages.impl.timeline.model.event.TimelineItemEventContent
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemFileContent
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemImageContent
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemLegacyCallInviteContent
@@ -21,6 +20,7 @@ import io.element.android.features.messages.impl.timeline.model.event.TimelineIt
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemPollContent
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemProfileChangeContent
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemRedactedContent
+import io.element.android.features.messages.impl.timeline.model.event.TimelineItemRtcNotificationContent
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemStateContent
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemStickerContent
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemTextBasedContent
@@ -37,15 +37,15 @@ import io.element.android.libraries.ui.strings.CommonStrings
class DefaultMessageSummaryFormatter(
@ApplicationContext private val context: Context,
) : MessageSummaryFormatter {
- override fun format(event: TimelineItem.Event): String {
- return when (event.content) {
- is TimelineItemTextBasedContent -> event.content.plainText
- is TimelineItemProfileChangeContent -> event.content.body
- is TimelineItemStateContent -> event.content.body
+ override fun format(content: TimelineItemEventContent): String {
+ return when (content) {
+ is TimelineItemTextBasedContent -> content.plainText
+ is TimelineItemProfileChangeContent -> content.body
+ is TimelineItemStateContent -> content.body
is TimelineItemLocationContent -> context.getString(CommonStrings.common_shared_location)
is TimelineItemEncryptedContent -> context.getString(CommonStrings.common_unable_to_decrypt)
is TimelineItemRedactedContent -> context.getString(CommonStrings.common_message_removed)
- is TimelineItemPollContent -> event.content.question
+ is TimelineItemPollContent -> content.question
is TimelineItemVoiceContent -> context.getString(CommonStrings.common_voice_message)
is TimelineItemUnknownContent -> context.getString(CommonStrings.common_unsupported_event)
is TimelineItemImageContent -> context.getString(CommonStrings.common_image)
@@ -54,7 +54,7 @@ class DefaultMessageSummaryFormatter(
is TimelineItemFileContent -> context.getString(CommonStrings.common_file)
is TimelineItemAudioContent -> context.getString(CommonStrings.common_audio)
is TimelineItemLegacyCallInviteContent -> context.getString(CommonStrings.common_unsupported_call)
- is TimelineItemCallNotifyContent -> context.getString(CommonStrings.common_call_started)
+ is TimelineItemRtcNotificationContent -> context.getString(CommonStrings.common_call_started)
}
// Truncate the message to a safe length to avoid crashes in Compose
.toSafeLength()
diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/utils/messagesummary/MessageSummaryFormatter.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/utils/messagesummary/MessageSummaryFormatter.kt
index 393ed21fa5..6e590c8779 100644
--- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/utils/messagesummary/MessageSummaryFormatter.kt
+++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/utils/messagesummary/MessageSummaryFormatter.kt
@@ -8,7 +8,11 @@
package io.element.android.features.messages.impl.utils.messagesummary
import io.element.android.features.messages.impl.timeline.model.TimelineItem
+import io.element.android.features.messages.impl.timeline.model.event.TimelineItemEventContent
interface MessageSummaryFormatter {
- fun format(event: TimelineItem.Event): String
+ fun format(event: TimelineItem.Event): String {
+ return format(event.content)
+ }
+ fun format(content: TimelineItemEventContent): String
}
diff --git a/features/messages/impl/src/main/res/values-cs/translations.xml b/features/messages/impl/src/main/res/values-cs/translations.xml
index a725337d8e..3b9ffb42a3 100644
--- a/features/messages/impl/src/main/res/values-cs/translations.xml
+++ b/features/messages/impl/src/main/res/values-cs/translations.xml
@@ -7,6 +7,7 @@
"Předměty"
"Smajlíci a lidé"
"Cestování a místa"
+ "Nedávné emotikony"
"Symboly"
"Titulky nemusí být viditelné pro lidi, kteří používají starší aplikace."
"Klepnutím změníte kvalitu nahrávání videa"
@@ -15,6 +16,7 @@
"Nahrání média se nezdařilo, zkuste to prosím znovu."
"Maximální povolená velikost souboru je %1$s."
"Soubor je pro nahrání příliš velký."
+ "Položka %1$d z %2$d"
"Optimalizace kvality obrazu"
"Probíhá zpracování…"
"Zablokovat uživatele"
diff --git a/features/messages/impl/src/main/res/values-cy/translations.xml b/features/messages/impl/src/main/res/values-cy/translations.xml
index 16841b55f6..5591e3abd7 100644
--- a/features/messages/impl/src/main/res/values-cy/translations.xml
+++ b/features/messages/impl/src/main/res/values-cy/translations.xml
@@ -7,10 +7,18 @@
"Gwrthrychau"
"Wynebau Hapus a Phobl"
"Teithio a Llefydd"
+ "Emojis diweddar"
"Symbolau"
"Efallai na fydd capsiynau yn weladwy i bobl sy\'n defnyddio apiau hŷn."
+ "Tapiwch i newid ansawdd llwytho\'r fideo"
+ "Nid oedd modd llwytho\'r ffeil."
"Wedi methu â phrosesu cyfryngau i\'w llwytho, ceisiwch eto."
"Wedi methu llwytho cyfryngau, ceisiwch eto."
+ "Y maint ffeil mwyaf a ganiateir yw %1$s ."
+ "Mae\'r ffeil yn rhy fawr i\'w llwytho"
+ "Eitem %1$d o %2$d"
+ "Optimeiddio ansawdd delwedd"
+ "Prosesu…"
"Rhwystro defnyddiwr"
"Gwiriwch a ydych am guddio\'r holl negeseuon presennol ac yn y dyfodol gan y defnyddiwr hwn"
"Bydd y neges hon yn cael ei hadrodd i weinyddwr eich gweinyddwr cartref. Fyddan nhw ddim yn gallu darllen unrhyw negeseuon wedi\'u hamgryptio."
@@ -38,6 +46,14 @@
"Dangos llai"
"Neges wedi\'i chopïo"
"Does gennych chi ddim caniatâd i bostio i\'r ystafell hon"
+
+ - "Ymatebodd %1$d aelodau gyda %2$s"
+ - "Ymatebodd %1$d aelodau gyda %2$s"
+ - "Ymatebodd %1$d aelod gyda %2$s"
+ - "Ymatebodd %1$d aelod gyda %2$s"
+ - "Ymatebodd %1$d aelod gyda %2$s"
+ - "Ymatebodd %1$d aelod gyda %2$s"
+
"Rydych chi wedi ymateb gyda %1$s"
"Dangos llai"
"Dangos rhagor"
diff --git a/features/messages/impl/src/main/res/values-eo/translations.xml b/features/messages/impl/src/main/res/values-eo/translations.xml
new file mode 100644
index 0000000000..a0810ca15b
--- /dev/null
+++ b/features/messages/impl/src/main/res/values-eo/translations.xml
@@ -0,0 +1,4 @@
+
+
+ "Message history is unavailable in this room. Confirm this device to see your message history."
+
diff --git a/features/messages/impl/src/main/res/values-fi/translations.xml b/features/messages/impl/src/main/res/values-fi/translations.xml
index 0f4a273f0f..3e1af3ce01 100644
--- a/features/messages/impl/src/main/res/values-fi/translations.xml
+++ b/features/messages/impl/src/main/res/values-fi/translations.xml
@@ -7,13 +7,17 @@
"Esineet"
"Hymiöt ja ihmiset"
"Matkustaminen ja paikat"
+ "Viimeaikaiset emojit"
"Symbolit"
"Kuvatekstit eivät välttämättä näy ihmisille, jotka käyttävät vanhempia sovelluksia."
+ "Napauta muuttaaksesi videon lähetyslaatua"
"Tiedostoa ei voitu lähettää."
"Median käsittely epäonnistui, yritä uudelleen."
"Median lähettäminen epäonnistui, yritä uudelleen."
"Suurin sallittu tiedostokoko on %1$s."
"Tiedosto on liian suuri lähetettäväksi"
+ "Optimoi kuvanlaatu"
+ "Käsitellään…"
"Estä käyttäjä"
"Valitse tämä, jos haluat piilottaa kaikki nykyiset ja tulevat viestit tältä käyttäjältä"
"Tämä viesti ilmoitetaan kotipalvelimesi ylläpitäjälle. Ylläpitäjä ei pysty lukemaan salattuja viestejä."
diff --git a/features/messages/impl/src/main/res/values-zh-rTW/translations.xml b/features/messages/impl/src/main/res/values-zh-rTW/translations.xml
index 7854d5a0f3..6abf951e4f 100644
--- a/features/messages/impl/src/main/res/values-zh-rTW/translations.xml
+++ b/features/messages/impl/src/main/res/values-zh-rTW/translations.xml
@@ -9,11 +9,14 @@
"旅行與景點"
"標誌"
"使用舊應用程式的使用者可能看不到標題。"
+ "輕點即可變更影片上傳品質"
"無法上傳檔案。"
"無法處理要上傳的媒體,請再試一次。"
"無法上傳媒體檔案,請稍後再試。"
"允許的最大檔案大小為 %1$s。"
"檔案太大,無法上傳"
+ "最佳化影像品質"
+ "正在處理……"
"封鎖使用者"
"檢查您是否要隱藏所有來自此使用者的目前及未來的訊息"
"此訊息將會回報給您的家伺服器管理員。他們將無法讀取任何已加密的訊息。"
diff --git a/features/messages/impl/src/main/res/values/localazy.xml b/features/messages/impl/src/main/res/values/localazy.xml
index dc9e2a1892..7b0827d792 100644
--- a/features/messages/impl/src/main/res/values/localazy.xml
+++ b/features/messages/impl/src/main/res/values/localazy.xml
@@ -7,6 +7,7 @@
"Objects"
"Smileys & People"
"Travel & Places"
+ "Recent emojis"
"Symbols"
"Captions might not be visible to people using older apps."
"Tap to change the video upload quality"
@@ -15,6 +16,7 @@
"Failed uploading media, please try again."
"The maximum file size allowed is %1$s."
"The file is too large to upload"
+ "Item %1$d of %2$d"
"Optimise image quality"
"Processing…"
"Block user"
diff --git a/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/DefaultMessagesEntryPointTest.kt b/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/DefaultMessagesEntryPointTest.kt
new file mode 100644
index 0000000000..a4753807cd
--- /dev/null
+++ b/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/DefaultMessagesEntryPointTest.kt
@@ -0,0 +1,136 @@
+/*
+ * Copyright 2025 New Vector Ltd.
+ *
+ * SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial
+ * Please see LICENSE files in the repository root for full details.
+ */
+
+package io.element.android.features.messages.impl
+
+import androidx.arch.core.executor.testing.InstantTaskExecutorRule
+import androidx.compose.runtime.Composable
+import com.bumble.appyx.core.modality.BuildContext
+import com.bumble.appyx.core.node.Node
+import com.bumble.appyx.testing.junit4.util.MainDispatcherRule
+import com.google.common.truth.Truth.assertThat
+import io.element.android.features.call.api.CallType
+import io.element.android.features.call.api.ElementCallEntryPoint
+import io.element.android.features.knockrequests.api.list.KnockRequestsListEntryPoint
+import io.element.android.features.location.api.SendLocationEntryPoint
+import io.element.android.features.location.api.ShowLocationEntryPoint
+import io.element.android.features.location.test.FakeLocationService
+import io.element.android.features.messages.api.MessagesEntryPoint
+import io.element.android.features.messages.impl.pinned.banner.createPinnedEventsTimelineProvider
+import io.element.android.features.messages.impl.timeline.createTimelineController
+import io.element.android.features.poll.api.create.CreatePollEntryPoint
+import io.element.android.libraries.dateformatter.test.FakeDateFormatter
+import io.element.android.libraries.matrix.api.core.EventId
+import io.element.android.libraries.matrix.api.core.RoomId
+import io.element.android.libraries.matrix.api.core.UserId
+import io.element.android.libraries.matrix.api.permalink.PermalinkData
+import io.element.android.libraries.matrix.api.timeline.Timeline
+import io.element.android.libraries.matrix.test.AN_EVENT_ID
+import io.element.android.libraries.matrix.test.A_USER_ID
+import io.element.android.libraries.matrix.test.FakeMatrixClient
+import io.element.android.libraries.matrix.test.room.FakeBaseRoom
+import io.element.android.libraries.matrix.ui.messages.RoomMemberProfilesCache
+import io.element.android.libraries.matrix.ui.messages.RoomNamesCache
+import io.element.android.libraries.mediaviewer.api.MediaViewerEntryPoint
+import io.element.android.libraries.textcomposer.mentions.MentionSpanTheme
+import io.element.android.libraries.textcomposer.mentions.MentionSpanUpdater
+import io.element.android.services.analytics.test.FakeAnalyticsService
+import io.element.android.tests.testutils.lambda.lambdaError
+import io.element.android.tests.testutils.node.TestParentNode
+import io.element.android.tests.testutils.testCoroutineDispatchers
+import kotlinx.coroutines.test.runTest
+import org.junit.Rule
+import org.junit.Test
+
+class DefaultMessagesEntryPointTest {
+ @get:Rule
+ val instantTaskExecutorRule = InstantTaskExecutorRule()
+
+ @get:Rule
+ val mainDispatcherRule = MainDispatcherRule()
+
+ @Test
+ fun `test node builder`() = runTest {
+ val entryPoint = DefaultMessagesEntryPoint()
+ val parentNode = TestParentNode.create { buildContext, plugins ->
+ MessagesFlowNode(
+ buildContext = buildContext,
+ plugins = plugins,
+ matrixClient = FakeMatrixClient(),
+ sendLocationEntryPoint = object : SendLocationEntryPoint {
+ override fun builder(timelineMode: Timeline.Mode) = lambdaError()
+ },
+ showLocationEntryPoint = object : ShowLocationEntryPoint {
+ override fun createNode(parentNode: Node, buildContext: BuildContext, inputs: ShowLocationEntryPoint.Inputs) = lambdaError()
+ },
+ createPollEntryPoint = object : CreatePollEntryPoint {
+ override fun nodeBuilder(parentNode: Node, buildContext: BuildContext) = lambdaError()
+ },
+ elementCallEntryPoint = object : ElementCallEntryPoint {
+ override fun startCall(callType: CallType) = lambdaError()
+ override suspend fun handleIncomingCall(
+ callType: CallType.RoomCall,
+ eventId: EventId,
+ senderId: UserId,
+ roomName: String?,
+ senderName: String?,
+ avatarUrl: String?,
+ timestamp: Long,
+ expirationTimestamp: Long,
+ notificationChannelId: String,
+ textContent: String?,
+ ) = lambdaError()
+ },
+ mediaViewerEntryPoint = object : MediaViewerEntryPoint {
+ override fun nodeBuilder(parentNode: Node, buildContext: BuildContext) = lambdaError()
+ },
+ analyticsService = FakeAnalyticsService(),
+ locationService = FakeLocationService(),
+ room = FakeBaseRoom(),
+ roomMemberProfilesCache = RoomMemberProfilesCache(),
+ roomNamesCache = RoomNamesCache(),
+ mentionSpanUpdater = object : MentionSpanUpdater {
+ override fun updateMentionSpans(text: CharSequence) = text
+
+ @Composable
+ override fun rememberMentionSpans(text: CharSequence) = text
+ },
+ mentionSpanTheme = MentionSpanTheme(A_USER_ID),
+ pinnedEventsTimelineProvider = createPinnedEventsTimelineProvider(),
+ timelineController = createTimelineController(),
+ knockRequestsListEntryPoint = object : KnockRequestsListEntryPoint {
+ override fun createNode(parentNode: Node, buildContext: BuildContext) = lambdaError()
+ },
+ dateFormatter = FakeDateFormatter(),
+ coroutineDispatchers = testCoroutineDispatchers(),
+ )
+ }
+ val callback = object : MessagesEntryPoint.Callback {
+ override fun onRoomDetailsClick() = lambdaError()
+ override fun onUserDataClick(userId: UserId) = lambdaError()
+ override fun onPermalinkClick(data: PermalinkData, pushToBackstack: Boolean) = lambdaError()
+ override fun onForwardedToSingleRoom(roomId: RoomId) = lambdaError()
+ }
+ val initialTarget = MessagesEntryPoint.InitialTarget.Messages(focusedEventId = AN_EVENT_ID)
+ val params = MessagesEntryPoint.Params(initialTarget)
+ val result = entryPoint.nodeBuilder(parentNode, BuildContext.root(null))
+ .params(params)
+ .callback(callback)
+ .build()
+ assertThat(result).isInstanceOf(MessagesFlowNode::class.java)
+ assertThat(result.plugins).contains(MessagesEntryPoint.Params(initialTarget))
+ assertThat(result.plugins).contains(callback)
+ }
+
+ @Test
+ fun `test initial target to nav target mapping`() {
+ assertThat(MessagesEntryPoint.InitialTarget.Messages(focusedEventId = AN_EVENT_ID).toNavTarget())
+ .isEqualTo(MessagesFlowNode.NavTarget.Messages(AN_EVENT_ID))
+ assertThat(MessagesEntryPoint.InitialTarget.PinnedMessages.toNavTarget())
+ .isEqualTo(MessagesFlowNode.NavTarget.PinnedMessagesList)
+ }
+}
diff --git a/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/MessagesPresenterTest.kt b/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/MessagesPresenterTest.kt
index 6a1abd4b3f..52c5ee2259 100644
--- a/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/MessagesPresenterTest.kt
+++ b/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/MessagesPresenterTest.kt
@@ -26,6 +26,7 @@ import io.element.android.features.messages.impl.pinned.banner.aLoadedPinnedMess
import io.element.android.features.messages.impl.timeline.TimelineController
import io.element.android.features.messages.impl.timeline.TimelineEvents
import io.element.android.features.messages.impl.timeline.aTimelineState
+import io.element.android.features.messages.impl.timeline.model.TimelineItemThreadInfo
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemFileContent
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemImageContent
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemTextContent
@@ -61,7 +62,6 @@ import io.element.android.libraries.matrix.api.room.RoomMembersState
import io.element.android.libraries.matrix.api.room.RoomMembershipState
import io.element.android.libraries.matrix.api.room.tombstone.SuccessorRoom
import io.element.android.libraries.matrix.api.timeline.Timeline
-import io.element.android.libraries.matrix.api.timeline.item.EventThreadInfo
import io.element.android.libraries.matrix.api.timeline.item.TimelineItemDebugInfo
import io.element.android.libraries.matrix.api.timeline.item.event.EventOrTransactionId
import io.element.android.libraries.matrix.api.timeline.item.event.toEventOrTransactionId
@@ -160,9 +160,9 @@ class MessagesPresenterTest {
@Test
fun `present - handle toggling a reaction`() = runTest {
val coroutineDispatchers = testCoroutineDispatchers(useUnconfinedTestDispatcher = true)
- val toggleReactionSuccess = lambdaRecorder { _: String, _: EventOrTransactionId -> Result.success(Unit) }
+ val toggleReactionSuccess = lambdaRecorder { _: String, _: EventOrTransactionId -> Result.success(true) }
val toggleReactionFailure =
- lambdaRecorder { _: String, _: EventOrTransactionId -> Result.failure(IllegalStateException("Failed to send reaction")) }
+ lambdaRecorder { _: String, _: EventOrTransactionId -> Result.failure(IllegalStateException("Failed to send reaction")) }
val timeline = FakeTimeline().apply {
this.toggleReactionLambda = toggleReactionSuccess
@@ -200,7 +200,11 @@ class MessagesPresenterTest {
@Test
fun `present - handle toggling a reaction twice`() = runTest {
val coroutineDispatchers = testCoroutineDispatchers(useUnconfinedTestDispatcher = true)
- val toggleReactionSuccess = lambdaRecorder { _: String, _: EventOrTransactionId -> Result.success(Unit) }
+ var toggle = false
+ val toggleReactionSuccess = lambdaRecorder { _: String, _: EventOrTransactionId ->
+ toggle = !toggle
+ Result.success(toggle)
+ }
val timeline = FakeTimeline().apply {
this.toggleReactionLambda = toggleReactionSuccess
@@ -1177,7 +1181,7 @@ class MessagesPresenterTest {
val initialState = awaitItem()
initialState.eventSink(MessagesEvents.HandleAction(
action = TimelineItemAction.ReplyInThread,
- event = aMessageEvent(threadInfo = EventThreadInfo(A_THREAD_ID, null))
+ event = aMessageEvent(threadInfo = TimelineItemThreadInfo.ThreadResponse(A_THREAD_ID))
))
awaitItem()
openThreadLambda.assertions().isCalledOnce().with(value(A_THREAD_ID), value(null))
@@ -1200,7 +1204,7 @@ class MessagesPresenterTest {
event = aMessageEvent(
// The event id will be used as the thread id instead
eventId = AN_EVENT_ID,
- threadInfo = EventThreadInfo(null, null),
+ threadInfo = null,
)
))
awaitItem()
diff --git a/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/actionlist/ActionListPresenterTest.kt b/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/actionlist/ActionListPresenterTest.kt
index 964143ac78..e8766798cd 100644
--- a/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/actionlist/ActionListPresenterTest.kt
+++ b/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/actionlist/ActionListPresenterTest.kt
@@ -18,8 +18,9 @@ import io.element.android.features.messages.impl.crypto.sendfailure.VerifiedUser
import io.element.android.features.messages.impl.crypto.sendfailure.VerifiedUserSendFailureFactory
import io.element.android.features.messages.impl.fixtures.aMessageEvent
import io.element.android.features.messages.impl.timeline.aTimelineItemEvent
-import io.element.android.features.messages.impl.timeline.model.event.TimelineItemCallNotifyContent
+import io.element.android.features.messages.impl.timeline.model.TimelineItemThreadInfo
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemRedactedContent
+import io.element.android.features.messages.impl.timeline.model.event.TimelineItemRtcNotificationContent
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemTextContent
import io.element.android.features.messages.impl.timeline.model.event.aTimelineItemImageContent
import io.element.android.features.messages.impl.timeline.model.event.aTimelineItemPollContent
@@ -31,7 +32,6 @@ import io.element.android.libraries.featureflag.api.FeatureFlags
import io.element.android.libraries.featureflag.test.FakeFeatureFlagService
import io.element.android.libraries.matrix.api.room.BaseRoom
import io.element.android.libraries.matrix.api.timeline.Timeline
-import io.element.android.libraries.matrix.api.timeline.item.EventThreadInfo
import io.element.android.libraries.matrix.api.timeline.item.event.LocalEventSendState
import io.element.android.libraries.matrix.test.AN_EVENT_ID
import io.element.android.libraries.matrix.test.A_CAPTION
@@ -198,7 +198,7 @@ class ActionListPresenterTest {
val messageEvent = aMessageEvent(
isMine = false,
isEditable = false,
- threadInfo = EventThreadInfo(threadRootId = A_THREAD_ID, threadSummary = null),
+ threadInfo = TimelineItemThreadInfo.ThreadResponse(threadRootId = A_THREAD_ID),
content = TimelineItemTextContent(body = A_MESSAGE, htmlDocument = null, isEdited = false, formattedBody = A_MESSAGE)
)
initialState.eventSink.invoke(
@@ -432,7 +432,7 @@ class ActionListPresenterTest {
val initialState = awaitItem()
val messageEvent = aMessageEvent(
isMine = true,
- threadInfo = EventThreadInfo(threadRootId = A_THREAD_ID, threadSummary = null),
+ threadInfo = TimelineItemThreadInfo.ThreadResponse(threadRootId = A_THREAD_ID),
content = TimelineItemTextContent(body = A_MESSAGE, htmlDocument = null, isEdited = false, formattedBody = A_MESSAGE)
)
initialState.eventSink.invoke(
@@ -1193,7 +1193,7 @@ class ActionListPresenterTest {
val initialState = awaitItem()
val messageEvent = aMessageEvent(
isMine = true,
- content = TimelineItemCallNotifyContent(),
+ content = TimelineItemRtcNotificationContent(),
)
initialState.eventSink.invoke(
ActionListEvents.ComputeForMessage(
@@ -1264,7 +1264,7 @@ class ActionListPresenterTest {
content = aTimelineItemVoiceContent(
caption = null,
),
- threadInfo = EventThreadInfo(A_THREAD_ID, null)
+ threadInfo = TimelineItemThreadInfo.ThreadResponse(threadRootId = A_THREAD_ID)
)
initialState.eventSink.invoke(
ActionListEvents.ComputeForMessage(
@@ -1368,7 +1368,7 @@ class ActionListPresenterTest {
content = aTimelineItemVoiceContent(
caption = null,
),
- threadInfo = EventThreadInfo(A_THREAD_ID, null),
+ threadInfo = TimelineItemThreadInfo.ThreadResponse(threadRootId = A_THREAD_ID),
)
assertThat(messageEvent.isRemote).isTrue()
diff --git a/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/fixtures/MessageEventFixtures.kt b/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/fixtures/MessageEventFixtures.kt
index a9f2e075ac..703b4b0043 100644
--- a/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/fixtures/MessageEventFixtures.kt
+++ b/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/fixtures/MessageEventFixtures.kt
@@ -12,6 +12,7 @@ import io.element.android.features.messages.impl.timeline.aTimelineItemReactions
import io.element.android.features.messages.impl.timeline.model.ReadReceiptData
import io.element.android.features.messages.impl.timeline.model.TimelineItem
import io.element.android.features.messages.impl.timeline.model.TimelineItemReadReceipts
+import io.element.android.features.messages.impl.timeline.model.TimelineItemThreadInfo
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemEventContent
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemTextContent
import io.element.android.libraries.designsystem.components.avatar.AvatarData
@@ -19,7 +20,6 @@ import io.element.android.libraries.designsystem.components.avatar.AvatarSize
import io.element.android.libraries.matrix.api.core.EventId
import io.element.android.libraries.matrix.api.core.TransactionId
import io.element.android.libraries.matrix.api.core.UniqueId
-import io.element.android.libraries.matrix.api.timeline.item.EventThreadInfo
import io.element.android.libraries.matrix.api.timeline.item.event.LocalEventSendState
import io.element.android.libraries.matrix.api.timeline.item.event.MessageShieldProvider
import io.element.android.libraries.matrix.api.timeline.item.event.SendHandleProvider
@@ -41,7 +41,7 @@ internal fun aMessageEvent(
canBeRepliedTo: Boolean = true,
content: TimelineItemEventContent = TimelineItemTextContent(body = A_MESSAGE, htmlDocument = null, formattedBody = A_MESSAGE, isEdited = false),
inReplyTo: InReplyToDetails? = null,
- threadInfo: EventThreadInfo = EventThreadInfo(threadRootId = null, threadSummary = null),
+ threadInfo: TimelineItemThreadInfo? = null,
sendState: LocalEventSendState = LocalEventSendState.Sent(AN_EVENT_ID),
debugInfoProvider: TimelineItemDebugInfoProvider = TimelineItemDebugInfoProvider { aTimelineItemDebugInfo() },
messageShieldProvider: MessageShieldProvider = MessageShieldProvider { null },
diff --git a/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/fixtures/TimelineItemsFactoryFixtures.kt b/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/fixtures/TimelineItemsFactoryFixtures.kt
index 2cf0f8a3c9..502ab74062 100644
--- a/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/fixtures/TimelineItemsFactoryFixtures.kt
+++ b/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/fixtures/TimelineItemsFactoryFixtures.kt
@@ -7,6 +7,7 @@
package io.element.android.features.messages.impl.fixtures
+import io.element.android.features.messages.impl.messagesummary.FakeMessageSummaryFormatter
import io.element.android.features.messages.impl.timeline.factories.TimelineItemsFactory
import io.element.android.features.messages.impl.timeline.factories.TimelineItemsFactoryConfig
import io.element.android.features.messages.impl.timeline.factories.event.TimelineItemContentFactory
@@ -30,7 +31,9 @@ import io.element.android.features.poll.test.pollcontent.FakePollContentStateFac
import io.element.android.libraries.androidutils.filesize.FakeFileSizeFormatter
import io.element.android.libraries.dateformatter.test.FakeDateFormatter
import io.element.android.libraries.eventformatter.api.TimelineEventFormatter
-import io.element.android.libraries.matrix.api.timeline.item.event.EventTimelineItem
+import io.element.android.libraries.matrix.api.core.UserId
+import io.element.android.libraries.matrix.api.timeline.item.event.EventContent
+import io.element.android.libraries.matrix.api.user.CurrentSessionIdHolder
import io.element.android.libraries.matrix.test.FakeMatrixClient
import io.element.android.libraries.matrix.test.permalink.FakePermalinkParser
import io.element.android.libraries.mediaviewer.test.util.FileExtensionExtractorWithoutValidation
@@ -75,11 +78,13 @@ internal fun TestScope.aTimelineItemsFactory(
stateFactory = TimelineItemContentStateFactory(timelineEventFormatter),
failedToParseMessageFactory = TimelineItemContentFailedToParseMessageFactory(),
failedToParseStateFactory = TimelineItemContentFailedToParseStateFactory(),
+ currentSessionIdHolder = CurrentSessionIdHolder(matrixClient),
),
matrixClient = matrixClient,
dateFormatter = FakeDateFormatter(),
permalinkParser = FakePermalinkParser(),
- config = config
+ config = config,
+ summaryFormatter = FakeMessageSummaryFormatter(),
)
}
},
@@ -95,7 +100,7 @@ internal fun TestScope.aTimelineItemsFactory(
internal fun aTimelineEventFormatter(): TimelineEventFormatter {
return object : TimelineEventFormatter {
- override fun format(event: EventTimelineItem): CharSequence {
+ override fun format(content: EventContent, isOutgoing: Boolean, sender: UserId, senderDisambiguatedDisplayName: String): CharSequence? {
return ""
}
}
diff --git a/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/messagesummary/FakeMessageSummaryFormatter.kt b/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/messagesummary/FakeMessageSummaryFormatter.kt
index 315f2e3a7a..06d1cca1c7 100644
--- a/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/messagesummary/FakeMessageSummaryFormatter.kt
+++ b/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/messagesummary/FakeMessageSummaryFormatter.kt
@@ -7,13 +7,13 @@
package io.element.android.features.messages.impl.messagesummary
-import io.element.android.features.messages.impl.timeline.model.TimelineItem
+import io.element.android.features.messages.impl.timeline.model.event.TimelineItemEventContent
import io.element.android.features.messages.impl.utils.messagesummary.MessageSummaryFormatter
class FakeMessageSummaryFormatter : MessageSummaryFormatter {
private var result = "A message"
- override fun format(event: TimelineItem.Event): String = result
+ override fun format(content: TimelineItemEventContent): String = result
fun givenMessageResult(value: String) {
result = value
diff --git a/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/pinned/banner/PinnedMessagesBannerPresenterTest.kt b/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/pinned/banner/PinnedMessagesBannerPresenterTest.kt
index 4840d5bed1..38182dec1d 100644
--- a/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/pinned/banner/PinnedMessagesBannerPresenterTest.kt
+++ b/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/pinned/banner/PinnedMessagesBannerPresenterTest.kt
@@ -178,10 +178,9 @@ class PinnedMessagesBannerPresenterTest {
),
syncService: SyncService = FakeSyncService(),
): PinnedMessagesBannerPresenter {
- val timelineProvider = PinnedEventsTimelineProvider(
+ val timelineProvider = createPinnedEventsTimelineProvider(
room = room,
syncService = syncService,
- dispatchers = testCoroutineDispatchers(),
)
timelineProvider.launchIn(backgroundScope)
@@ -192,3 +191,12 @@ class PinnedMessagesBannerPresenterTest {
)
}
}
+
+internal fun TestScope.createPinnedEventsTimelineProvider(
+ room: JoinedRoom = FakeJoinedRoom(),
+ syncService: SyncService = FakeSyncService(),
+) = PinnedEventsTimelineProvider(
+ room = room,
+ syncService = syncService,
+ dispatchers = testCoroutineDispatchers(),
+)
diff --git a/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/timeline/TimelineControllerTest.kt b/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/timeline/TimelineControllerTest.kt
index a2005b7a39..71d295ba8b 100644
--- a/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/timeline/TimelineControllerTest.kt
+++ b/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/timeline/TimelineControllerTest.kt
@@ -217,3 +217,13 @@ class TimelineControllerTest {
}
}
}
+
+internal fun createTimelineController(
+ room: FakeJoinedRoom = FakeJoinedRoom(liveTimeline = FakeTimeline()),
+ liveTimeline: Timeline = FakeTimeline(name = "live"),
+): TimelineController {
+ return TimelineController(
+ room = room,
+ liveTimeline = liveTimeline
+ )
+}
diff --git a/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/timeline/factories/event/TimelineItemContentMessageFactoryTest.kt b/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/timeline/factories/event/TimelineItemContentMessageFactoryTest.kt
index 917683220e..fb13103694 100644
--- a/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/timeline/factories/event/TimelineItemContentMessageFactoryTest.kt
+++ b/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/timeline/factories/event/TimelineItemContentMessageFactoryTest.kt
@@ -750,7 +750,7 @@ class TimelineItemContentMessageFactoryTest {
body: String = "Body",
inReplyTo: InReplyTo? = null,
isEdited: Boolean = false,
- threadInfo: EventThreadInfo = EventThreadInfo(threadRootId = null, threadSummary = null),
+ threadInfo: EventThreadInfo? = null,
type: MessageType,
): MessageContent {
return MessageContent(
diff --git a/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/timeline/groups/TimelineItemGrouperTest.kt b/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/timeline/groups/TimelineItemGrouperTest.kt
index 188c5f0bcd..1bdc43ebef 100644
--- a/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/timeline/groups/TimelineItemGrouperTest.kt
+++ b/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/timeline/groups/TimelineItemGrouperTest.kt
@@ -18,7 +18,6 @@ import io.element.android.features.messages.impl.timeline.model.event.TimelineIt
import io.element.android.features.messages.impl.timeline.model.virtual.aTimelineItemDaySeparatorModel
import io.element.android.libraries.designsystem.components.avatar.anAvatarData
import io.element.android.libraries.matrix.api.core.UniqueId
-import io.element.android.libraries.matrix.api.timeline.item.EventThreadInfo
import io.element.android.libraries.matrix.api.timeline.item.event.LocalEventSendState
import io.element.android.libraries.matrix.test.AN_EVENT_ID
import io.element.android.libraries.matrix.test.A_USER_ID
@@ -42,7 +41,7 @@ class TimelineItemGrouperTest {
isEditable = false,
canBeRepliedTo = false,
inReplyTo = null,
- threadInfo = EventThreadInfo(threadRootId = null, threadSummary = null),
+ threadInfo = null,
origin = null,
timelineItemDebugInfoProvider = { aTimelineItemDebugInfo() },
messageShieldProvider = { null },
diff --git a/features/migration/impl/build.gradle.kts b/features/migration/impl/build.gradle.kts
index 0a9048a5c6..dd445624b9 100644
--- a/features/migration/impl/build.gradle.kts
+++ b/features/migration/impl/build.gradle.kts
@@ -1,4 +1,5 @@
import extension.setupDependencyInjection
+import extension.testCommonDependencies
/*
* Copyright 2024 New Vector Ltd.
@@ -29,15 +30,9 @@ dependencies {
implementation(projects.libraries.sessionStorage.api)
implementation(projects.libraries.uiStrings)
- testImplementation(libs.test.junit)
- testImplementation(libs.coroutines.test)
- testImplementation(libs.molecule.runtime)
- testImplementation(libs.test.robolectric)
- testImplementation(libs.test.truth)
- testImplementation(libs.test.turbine)
+ testCommonDependencies(libs)
testImplementation(projects.libraries.matrix.test)
testImplementation(projects.libraries.sessionStorage.test)
testImplementation(projects.libraries.preferences.test)
- testImplementation(projects.tests.testutils)
testImplementation(projects.features.rageshake.test)
}
diff --git a/features/poll/api/src/main/kotlin/io/element/android/features/poll/api/history/PollHistoryEntryPoint.kt b/features/poll/api/src/main/kotlin/io/element/android/features/poll/api/history/PollHistoryEntryPoint.kt
index 7ca61340c4..49f5f92b87 100644
--- a/features/poll/api/src/main/kotlin/io/element/android/features/poll/api/history/PollHistoryEntryPoint.kt
+++ b/features/poll/api/src/main/kotlin/io/element/android/features/poll/api/history/PollHistoryEntryPoint.kt
@@ -7,10 +7,6 @@
package io.element.android.features.poll.api.history
-import com.bumble.appyx.core.modality.BuildContext
-import com.bumble.appyx.core.node.Node
-import io.element.android.libraries.architecture.FeatureEntryPoint
+import io.element.android.libraries.architecture.SimpleFeatureEntryPoint
-interface PollHistoryEntryPoint : FeatureEntryPoint {
- fun createNode(parentNode: Node, buildContext: BuildContext): Node
-}
+interface PollHistoryEntryPoint : SimpleFeatureEntryPoint
diff --git a/features/poll/api/src/main/kotlin/io/element/android/features/poll/api/pollcontent/PollContentStateFactory.kt b/features/poll/api/src/main/kotlin/io/element/android/features/poll/api/pollcontent/PollContentStateFactory.kt
index 5229534cc4..e42bb98bef 100644
--- a/features/poll/api/src/main/kotlin/io/element/android/features/poll/api/pollcontent/PollContentStateFactory.kt
+++ b/features/poll/api/src/main/kotlin/io/element/android/features/poll/api/pollcontent/PollContentStateFactory.kt
@@ -7,9 +7,18 @@
package io.element.android.features.poll.api.pollcontent
+import io.element.android.libraries.matrix.api.core.EventId
import io.element.android.libraries.matrix.api.timeline.item.event.EventTimelineItem
import io.element.android.libraries.matrix.api.timeline.item.event.PollContent
interface PollContentStateFactory {
- suspend fun create(event: EventTimelineItem, content: PollContent): PollContentState
+ suspend fun create(eventTimelineItem: EventTimelineItem, content: PollContent): PollContentState {
+ return create(
+ eventId = eventTimelineItem.eventId,
+ isEditable = eventTimelineItem.isEditable,
+ isOwn = eventTimelineItem.isOwn,
+ content = content,
+ )
+ }
+ suspend fun create(eventId: EventId?, isEditable: Boolean, isOwn: Boolean, content: PollContent): PollContentState
}
diff --git a/features/poll/api/src/main/res/values-cy/translations.xml b/features/poll/api/src/main/res/values-cy/translations.xml
index 3479c30674..207b2f5aeb 100644
--- a/features/poll/api/src/main/res/values-cy/translations.xml
+++ b/features/poll/api/src/main/res/values-cy/translations.xml
@@ -1,5 +1,13 @@
+
+ - "%1$d y cant o\'r holl bleidleisiau"
+ - "%1$d y cant o\'r holl bleidleisiau"
+ - "%1$d y cant o\'r holl bleidleisiau"
+ - "%1$d y cant o\'r holl bleidleisiau"
+ - "%1$d y cant o\'r holl bleidleisiau"
+ - "%1$d y cant o\'r holl bleidleisiau"
+
"Bydd yn dileu\'r dewis blaenorol"
"Dyma\'r ateb buddugol"
diff --git a/features/poll/impl/build.gradle.kts b/features/poll/impl/build.gradle.kts
index 200fe0f4b8..99ebefa71c 100644
--- a/features/poll/impl/build.gradle.kts
+++ b/features/poll/impl/build.gradle.kts
@@ -1,4 +1,5 @@
import extension.setupDependencyInjection
+import extension.testCommonDependencies
/*
* Copyright 2023, 2024 New Vector Ltd.
@@ -35,18 +36,10 @@ dependencies {
implementation(projects.libraries.dateformatter.api)
implementation(projects.libraries.uiStrings)
- testImplementation(libs.test.junit)
- testImplementation(libs.coroutines.test)
- testImplementation(libs.molecule.runtime)
- testImplementation(libs.test.truth)
- testImplementation(libs.test.turbine)
- testImplementation(libs.test.robolectric)
+ testCommonDependencies(libs, true)
testImplementation(projects.libraries.matrix.test)
testImplementation(projects.services.analytics.test)
testImplementation(projects.features.messages.test)
- testImplementation(projects.tests.testutils)
testImplementation(projects.libraries.dateformatter.test)
testImplementation(projects.features.poll.test)
- testImplementation(libs.androidx.compose.ui.test.junit)
- testReleaseImplementation(libs.androidx.compose.ui.test.manifest)
}
diff --git a/features/poll/impl/src/main/kotlin/io/element/android/features/poll/impl/create/CreatePollPresenter.kt b/features/poll/impl/src/main/kotlin/io/element/android/features/poll/impl/create/CreatePollPresenter.kt
index 134742f7d1..2d760d8314 100644
--- a/features/poll/impl/src/main/kotlin/io/element/android/features/poll/impl/create/CreatePollPresenter.kt
+++ b/features/poll/impl/src/main/kotlin/io/element/android/features/poll/impl/create/CreatePollPresenter.kt
@@ -47,7 +47,7 @@ class CreatePollPresenter(
@Assisted private val timelineMode: Timeline.Mode,
) : Presenter {
@AssistedFactory
- interface Factory {
+ fun interface Factory {
fun create(
timelineMode: Timeline.Mode,
backNavigator: () -> Unit,
diff --git a/features/poll/impl/src/main/kotlin/io/element/android/features/poll/impl/data/PollRepository.kt b/features/poll/impl/src/main/kotlin/io/element/android/features/poll/impl/data/PollRepository.kt
index 4fbb7f1499..983e3157a3 100644
--- a/features/poll/impl/src/main/kotlin/io/element/android/features/poll/impl/data/PollRepository.kt
+++ b/features/poll/impl/src/main/kotlin/io/element/android/features/poll/impl/data/PollRepository.kt
@@ -33,7 +33,7 @@ class PollRepository(
@Assisted private val timelineMode: Timeline.Mode,
) {
@AssistedFactory
- interface Factory {
+ fun interface Factory {
fun create(
timelineMode: Timeline.Mode,
): PollRepository
diff --git a/features/poll/impl/src/main/kotlin/io/element/android/features/poll/impl/history/model/PollHistoryItemsFactory.kt b/features/poll/impl/src/main/kotlin/io/element/android/features/poll/impl/history/model/PollHistoryItemsFactory.kt
index 3db799bce9..2a9c802e6b 100644
--- a/features/poll/impl/src/main/kotlin/io/element/android/features/poll/impl/history/model/PollHistoryItemsFactory.kt
+++ b/features/poll/impl/src/main/kotlin/io/element/android/features/poll/impl/history/model/PollHistoryItemsFactory.kt
@@ -45,7 +45,12 @@ class PollHistoryItemsFactory(
return when (timelineItem) {
is MatrixTimelineItem.Event -> {
val pollContent = timelineItem.event.content as? PollContent ?: return null
- val pollContentState = pollContentStateFactory.create(timelineItem.event, pollContent)
+ val pollContentState = pollContentStateFactory.create(
+ eventId = timelineItem.eventId,
+ isEditable = timelineItem.event.isEditable,
+ isOwn = timelineItem.event.isOwn,
+ content = pollContent,
+ )
PollHistoryItem(
formattedDate = dateFormatter.format(
timestamp = timelineItem.event.timestamp,
diff --git a/features/poll/impl/src/main/kotlin/io/element/android/features/poll/impl/model/DefaultPollContentStateFactory.kt b/features/poll/impl/src/main/kotlin/io/element/android/features/poll/impl/model/DefaultPollContentStateFactory.kt
index d506b72cf5..8647d80f23 100644
--- a/features/poll/impl/src/main/kotlin/io/element/android/features/poll/impl/model/DefaultPollContentStateFactory.kt
+++ b/features/poll/impl/src/main/kotlin/io/element/android/features/poll/impl/model/DefaultPollContentStateFactory.kt
@@ -14,8 +14,8 @@ import io.element.android.features.poll.api.pollcontent.PollContentState
import io.element.android.features.poll.api.pollcontent.PollContentStateFactory
import io.element.android.libraries.di.RoomScope
import io.element.android.libraries.matrix.api.MatrixClient
+import io.element.android.libraries.matrix.api.core.EventId
import io.element.android.libraries.matrix.api.poll.isDisclosed
-import io.element.android.libraries.matrix.api.timeline.item.event.EventTimelineItem
import io.element.android.libraries.matrix.api.timeline.item.event.PollContent
import kotlinx.collections.immutable.toImmutableList
@@ -25,8 +25,10 @@ class DefaultPollContentStateFactory(
private val matrixClient: MatrixClient,
) : PollContentStateFactory {
override suspend fun create(
- event: EventTimelineItem,
- content: PollContent
+ eventId: EventId?,
+ isEditable: Boolean,
+ isOwn: Boolean,
+ content: PollContent,
): PollContentState {
val totalVoteCount = content.votes.flatMap { it.value }.size
val myVotes = content.votes.filter { matrixClient.sessionId in it.value }.keys
@@ -59,13 +61,13 @@ class DefaultPollContentStateFactory(
}
return PollContentState(
- eventId = event.eventId,
+ eventId = eventId,
question = content.question,
answerItems = answerItems.toImmutableList(),
pollKind = content.kind,
- isPollEditable = event.isEditable,
+ isPollEditable = isEditable,
isPollEnded = isPollEnded,
- isMine = event.isOwn,
+ isMine = isOwn,
)
}
}
diff --git a/features/poll/impl/src/test/kotlin/io/element/android/features/poll/impl/create/DefaultCreatePollEntryPointTest.kt b/features/poll/impl/src/test/kotlin/io/element/android/features/poll/impl/create/DefaultCreatePollEntryPointTest.kt
new file mode 100644
index 0000000000..bf77cb4535
--- /dev/null
+++ b/features/poll/impl/src/test/kotlin/io/element/android/features/poll/impl/create/DefaultCreatePollEntryPointTest.kt
@@ -0,0 +1,62 @@
+/*
+ * Copyright 2025 New Vector Ltd.
+ *
+ * SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial
+ * Please see LICENSE files in the repository root for full details.
+ */
+
+package io.element.android.features.poll.impl.create
+
+import androidx.arch.core.executor.testing.InstantTaskExecutorRule
+import com.bumble.appyx.core.modality.BuildContext
+import com.google.common.truth.Truth.assertThat
+import io.element.android.features.messages.test.FakeMessageComposerContext
+import io.element.android.features.poll.api.create.CreatePollEntryPoint
+import io.element.android.features.poll.api.create.CreatePollMode
+import io.element.android.features.poll.impl.data.PollRepository
+import io.element.android.libraries.matrix.api.timeline.Timeline
+import io.element.android.libraries.matrix.test.room.FakeJoinedRoom
+import io.element.android.libraries.matrix.test.timeline.LiveTimelineProvider
+import io.element.android.services.analytics.test.FakeAnalyticsService
+import io.element.android.tests.testutils.node.TestParentNode
+import org.junit.Rule
+import org.junit.Test
+
+class DefaultCreatePollEntryPointTest {
+ @get:Rule
+ val instantTaskExecutorRule = InstantTaskExecutorRule()
+
+ @Test
+ fun `test node builder`() {
+ val entryPoint = DefaultCreatePollEntryPoint()
+ val parentNode = TestParentNode.create { buildContext, plugins ->
+ CreatePollNode(
+ buildContext = buildContext,
+ plugins = plugins,
+ presenterFactory = { timelineMode: Timeline.Mode, backNavigator: () -> Unit, mode: CreatePollMode ->
+ CreatePollPresenter(
+ repositoryFactory = {
+ val room = FakeJoinedRoom()
+ PollRepository(room, LiveTimelineProvider(room), timelineMode)
+ },
+ analyticsService = FakeAnalyticsService(),
+ messageComposerContext = FakeMessageComposerContext(),
+ navigateUp = backNavigator,
+ mode = mode,
+ timelineMode = timelineMode,
+ )
+ },
+ analyticsService = FakeAnalyticsService(),
+ )
+ }
+ val params = CreatePollEntryPoint.Params(
+ timelineMode = Timeline.Mode.Live,
+ mode = CreatePollMode.NewPoll,
+ )
+ val result = entryPoint.nodeBuilder(parentNode, BuildContext.root(null))
+ .params(params)
+ .build()
+ assertThat(result).isInstanceOf(CreatePollNode::class.java)
+ assertThat(result.plugins).contains(CreatePollNode.Inputs(timelineMode = params.timelineMode, mode = params.mode))
+ }
+}
diff --git a/features/poll/impl/src/test/kotlin/io/element/android/features/poll/impl/history/DefaultPollHistoryEntryPointTest.kt b/features/poll/impl/src/test/kotlin/io/element/android/features/poll/impl/history/DefaultPollHistoryEntryPointTest.kt
new file mode 100644
index 0000000000..dfab33e837
--- /dev/null
+++ b/features/poll/impl/src/test/kotlin/io/element/android/features/poll/impl/history/DefaultPollHistoryEntryPointTest.kt
@@ -0,0 +1,44 @@
+/*
+ * Copyright 2025 New Vector Ltd.
+ *
+ * SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial
+ * Please see LICENSE files in the repository root for full details.
+ */
+
+package io.element.android.features.poll.impl.history
+
+import androidx.arch.core.executor.testing.InstantTaskExecutorRule
+import com.bumble.appyx.core.modality.BuildContext
+import com.bumble.appyx.core.node.Node
+import com.bumble.appyx.testing.junit4.util.MainDispatcherRule
+import com.google.common.truth.Truth.assertThat
+import io.element.android.features.poll.api.create.CreatePollEntryPoint
+import io.element.android.tests.testutils.lambda.lambdaError
+import io.element.android.tests.testutils.node.TestParentNode
+import kotlinx.coroutines.test.runTest
+import org.junit.Rule
+import org.junit.Test
+
+class DefaultPollHistoryEntryPointTest {
+ @get:Rule
+ val instantTaskExecutorRule = InstantTaskExecutorRule()
+
+ @get:Rule
+ val mainDispatcherRule = MainDispatcherRule()
+
+ @Test
+ fun `test node builder`() = runTest {
+ val entryPoint = DefaultPollHistoryEntryPoint()
+ val parentNode = TestParentNode.create { buildContext, plugins ->
+ PollHistoryFlowNode(
+ buildContext = buildContext,
+ plugins = plugins,
+ createPollEntryPoint = object : CreatePollEntryPoint {
+ override fun nodeBuilder(parentNode: Node, buildContext: BuildContext) = lambdaError()
+ }
+ )
+ }
+ val result = entryPoint.createNode(parentNode, BuildContext.root(null))
+ assertThat(result).isInstanceOf(PollHistoryFlowNode::class.java)
+ }
+}
diff --git a/features/poll/impl/src/test/kotlin/io/element/android/features/poll/impl/history/PollHistoryPresenterTest.kt b/features/poll/impl/src/test/kotlin/io/element/android/features/poll/impl/history/PollHistoryPresenterTest.kt
index eeb4d0d223..cac5fae135 100644
--- a/features/poll/impl/src/test/kotlin/io/element/android/features/poll/impl/history/PollHistoryPresenterTest.kt
+++ b/features/poll/impl/src/test/kotlin/io/element/android/features/poll/impl/history/PollHistoryPresenterTest.kt
@@ -151,23 +151,23 @@ class PollHistoryPresenterTest {
assert(paginateLambda).isCalledExactly(2)
}
}
-
- private fun TestScope.createPollHistoryPresenter(
- room: FakeJoinedRoom = FakeJoinedRoom(),
- endPollAction: EndPollAction = FakeEndPollAction(),
- sendPollResponseAction: SendPollResponseAction = FakeSendPollResponseAction(),
- pollHistoryItemFactory: PollHistoryItemsFactory = PollHistoryItemsFactory(
- pollContentStateFactory = DefaultPollContentStateFactory(FakeMatrixClient()),
- dateFormatter = FakeDateFormatter(),
- dispatchers = testCoroutineDispatchers(),
- ),
- ): PollHistoryPresenter {
- return PollHistoryPresenter(
- sessionCoroutineScope = this,
- sendPollResponseAction = sendPollResponseAction,
- endPollAction = endPollAction,
- pollHistoryItemFactory = pollHistoryItemFactory,
- room = room,
- )
- }
+}
+
+internal fun TestScope.createPollHistoryPresenter(
+ room: FakeJoinedRoom = FakeJoinedRoom(),
+ endPollAction: EndPollAction = FakeEndPollAction(),
+ sendPollResponseAction: SendPollResponseAction = FakeSendPollResponseAction(),
+ pollHistoryItemFactory: PollHistoryItemsFactory = PollHistoryItemsFactory(
+ pollContentStateFactory = DefaultPollContentStateFactory(FakeMatrixClient()),
+ dateFormatter = FakeDateFormatter(),
+ dispatchers = testCoroutineDispatchers(),
+ ),
+): PollHistoryPresenter {
+ return PollHistoryPresenter(
+ sessionCoroutineScope = this,
+ sendPollResponseAction = sendPollResponseAction,
+ endPollAction = endPollAction,
+ pollHistoryItemFactory = pollHistoryItemFactory,
+ room = room,
+ )
}
diff --git a/features/poll/test/src/main/kotlin/io/element/android/features/poll/test/pollcontent/FakePollContentStateFactory.kt b/features/poll/test/src/main/kotlin/io/element/android/features/poll/test/pollcontent/FakePollContentStateFactory.kt
index 4c467fddd9..701d2e4640 100644
--- a/features/poll/test/src/main/kotlin/io/element/android/features/poll/test/pollcontent/FakePollContentStateFactory.kt
+++ b/features/poll/test/src/main/kotlin/io/element/android/features/poll/test/pollcontent/FakePollContentStateFactory.kt
@@ -10,20 +10,20 @@ package io.element.android.features.poll.test.pollcontent
import io.element.android.features.poll.api.pollcontent.PollAnswerItem
import io.element.android.features.poll.api.pollcontent.PollContentState
import io.element.android.features.poll.api.pollcontent.PollContentStateFactory
-import io.element.android.libraries.matrix.api.timeline.item.event.EventTimelineItem
+import io.element.android.libraries.matrix.api.core.EventId
import io.element.android.libraries.matrix.api.timeline.item.event.PollContent
import kotlinx.collections.immutable.toImmutableList
class FakePollContentStateFactory : PollContentStateFactory {
- override suspend fun create(event: EventTimelineItem, content: PollContent): PollContentState {
+ override suspend fun create(eventId: EventId?, isEditable: Boolean, isOwn: Boolean, content: PollContent): PollContentState {
return PollContentState(
- eventId = event.eventId,
+ eventId = eventId,
question = content.question,
answerItems = emptyList().toImmutableList(),
pollKind = content.kind,
- isPollEditable = event.isEditable,
+ isPollEditable = isEditable,
isPollEnded = content.endTime != null,
- isMine = event.isOwn
+ isMine = isOwn,
)
}
}
diff --git a/features/preferences/impl/build.gradle.kts b/features/preferences/impl/build.gradle.kts
index d6c716ca87..d3edba5833 100644
--- a/features/preferences/impl/build.gradle.kts
+++ b/features/preferences/impl/build.gradle.kts
@@ -1,6 +1,7 @@
import config.BuildTimeConfig
import extension.buildConfigFieldStr
import extension.setupDependencyInjection
+import extension.testCommonDependencies
/*
* Copyright 2022-2024 New Vector Ltd.
@@ -71,7 +72,6 @@ dependencies {
implementation(projects.features.rageshake.api)
implementation(projects.features.lockscreen.api)
implementation(projects.features.analytics.api)
- implementation(projects.features.ftue.api)
implementation(projects.features.licenses.api)
implementation(projects.features.logout.api)
implementation(projects.features.deactivation.api)
@@ -91,13 +91,7 @@ dependencies {
implementation(platform(libs.network.okhttp.bom))
implementation(libs.network.okhttp)
- testImplementation(libs.test.junit)
- testImplementation(libs.coroutines.test)
- testImplementation(libs.molecule.runtime)
- testImplementation(libs.test.truth)
- testImplementation(libs.test.turbine)
- testImplementation(libs.test.mockk)
- testImplementation(libs.test.robolectric)
+ testCommonDependencies(libs, true)
testImplementation(projects.libraries.matrix.test)
testImplementation(projects.libraries.featureflag.test)
testImplementation(projects.libraries.mediapickers.test)
@@ -106,7 +100,6 @@ dependencies {
testImplementation(projects.libraries.preferences.test)
testImplementation(projects.libraries.push.test)
testImplementation(projects.libraries.pushstore.test)
- testImplementation(projects.features.ftue.test)
testImplementation(projects.features.invite.test)
testImplementation(projects.features.rageshake.test)
testImplementation(projects.features.logout.test)
@@ -114,7 +107,4 @@ dependencies {
testImplementation(projects.libraries.pushproviders.test)
testImplementation(projects.services.analytics.test)
testImplementation(projects.services.toolbox.test)
- testImplementation(projects.tests.testutils)
- testImplementation(libs.androidx.compose.ui.test.junit)
- testReleaseImplementation(libs.androidx.compose.ui.test.manifest)
}
diff --git a/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/PreferencesFlowNode.kt b/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/PreferencesFlowNode.kt
index 6b0d8a7bec..49e297af08 100644
--- a/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/PreferencesFlowNode.kt
+++ b/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/PreferencesFlowNode.kt
@@ -208,6 +208,10 @@ class PreferencesFlowNode(
navigateUp()
}
}
+
+ override fun openIgnoredUsers() {
+ backstack.push(NavTarget.BlockedUsers)
+ }
})
.build()
}
@@ -261,7 +265,7 @@ class PreferencesFlowNode(
.build()
}
is NavTarget.OssLicenses -> {
- openSourceLicensesEntryPoint.getNode(this, buildContext)
+ openSourceLicensesEntryPoint.createNode(this, buildContext)
}
NavTarget.AccountDeactivation -> {
accountDeactivationEntryPoint.createNode(this, buildContext)
diff --git a/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/root/PreferencesRootView.kt b/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/root/PreferencesRootView.kt
index 85c180ddac..544b5f5b3e 100644
--- a/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/root/PreferencesRootView.kt
+++ b/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/root/PreferencesRootView.kt
@@ -214,9 +214,6 @@ private fun ColumnScope.GeneralSection(
leadingContent = ListItemContent.Icon(IconSource.Vector(CompoundIcons.Settings())),
onClick = onOpenAdvancedSettings,
)
- if (state.showDeveloperSettings) {
- DeveloperPreferencesView(onOpenDeveloperSettings)
- }
ListItem(
headlineContent = { Text(stringResource(id = CommonStrings.action_signout)) },
leadingContent = ListItemContent.Icon(IconSource.Vector(CompoundIcons.SignOut())),
@@ -231,6 +228,10 @@ private fun ColumnScope.GeneralSection(
onClick = onDeactivateClick,
)
}
+ // Put developer settings at the end, so nothing bad happens if the user clicks 8 times to enable the entry
+ if (state.showDeveloperSettings) {
+ DeveloperPreferencesView(onOpenDeveloperSettings)
+ }
}
@Composable
diff --git a/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/tasks/ClearCacheUseCase.kt b/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/tasks/ClearCacheUseCase.kt
index 11c4a3c94f..50d9cf8798 100644
--- a/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/tasks/ClearCacheUseCase.kt
+++ b/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/tasks/ClearCacheUseCase.kt
@@ -12,7 +12,6 @@ import coil3.SingletonImageLoader
import dev.zacsweers.metro.ContributesBinding
import dev.zacsweers.metro.Inject
import dev.zacsweers.metro.Provider
-import io.element.android.features.ftue.api.state.FtueService
import io.element.android.features.invite.api.SeenInvitesStore
import io.element.android.features.preferences.impl.DefaultCacheService
import io.element.android.libraries.core.coroutine.CoroutineDispatchers
@@ -36,7 +35,6 @@ class DefaultClearCacheUseCase(
private val coroutineDispatchers: CoroutineDispatchers,
private val defaultCacheService: DefaultCacheService,
private val okHttpClient: Provider,
- private val ftueService: FtueService,
private val pushService: PushService,
private val seenInvitesStore: SeenInvitesStore,
private val activeRoomsHolder: ActiveRoomsHolder,
@@ -56,7 +54,6 @@ class DefaultClearCacheUseCase(
// Clear app cache
context.cacheDir.deleteRecursively()
// Clear some settings
- ftueService.reset()
seenInvitesStore.clear()
// Ensure any error will be displayed again
pushService.setIgnoreRegistrationError(matrixClient.sessionId, false)
diff --git a/features/preferences/impl/src/main/res/values-cy/translations.xml b/features/preferences/impl/src/main/res/values-cy/translations.xml
index da0308b003..9711eda179 100644
--- a/features/preferences/impl/src/main/res/values-cy/translations.xml
+++ b/features/preferences/impl/src/main/res/values-cy/translations.xml
@@ -13,6 +13,13 @@
"Llwythwch i fyny lluniau a fideos yn gynt a lleihau\'r defnydd o ddata"
"Optimeiddio ansawdd y cyfryngau"
"Cymedroli a Diogelwch"
+ "Optimeiddio delweddau\'n awtomatig ar gyfer llwytho cyflymach a meintiau ffeiliau llai."
+ "Optimeiddio ansawdd llwytho delweddau"
+ "%1$s Tapiwch yma i newid."
+ "Uchel (1080p)"
+ "Isel (480c)"
+ "Safonol (720p)"
+ "Ansawdd lwytho fideo"
"Darparwr hysbysiad gwthio"
"Analluogi\'r golygydd testun cyfoethog i deipio Markdown â llaw."
"Derbynebau darllen"
diff --git a/features/preferences/impl/src/main/res/values-fi/translations.xml b/features/preferences/impl/src/main/res/values-fi/translations.xml
index f938235e66..1240b620e9 100644
--- a/features/preferences/impl/src/main/res/values-fi/translations.xml
+++ b/features/preferences/impl/src/main/res/values-fi/translations.xml
@@ -13,6 +13,13 @@
"Lähetä valokuvia ja videoita nopeammin ja vähennä datan käyttöä."
"Optimoi median laatu"
"Moderointi ja Turvallisuus"
+ "Optimoi kuvat automaattisesti nopeampia lähetysnopeuksia ja pienempiä tiedostokokoja varten."
+ "Optimoi kuvien lähetyslaatu"
+ "%1$s. Napauta tästä vaihtaaksesi."
+ "Korkea (1080p)"
+ "Matala (480p)"
+ "Normaali (720p)"
+ "Videon lähetyslaatu"
"Push-ilmoitusten tarjoaja"
"Ota rikastettu tekstieditori pois käytöstä, jotta voit kirjoittaa Markdownia manuaalisesti."
"Lukukuittaukset"
diff --git a/features/preferences/impl/src/main/res/values-zh-rTW/translations.xml b/features/preferences/impl/src/main/res/values-zh-rTW/translations.xml
index 52630e1c7b..bda2b085a5 100644
--- a/features/preferences/impl/src/main/res/values-zh-rTW/translations.xml
+++ b/features/preferences/impl/src/main/res/values-zh-rTW/translations.xml
@@ -13,6 +13,13 @@
"上傳照片與影片更快且減少資料使用量"
"最佳化媒體品質"
"管理與安全"
+ "自動最佳化影像以提供更快的上傳速度與較小的檔案大小。"
+ "最佳化影像上傳品質"
+ "%1$s。輕點此處以變更。"
+ "高 (1080p)"
+ "低 (480p)"
+ "標準 (720p)"
+ "視訊上傳品質"
"推播通知提供者"
"手動輸入 Markdown,停用格式化文字編輯器。"
"已讀回條"
diff --git a/features/preferences/impl/src/test/kotlin/io/element/android/features/preferences/impl/DefaultPreferencesEntryPointTest.kt b/features/preferences/impl/src/test/kotlin/io/element/android/features/preferences/impl/DefaultPreferencesEntryPointTest.kt
new file mode 100644
index 0000000000..807ff3a5c6
--- /dev/null
+++ b/features/preferences/impl/src/test/kotlin/io/element/android/features/preferences/impl/DefaultPreferencesEntryPointTest.kt
@@ -0,0 +1,93 @@
+/*
+ * Copyright 2025 New Vector Ltd.
+ *
+ * SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial
+ * Please see LICENSE files in the repository root for full details.
+ */
+
+package io.element.android.features.preferences.impl
+
+import android.content.Context
+import androidx.arch.core.executor.testing.InstantTaskExecutorRule
+import com.bumble.appyx.core.modality.BuildContext
+import com.bumble.appyx.core.node.Node
+import com.bumble.appyx.testing.junit4.util.MainDispatcherRule
+import com.google.common.truth.Truth.assertThat
+import io.element.android.features.deactivation.api.AccountDeactivationEntryPoint
+import io.element.android.features.licenses.api.OpenSourceLicensesEntryPoint
+import io.element.android.features.lockscreen.api.LockScreenEntryPoint
+import io.element.android.features.logout.api.LogoutEntryPoint
+import io.element.android.features.preferences.api.PreferencesEntryPoint
+import io.element.android.libraries.matrix.api.core.EventId
+import io.element.android.libraries.matrix.api.core.RoomId
+import io.element.android.libraries.matrix.api.core.SessionId
+import io.element.android.libraries.troubleshoot.api.NotificationTroubleShootEntryPoint
+import io.element.android.libraries.troubleshoot.api.PushHistoryEntryPoint
+import io.element.android.tests.testutils.lambda.lambdaError
+import io.element.android.tests.testutils.node.TestParentNode
+import org.junit.Rule
+import org.junit.Test
+
+class DefaultPreferencesEntryPointTest {
+ @get:Rule
+ val instantTaskExecutorRule = InstantTaskExecutorRule()
+
+ @get:Rule
+ val mainDispatcherRule = MainDispatcherRule()
+
+ @Test
+ fun `test node builder`() {
+ val entryPoint = DefaultPreferencesEntryPoint()
+ val parentNode = TestParentNode.create { buildContext, plugins ->
+ PreferencesFlowNode(
+ buildContext = buildContext,
+ plugins = plugins,
+ lockScreenEntryPoint = object : LockScreenEntryPoint {
+ override fun nodeBuilder(parentNode: Node, buildContext: BuildContext, navTarget: LockScreenEntryPoint.Target) = lambdaError()
+ override fun pinUnlockIntent(context: Context) = lambdaError()
+ },
+ notificationTroubleShootEntryPoint = object : NotificationTroubleShootEntryPoint {
+ override fun nodeBuilder(parentNode: Node, buildContext: BuildContext) = lambdaError()
+ },
+ pushHistoryEntryPoint = object : PushHistoryEntryPoint {
+ override fun nodeBuilder(parentNode: Node, buildContext: BuildContext) = lambdaError()
+ },
+ logoutEntryPoint = object : LogoutEntryPoint {
+ override fun nodeBuilder(parentNode: Node, buildContext: BuildContext) = lambdaError()
+ },
+ openSourceLicensesEntryPoint = object : OpenSourceLicensesEntryPoint {
+ override fun createNode(parentNode: Node, buildContext: BuildContext) = lambdaError()
+ },
+ accountDeactivationEntryPoint = object : AccountDeactivationEntryPoint {
+ override fun createNode(parentNode: Node, buildContext: BuildContext) = lambdaError()
+ },
+ )
+ }
+ val callback = object : PreferencesEntryPoint.Callback {
+ override fun onOpenBugReport() = lambdaError()
+ override fun onSecureBackupClick() = lambdaError()
+ override fun onOpenRoomNotificationSettings(roomId: RoomId) = lambdaError()
+ override fun navigateTo(sessionId: SessionId, roomId: RoomId, eventId: EventId) = lambdaError()
+ }
+ val params = PreferencesEntryPoint.Params(
+ initialElement = PreferencesEntryPoint.InitialTarget.NotificationSettings,
+ )
+ val result = entryPoint.nodeBuilder(parentNode, BuildContext.root(null))
+ .params(params)
+ .callback(callback)
+ .build()
+ assertThat(result).isInstanceOf(PreferencesFlowNode::class.java)
+ assertThat(result.plugins).contains(params)
+ assertThat(result.plugins).contains(callback)
+ }
+
+ @Test
+ fun `test initial target to nav target mapping`() {
+ assertThat(PreferencesEntryPoint.InitialTarget.Root.toNavTarget())
+ .isEqualTo(PreferencesFlowNode.NavTarget.Root)
+ assertThat(PreferencesEntryPoint.InitialTarget.NotificationSettings.toNavTarget())
+ .isEqualTo(PreferencesFlowNode.NavTarget.NotificationSettings)
+ assertThat(PreferencesEntryPoint.InitialTarget.NotificationTroubleshoot.toNavTarget())
+ .isEqualTo(PreferencesFlowNode.NavTarget.TroubleshootNotifications)
+ }
+}
diff --git a/features/preferences/impl/src/test/kotlin/io/element/android/features/preferences/impl/tasks/DefaultClearCacheUseCaseTest.kt b/features/preferences/impl/src/test/kotlin/io/element/android/features/preferences/impl/tasks/DefaultClearCacheUseCaseTest.kt
index cfdc63984c..1e16509ad2 100644
--- a/features/preferences/impl/src/test/kotlin/io/element/android/features/preferences/impl/tasks/DefaultClearCacheUseCaseTest.kt
+++ b/features/preferences/impl/src/test/kotlin/io/element/android/features/preferences/impl/tasks/DefaultClearCacheUseCaseTest.kt
@@ -10,7 +10,6 @@ package io.element.android.features.preferences.impl.tasks
import androidx.test.platform.app.InstrumentationRegistry
import app.cash.turbine.test
import com.google.common.truth.Truth.assertThat
-import io.element.android.features.ftue.test.FakeFtueService
import io.element.android.features.invite.test.InMemorySeenInvitesStore
import io.element.android.features.preferences.impl.DefaultCacheService
import io.element.android.libraries.matrix.api.core.SessionId
@@ -41,10 +40,6 @@ class DefaultClearCacheUseCaseTest {
clearCacheLambda = clearCacheLambda,
)
val defaultCacheService = DefaultCacheService()
- val resetFtueLambda = lambdaRecorder { }
- val ftueService = FakeFtueService(
- resetLambda = resetFtueLambda,
- )
val setIgnoreRegistrationErrorLambda = lambdaRecorder { _, _ -> }
val resetBatteryOptimizationStateResult = lambdaRecorder { }
val pushService = FakePushService(
@@ -59,7 +54,6 @@ class DefaultClearCacheUseCaseTest {
coroutineDispatchers = testCoroutineDispatchers(),
defaultCacheService = defaultCacheService,
okHttpClient = { OkHttpClient.Builder().build() },
- ftueService = ftueService,
pushService = pushService,
seenInvitesStore = seenInvitesStore,
activeRoomsHolder = activeRoomsHolder,
@@ -67,7 +61,6 @@ class DefaultClearCacheUseCaseTest {
defaultCacheService.clearedCacheEventFlow.test {
sut.invoke()
clearCacheLambda.assertions().isCalledOnce()
- resetFtueLambda.assertions().isCalledOnce()
setIgnoreRegistrationErrorLambda.assertions().isCalledOnce()
.with(value(matrixClient.sessionId), value(false))
resetBatteryOptimizationStateResult.assertions().isCalledOnce()
diff --git a/features/rageshake/api/src/main/kotlin/io/element/android/features/rageshake/api/bugreport/BugReportEntryPoint.kt b/features/rageshake/api/src/main/kotlin/io/element/android/features/rageshake/api/bugreport/BugReportEntryPoint.kt
index fbc7eb0dc8..0eb84b529b 100644
--- a/features/rageshake/api/src/main/kotlin/io/element/android/features/rageshake/api/bugreport/BugReportEntryPoint.kt
+++ b/features/rageshake/api/src/main/kotlin/io/element/android/features/rageshake/api/bugreport/BugReportEntryPoint.kt
@@ -21,7 +21,6 @@ interface BugReportEntryPoint : FeatureEntryPoint {
}
interface Callback : Plugin {
- fun onBugReportSent()
- fun onViewLogs(basePath: String)
+ fun onDone()
}
}
diff --git a/features/rageshake/impl/build.gradle.kts b/features/rageshake/impl/build.gradle.kts
index ea4eb33ba6..b17d78f3aa 100644
--- a/features/rageshake/impl/build.gradle.kts
+++ b/features/rageshake/impl/build.gradle.kts
@@ -1,4 +1,5 @@
import extension.setupDependencyInjection
+import extension.testCommonDependencies
/*
* Copyright 2022-2024 New Vector Ltd.
@@ -27,6 +28,7 @@ setupDependencyInjection()
dependencies {
implementation(projects.appconfig)
implementation(projects.features.enterprise.api)
+ implementation(projects.features.viewfolder.api)
implementation(projects.services.toolbox.api)
implementation(projects.libraries.androidutils)
implementation(projects.libraries.core)
@@ -45,19 +47,12 @@ dependencies {
implementation(libs.coil)
implementation(libs.coil.compose)
- testImplementation(libs.test.junit)
- testImplementation(libs.test.robolectric)
- testImplementation(libs.coroutines.test)
- testImplementation(libs.molecule.runtime)
- testImplementation(libs.test.truth)
- testImplementation(libs.test.turbine)
- testImplementation(libs.test.mockk)
+ testCommonDependencies(libs)
testImplementation(projects.features.enterprise.test)
testImplementation(projects.libraries.matrix.test)
testImplementation(projects.libraries.sessionStorage.test)
testImplementation(projects.features.rageshake.test)
testImplementation(projects.libraries.preferences.test)
- testImplementation(projects.tests.testutils)
testImplementation(projects.services.toolbox.test)
testImplementation(libs.network.mockwebserver)
}
diff --git a/features/rageshake/impl/src/main/kotlin/io/element/android/features/rageshake/impl/bugreport/BugReportFlowNode.kt b/features/rageshake/impl/src/main/kotlin/io/element/android/features/rageshake/impl/bugreport/BugReportFlowNode.kt
new file mode 100644
index 0000000000..0dd4d4f518
--- /dev/null
+++ b/features/rageshake/impl/src/main/kotlin/io/element/android/features/rageshake/impl/bugreport/BugReportFlowNode.kt
@@ -0,0 +1,95 @@
+/*
+ * Copyright 2025 New Vector Ltd.
+ *
+ * SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial
+ * Please see LICENSE files in the repository root for full details.
+ */
+
+package io.element.android.features.rageshake.impl.bugreport
+
+import android.os.Parcelable
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.Modifier
+import com.bumble.appyx.core.modality.BuildContext
+import com.bumble.appyx.core.node.Node
+import com.bumble.appyx.core.plugin.Plugin
+import com.bumble.appyx.core.plugin.plugins
+import com.bumble.appyx.navmodel.backstack.BackStack
+import com.bumble.appyx.navmodel.backstack.operation.pop
+import com.bumble.appyx.navmodel.backstack.operation.push
+import dev.zacsweers.metro.AppScope
+import dev.zacsweers.metro.Assisted
+import dev.zacsweers.metro.Inject
+import io.element.android.annotations.ContributesNode
+import io.element.android.features.rageshake.api.bugreport.BugReportEntryPoint
+import io.element.android.features.viewfolder.api.ViewFolderEntryPoint
+import io.element.android.libraries.architecture.BackstackView
+import io.element.android.libraries.architecture.BaseFlowNode
+import io.element.android.libraries.architecture.createNode
+import kotlinx.parcelize.Parcelize
+
+@ContributesNode(AppScope::class)
+@Inject
+class BugReportFlowNode(
+ @Assisted val buildContext: BuildContext,
+ @Assisted plugins: List,
+ private val viewFolderEntryPoint: ViewFolderEntryPoint,
+) : BaseFlowNode(
+ backstack = BackStack(
+ initialElement = NavTarget.Root,
+ savedStateMap = buildContext.savedStateMap,
+ ),
+ buildContext = buildContext,
+ plugins = plugins
+) {
+ private fun onDone() {
+ plugins().forEach { it.onDone() }
+ }
+
+ sealed interface NavTarget : Parcelable {
+ @Parcelize
+ data object Root : NavTarget
+
+ @Parcelize
+ data class ViewLogs(
+ val rootPath: String,
+ ) : NavTarget
+ }
+
+ override fun resolve(navTarget: NavTarget, buildContext: BuildContext): Node {
+ return when (navTarget) {
+ NavTarget.Root -> {
+ val callback = object : BugReportNode.Callback {
+ override fun onDone() {
+ this@BugReportFlowNode.onDone()
+ }
+
+ override fun onViewLogs(basePath: String) {
+ backstack.push(NavTarget.ViewLogs(rootPath = basePath))
+ }
+ }
+ createNode(buildContext, listOf(callback))
+ }
+ is NavTarget.ViewLogs -> {
+ val callback = object : ViewFolderEntryPoint.Callback {
+ override fun onDone() {
+ backstack.pop()
+ }
+ }
+ val params = ViewFolderEntryPoint.Params(
+ rootPath = navTarget.rootPath,
+ )
+ viewFolderEntryPoint
+ .nodeBuilder(this, buildContext)
+ .params(params)
+ .callback(callback)
+ .build()
+ }
+ }
+ }
+
+ @Composable
+ override fun View(modifier: Modifier) {
+ BackstackView()
+ }
+}
diff --git a/features/rageshake/impl/src/main/kotlin/io/element/android/features/rageshake/impl/bugreport/BugReportNode.kt b/features/rageshake/impl/src/main/kotlin/io/element/android/features/rageshake/impl/bugreport/BugReportNode.kt
index 3f507829e8..b6eb494589 100644
--- a/features/rageshake/impl/src/main/kotlin/io/element/android/features/rageshake/impl/bugreport/BugReportNode.kt
+++ b/features/rageshake/impl/src/main/kotlin/io/element/android/features/rageshake/impl/bugreport/BugReportNode.kt
@@ -18,7 +18,6 @@ import dev.zacsweers.metro.AppScope
import dev.zacsweers.metro.Assisted
import dev.zacsweers.metro.Inject
import io.element.android.annotations.ContributesNode
-import io.element.android.features.rageshake.api.bugreport.BugReportEntryPoint
import io.element.android.features.rageshake.api.reporter.BugReporter
import io.element.android.libraries.androidutils.system.toast
import io.element.android.libraries.ui.strings.CommonStrings
@@ -31,8 +30,17 @@ class BugReportNode(
private val presenter: BugReportPresenter,
private val bugReporter: BugReporter,
) : Node(buildContext, plugins = plugins) {
+ interface Callback : Plugin {
+ fun onDone()
+ fun onViewLogs(basePath: String)
+ }
+
private fun onViewLogs(basePath: String) {
- plugins().forEach { it.onViewLogs(basePath) }
+ plugins().forEach { it.onViewLogs(basePath) }
+ }
+
+ private fun onDone() {
+ plugins().forEach { it.onDone() }
}
@Composable
@@ -54,8 +62,4 @@ class BugReportNode(
}
)
}
-
- private fun onDone() {
- plugins().forEach { it.onBugReportSent() }
- }
}
diff --git a/features/rageshake/impl/src/main/kotlin/io/element/android/features/rageshake/impl/bugreport/DefaultBugReportEntryPoint.kt b/features/rageshake/impl/src/main/kotlin/io/element/android/features/rageshake/impl/bugreport/DefaultBugReportEntryPoint.kt
index 0415d36e1d..6fa5772c17 100644
--- a/features/rageshake/impl/src/main/kotlin/io/element/android/features/rageshake/impl/bugreport/DefaultBugReportEntryPoint.kt
+++ b/features/rageshake/impl/src/main/kotlin/io/element/android/features/rageshake/impl/bugreport/DefaultBugReportEntryPoint.kt
@@ -29,7 +29,7 @@ class DefaultBugReportEntryPoint : BugReportEntryPoint {
}
override fun build(): Node {
- return parentNode.createNode(buildContext, plugins)
+ return parentNode.createNode(buildContext, plugins)
}
}
}
diff --git a/features/rageshake/impl/src/test/kotlin/io/element/android/features/rageshake/impl/bugreport/BugReportPresenterTest.kt b/features/rageshake/impl/src/test/kotlin/io/element/android/features/rageshake/impl/bugreport/BugReportPresenterTest.kt
index 027e2fb38c..362b3798d6 100644
--- a/features/rageshake/impl/src/test/kotlin/io/element/android/features/rageshake/impl/bugreport/BugReportPresenterTest.kt
+++ b/features/rageshake/impl/src/test/kotlin/io/element/android/features/rageshake/impl/bugreport/BugReportPresenterTest.kt
@@ -225,15 +225,15 @@ class BugReportPresenterTest {
assertThat(awaitItem().sending).isEqualTo(AsyncAction.Uninitialized)
}
}
-
- private fun TestScope.createPresenter(
- bugReporter: BugReporter = FakeBugReporter(),
- crashDataStore: CrashDataStore = FakeCrashDataStore(),
- screenshotHolder: ScreenshotHolder = FakeScreenshotHolder(),
- ) = BugReportPresenter(
- bugReporter = bugReporter,
- crashDataStore = crashDataStore,
- screenshotHolder = screenshotHolder,
- appCoroutineScope = this,
- )
}
+
+internal fun TestScope.createPresenter(
+ bugReporter: BugReporter = FakeBugReporter(),
+ crashDataStore: CrashDataStore = FakeCrashDataStore(),
+ screenshotHolder: ScreenshotHolder = FakeScreenshotHolder(),
+) = BugReportPresenter(
+ bugReporter = bugReporter,
+ crashDataStore = crashDataStore,
+ screenshotHolder = screenshotHolder,
+ appCoroutineScope = this,
+)
diff --git a/features/rageshake/impl/src/test/kotlin/io/element/android/features/rageshake/impl/bugreport/DefaultBugReportEntryPointTest.kt b/features/rageshake/impl/src/test/kotlin/io/element/android/features/rageshake/impl/bugreport/DefaultBugReportEntryPointTest.kt
new file mode 100644
index 0000000000..23d74f7247
--- /dev/null
+++ b/features/rageshake/impl/src/test/kotlin/io/element/android/features/rageshake/impl/bugreport/DefaultBugReportEntryPointTest.kt
@@ -0,0 +1,51 @@
+/*
+ * Copyright 2025 New Vector Ltd.
+ *
+ * SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial
+ * Please see LICENSE files in the repository root for full details.
+ */
+
+package io.element.android.features.rageshake.impl.bugreport
+
+import androidx.arch.core.executor.testing.InstantTaskExecutorRule
+import com.bumble.appyx.core.modality.BuildContext
+import com.bumble.appyx.core.node.Node
+import com.bumble.appyx.testing.junit4.util.MainDispatcherRule
+import com.google.common.truth.Truth.assertThat
+import io.element.android.features.rageshake.api.bugreport.BugReportEntryPoint
+import io.element.android.features.viewfolder.api.ViewFolderEntryPoint
+import io.element.android.tests.testutils.lambda.lambdaError
+import io.element.android.tests.testutils.node.TestParentNode
+import kotlinx.coroutines.test.runTest
+import org.junit.Rule
+import org.junit.Test
+
+class DefaultBugReportEntryPointTest {
+ @get:Rule
+ val instantTaskExecutorRule = InstantTaskExecutorRule()
+
+ @get:Rule
+ val mainDispatcherRule = MainDispatcherRule()
+
+ @Test
+ fun `test node builder`() = runTest {
+ val entryPoint = DefaultBugReportEntryPoint()
+ val parentNode = TestParentNode.create { buildContext, plugins ->
+ BugReportFlowNode(
+ buildContext = buildContext,
+ plugins = plugins,
+ viewFolderEntryPoint = object : ViewFolderEntryPoint {
+ override fun nodeBuilder(parentNode: Node, buildContext: BuildContext) = lambdaError()
+ },
+ )
+ }
+ val callback = object : BugReportEntryPoint.Callback {
+ override fun onDone() = lambdaError()
+ }
+ val result = entryPoint.nodeBuilder(parentNode, BuildContext.root(null))
+ .callback(callback)
+ .build()
+ assertThat(result).isInstanceOf(BugReportFlowNode::class.java)
+ assertThat(result.plugins).contains(callback)
+ }
+}
diff --git a/features/reportroom/api/src/main/kotlin/io/element/android/features/reportroom/api/ReportRoomEntryPoint.kt b/features/reportroom/api/src/main/kotlin/io/element/android/features/reportroom/api/ReportRoomEntryPoint.kt
index 7f531fb9e3..1eff7f8206 100644
--- a/features/reportroom/api/src/main/kotlin/io/element/android/features/reportroom/api/ReportRoomEntryPoint.kt
+++ b/features/reportroom/api/src/main/kotlin/io/element/android/features/reportroom/api/ReportRoomEntryPoint.kt
@@ -12,6 +12,6 @@ import com.bumble.appyx.core.node.Node
import io.element.android.libraries.architecture.FeatureEntryPoint
import io.element.android.libraries.matrix.api.core.RoomId
-interface ReportRoomEntryPoint : FeatureEntryPoint {
+fun interface ReportRoomEntryPoint : FeatureEntryPoint {
fun createNode(parentNode: Node, buildContext: BuildContext, roomId: RoomId): Node
}
diff --git a/features/reportroom/impl/build.gradle.kts b/features/reportroom/impl/build.gradle.kts
index 797fa08741..99d65612bd 100644
--- a/features/reportroom/impl/build.gradle.kts
+++ b/features/reportroom/impl/build.gradle.kts
@@ -6,6 +6,7 @@
*/
import extension.setupDependencyInjection
+import extension.testCommonDependencies
plugins {
id("io.element.android-compose-library")
@@ -32,14 +33,6 @@ dependencies {
implementation(projects.libraries.designsystem)
implementation(projects.libraries.uiStrings)
- testImplementation(libs.test.junit)
- testImplementation(libs.coroutines.test)
- testImplementation(libs.molecule.runtime)
- testImplementation(libs.test.truth)
- testImplementation(libs.test.turbine)
+ testCommonDependencies(libs, true)
testImplementation(projects.libraries.matrix.test)
- testImplementation(projects.tests.testutils)
- testImplementation(libs.androidx.compose.ui.test.junit)
- testReleaseImplementation(libs.androidx.compose.ui.test.manifest)
- testImplementation(libs.test.robolectric)
}
diff --git a/features/reportroom/impl/src/main/kotlin/io/element/android/features/reportroom/impl/ReportRoomPresenter.kt b/features/reportroom/impl/src/main/kotlin/io/element/android/features/reportroom/impl/ReportRoomPresenter.kt
index fccea0e576..f47ab19004 100644
--- a/features/reportroom/impl/src/main/kotlin/io/element/android/features/reportroom/impl/ReportRoomPresenter.kt
+++ b/features/reportroom/impl/src/main/kotlin/io/element/android/features/reportroom/impl/ReportRoomPresenter.kt
@@ -31,7 +31,7 @@ class ReportRoomPresenter(
private val reportRoom: ReportRoom,
) : Presenter {
@AssistedFactory
- interface Factory {
+ fun interface Factory {
fun create(roomId: RoomId): ReportRoomPresenter
}
diff --git a/features/reportroom/impl/src/test/kotlin/io/element/android/features/reportroom/impl/DefaultReportRoomEntryPointTest.kt b/features/reportroom/impl/src/test/kotlin/io/element/android/features/reportroom/impl/DefaultReportRoomEntryPointTest.kt
new file mode 100644
index 0000000000..c9f850062e
--- /dev/null
+++ b/features/reportroom/impl/src/test/kotlin/io/element/android/features/reportroom/impl/DefaultReportRoomEntryPointTest.kt
@@ -0,0 +1,39 @@
+/*
+ * Copyright 2025 New Vector Ltd.
+ *
+ * SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial
+ * Please see LICENSE files in the repository root for full details.
+ */
+
+package io.element.android.features.reportroom.impl
+
+import androidx.arch.core.executor.testing.InstantTaskExecutorRule
+import com.bumble.appyx.core.modality.BuildContext
+import com.google.common.truth.Truth.assertThat
+import io.element.android.libraries.matrix.test.A_ROOM_ID
+import io.element.android.tests.testutils.node.TestParentNode
+import org.junit.Rule
+import org.junit.Test
+
+class DefaultReportRoomEntryPointTest {
+ @get:Rule
+ val instantTaskExecutorRule = InstantTaskExecutorRule()
+
+ @Test
+ fun `test node builder`() {
+ val entryPoint = DefaultReportRoomEntryPoint()
+ val parentNode = TestParentNode.create { buildContext, plugins ->
+ ReportRoomNode(
+ buildContext = buildContext,
+ plugins = plugins,
+ presenterFactory = { roomId ->
+ assertThat(roomId).isEqualTo(A_ROOM_ID)
+ createReportRoomPresenter()
+ }
+ )
+ }
+ val result = entryPoint.createNode(parentNode, BuildContext.root(null), A_ROOM_ID)
+ assertThat(result).isInstanceOf(ReportRoomNode::class.java)
+ assertThat(result.plugins).contains(ReportRoomNode.Inputs(A_ROOM_ID))
+ }
+}
diff --git a/features/reportroom/impl/src/test/kotlin/io/element/android/features/reportroom/impl/ReportRoomPresenterTest.kt b/features/reportroom/impl/src/test/kotlin/io/element/android/features/reportroom/impl/ReportRoomPresenterTest.kt
index d85f2b86e8..eb2e94366d 100644
--- a/features/reportroom/impl/src/test/kotlin/io/element/android/features/reportroom/impl/ReportRoomPresenterTest.kt
+++ b/features/reportroom/impl/src/test/kotlin/io/element/android/features/reportroom/impl/ReportRoomPresenterTest.kt
@@ -141,11 +141,11 @@ class ReportRoomPresenterTest {
)
}
}
-
- fun createReportRoomPresenter(
- roomId: RoomId = A_ROOM_ID,
- reportRoom: ReportRoom = FakeReportRoom()
- ): ReportRoomPresenter {
- return ReportRoomPresenter(roomId, reportRoom)
- }
+}
+
+internal fun createReportRoomPresenter(
+ roomId: RoomId = A_ROOM_ID,
+ reportRoom: ReportRoom = FakeReportRoom()
+): ReportRoomPresenter {
+ return ReportRoomPresenter(roomId, reportRoom)
}
diff --git a/features/roomaliasresolver/impl/build.gradle.kts b/features/roomaliasresolver/impl/build.gradle.kts
index f70f2a6f7b..45cf32f661 100644
--- a/features/roomaliasresolver/impl/build.gradle.kts
+++ b/features/roomaliasresolver/impl/build.gradle.kts
@@ -1,4 +1,5 @@
import extension.setupDependencyInjection
+import extension.testCommonDependencies
/*
* Copyright 2024 New Vector Ltd.
@@ -33,14 +34,6 @@ dependencies {
implementation(projects.libraries.designsystem)
implementation(projects.libraries.uiStrings)
- testImplementation(libs.test.junit)
- testImplementation(libs.coroutines.test)
- testImplementation(libs.molecule.runtime)
- testImplementation(libs.test.robolectric)
- testImplementation(libs.test.truth)
- testImplementation(libs.test.turbine)
+ testCommonDependencies(libs, true)
testImplementation(projects.libraries.matrix.test)
- testImplementation(projects.tests.testutils)
- testImplementation(libs.androidx.compose.ui.test.junit)
- testReleaseImplementation(libs.androidx.compose.ui.test.manifest)
}
diff --git a/features/roomaliasresolver/impl/src/main/kotlin/io/element/android/features/roomaliasresolver/impl/RoomAliasResolverPresenter.kt b/features/roomaliasresolver/impl/src/main/kotlin/io/element/android/features/roomaliasresolver/impl/RoomAliasResolverPresenter.kt
index 95ed62a819..9b65d3e14a 100644
--- a/features/roomaliasresolver/impl/src/main/kotlin/io/element/android/features/roomaliasresolver/impl/RoomAliasResolverPresenter.kt
+++ b/features/roomaliasresolver/impl/src/main/kotlin/io/element/android/features/roomaliasresolver/impl/RoomAliasResolverPresenter.kt
@@ -30,7 +30,7 @@ class RoomAliasResolverPresenter(
@Assisted private val roomAlias: RoomAlias,
private val matrixClient: MatrixClient,
) : Presenter {
- interface Factory {
+ fun interface Factory {
fun create(
roomAlias: RoomAlias,
): RoomAliasResolverPresenter
diff --git a/features/roomaliasresolver/impl/src/main/kotlin/io/element/android/features/roomaliasresolver/impl/RoomAliasResolverView.kt b/features/roomaliasresolver/impl/src/main/kotlin/io/element/android/features/roomaliasresolver/impl/RoomAliasResolverView.kt
index ef2cc47ecc..9d7536b2f5 100644
--- a/features/roomaliasresolver/impl/src/main/kotlin/io/element/android/features/roomaliasresolver/impl/RoomAliasResolverView.kt
+++ b/features/roomaliasresolver/impl/src/main/kotlin/io/element/android/features/roomaliasresolver/impl/RoomAliasResolverView.kt
@@ -117,7 +117,7 @@ private fun RoomAliasResolverContent(
RoomPreviewOrganism(
modifier = modifier,
avatar = {
- PlaceholderAtom(width = AvatarSize.RoomHeader.dp, height = AvatarSize.RoomHeader.dp)
+ PlaceholderAtom(width = AvatarSize.RoomPreviewHeader.dp, height = AvatarSize.RoomPreviewHeader.dp)
},
title = {
RoomPreviewSubtitleAtom(roomAlias.value)
diff --git a/features/roomaliasresolver/impl/src/test/kotlin/io/element/android/features/roomaliasresolver/impl/DefaultRoomAliasResolverEntryPointTest.kt b/features/roomaliasresolver/impl/src/test/kotlin/io/element/android/features/roomaliasresolver/impl/DefaultRoomAliasResolverEntryPointTest.kt
new file mode 100644
index 0000000000..238b35017b
--- /dev/null
+++ b/features/roomaliasresolver/impl/src/test/kotlin/io/element/android/features/roomaliasresolver/impl/DefaultRoomAliasResolverEntryPointTest.kt
@@ -0,0 +1,54 @@
+/*
+ * Copyright 2025 New Vector Ltd.
+ *
+ * SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial
+ * Please see LICENSE files in the repository root for full details.
+ */
+
+package io.element.android.features.roomaliasresolver.impl
+
+import androidx.arch.core.executor.testing.InstantTaskExecutorRule
+import com.bumble.appyx.core.modality.BuildContext
+import com.google.common.truth.Truth.assertThat
+import io.element.android.features.roomaliasesolver.api.RoomAliasResolverEntryPoint
+import io.element.android.libraries.matrix.api.room.alias.ResolvedRoomAlias
+import io.element.android.libraries.matrix.test.A_ROOM_ALIAS
+import io.element.android.tests.testutils.lambda.lambdaError
+import io.element.android.tests.testutils.node.TestParentNode
+import org.junit.Rule
+import org.junit.Test
+
+class DefaultRoomAliasResolverEntryPointTest {
+ @get:Rule
+ val instantTaskExecutorRule = InstantTaskExecutorRule()
+
+ @Test
+ fun `test node builder`() {
+ val entryPoint = DefaultRoomAliasResolverEntryPoint()
+ val parentNode = TestParentNode.create { buildContext, plugins ->
+ RoomAliasResolverNode(
+ buildContext = buildContext,
+ plugins = plugins,
+ presenterFactory = { alias ->
+ assertThat(alias).isEqualTo(A_ROOM_ALIAS)
+ createPresenter(
+ alias,
+ )
+ }
+ )
+ }
+ val callback = object : RoomAliasResolverEntryPoint.Callback {
+ override fun onAliasResolved(data: ResolvedRoomAlias) = lambdaError()
+ }
+ val params = RoomAliasResolverEntryPoint.Params(
+ roomAlias = A_ROOM_ALIAS
+ )
+ val result = entryPoint.nodeBuilder(parentNode, BuildContext.root(null))
+ .params(params)
+ .callback(callback)
+ .build()
+ assertThat(result).isInstanceOf(RoomAliasResolverNode::class.java)
+ assertThat(result.plugins).contains(params)
+ assertThat(result.plugins).contains(callback)
+ }
+}
diff --git a/features/roomaliasresolver/impl/src/test/kotlin/io/element/android/features/roomaliasresolver/impl/RoomAliasHelperPresenterTest.kt b/features/roomaliasresolver/impl/src/test/kotlin/io/element/android/features/roomaliasresolver/impl/RoomAliasHelperPresenterTest.kt
index 3071d8943a..f90b07c91b 100644
--- a/features/roomaliasresolver/impl/src/test/kotlin/io/element/android/features/roomaliasresolver/impl/RoomAliasHelperPresenterTest.kt
+++ b/features/roomaliasresolver/impl/src/test/kotlin/io/element/android/features/roomaliasresolver/impl/RoomAliasHelperPresenterTest.kt
@@ -79,16 +79,16 @@ class RoomAliasHelperPresenterTest {
assertThat(retryState.resolveState.errorOrNull()).isEqualTo(AN_EXCEPTION)
}
}
-
- private fun createPresenter(
- roomAlias: RoomAlias = A_ROOM_ALIAS,
- matrixClient: MatrixClient = FakeMatrixClient(),
- ) = RoomAliasResolverPresenter(
- roomAlias = roomAlias,
- matrixClient = matrixClient,
- )
}
+internal fun createPresenter(
+ roomAlias: RoomAlias = A_ROOM_ALIAS,
+ matrixClient: MatrixClient = FakeMatrixClient(),
+) = RoomAliasResolverPresenter(
+ roomAlias = roomAlias,
+ matrixClient = matrixClient,
+)
+
internal fun aResolvedRoomAlias(
roomId: RoomId = A_ROOM_ID,
servers: List = A_SERVER_LIST,
diff --git a/features/roomcall/impl/build.gradle.kts b/features/roomcall/impl/build.gradle.kts
index 5c69ffed36..7a6a3cf0a6 100644
--- a/features/roomcall/impl/build.gradle.kts
+++ b/features/roomcall/impl/build.gradle.kts
@@ -1,4 +1,5 @@
import extension.setupDependencyInjection
+import extension.testCommonDependencies
/*
* Copyright 2024 New Vector Ltd.
@@ -26,15 +27,8 @@ dependencies {
implementation(projects.libraries.matrix.api)
implementation(projects.libraries.matrixui)
- testImplementation(libs.test.junit)
- testImplementation(libs.coroutines.test)
- testImplementation(libs.molecule.runtime)
- testImplementation(libs.test.truth)
- testImplementation(libs.test.turbine)
+ testCommonDependencies(libs, true)
testImplementation(projects.libraries.matrix.test)
testImplementation(projects.features.call.test)
testImplementation(projects.features.enterprise.test)
- testImplementation(projects.tests.testutils)
- testImplementation(libs.androidx.compose.ui.test.junit)
- testReleaseImplementation(libs.androidx.compose.ui.test.manifest)
}
diff --git a/features/roomdetails/impl/build.gradle.kts b/features/roomdetails/impl/build.gradle.kts
index fa5569a873..882058ef48 100644
--- a/features/roomdetails/impl/build.gradle.kts
+++ b/features/roomdetails/impl/build.gradle.kts
@@ -1,4 +1,5 @@
import extension.setupDependencyInjection
+import extension.testCommonDependencies
/*
* Copyright 2023, 2024 New Vector Ltd.
@@ -58,13 +59,7 @@ dependencies {
implementation(projects.features.changeroommemberroles.api)
implementation(projects.features.invitepeople.api)
- testImplementation(libs.test.junit)
- testImplementation(libs.coroutines.test)
- testImplementation(libs.molecule.runtime)
- testImplementation(libs.test.truth)
- testImplementation(libs.test.turbine)
- testImplementation(libs.test.mockk)
- testImplementation(libs.test.robolectric)
+ testCommonDependencies(libs, true)
testImplementation(projects.libraries.matrix.test)
testImplementation(projects.libraries.mediaupload.test)
testImplementation(projects.libraries.mediapickers.test)
@@ -72,9 +67,6 @@ dependencies {
testImplementation(projects.libraries.preferences.test)
testImplementation(projects.libraries.usersearch.test)
testImplementation(projects.libraries.featureflag.test)
- testImplementation(projects.tests.testutils)
testImplementation(projects.features.startchat.test)
testImplementation(projects.services.analytics.test)
- testImplementation(libs.androidx.compose.ui.test.junit)
- testReleaseImplementation(libs.androidx.compose.ui.test.manifest)
}
diff --git a/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/RoomDetailsStateProvider.kt b/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/RoomDetailsStateProvider.kt
index e41392ee76..c9087d6458 100644
--- a/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/RoomDetailsStateProvider.kt
+++ b/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/RoomDetailsStateProvider.kt
@@ -67,7 +67,6 @@ fun aDmRoomMember(
membership: RoomMembershipState = RoomMembershipState.JOIN,
isNameAmbiguous: Boolean = false,
powerLevel: Long = 0,
- normalizedPowerLevel: Long = powerLevel,
isIgnored: Boolean = false,
role: RoomMember.Role = RoomMember.Role.User,
membershipChangeReason: String? = null,
@@ -78,7 +77,6 @@ fun aDmRoomMember(
membership = membership,
isNameAmbiguous = isNameAmbiguous,
powerLevel = powerLevel,
- normalizedPowerLevel = normalizedPowerLevel,
isIgnored = isIgnored,
role = role,
membershipChangeReason = membershipChangeReason
diff --git a/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/RoomDetailsView.kt b/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/RoomDetailsView.kt
index 3fdb2a0800..61d5ba115a 100644
--- a/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/RoomDetailsView.kt
+++ b/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/RoomDetailsView.kt
@@ -396,10 +396,10 @@ private fun RoomHeaderSection(
horizontalAlignment = Alignment.CenterHorizontally,
) {
Avatar(
- avatarData = AvatarData(roomId.value, roomName, avatarUrl, AvatarSize.RoomHeader),
+ avatarData = AvatarData(roomId.value, roomName, avatarUrl, AvatarSize.RoomDetailsHeader),
avatarType = AvatarType.Room(
heroes = heroes.map { user ->
- user.getAvatarData(size = AvatarSize.RoomHeader)
+ user.getAvatarData(size = AvatarSize.RoomDetailsHeader)
}.toPersistentList(),
isTombstoned = isTombstoned,
),
diff --git a/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/invite/RoomInviteMembersNode.kt b/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/invite/RoomInviteMembersNode.kt
index 6c69f0ee5d..04b98e3d98 100644
--- a/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/invite/RoomInviteMembersNode.kt
+++ b/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/invite/RoomInviteMembersNode.kt
@@ -8,6 +8,7 @@
package io.element.android.features.roomdetails.impl.invite
import androidx.compose.runtime.Composable
+import androidx.compose.runtime.LaunchedEffect
import androidx.compose.ui.Modifier
import com.bumble.appyx.core.lifecycle.subscribe
import com.bumble.appyx.core.modality.BuildContext
@@ -49,11 +50,18 @@ class RoomInviteMembersNode(
@Composable
override fun View(modifier: Modifier) {
val state = invitePeoplePresenter.present()
+
+ // Once invites have been sent successfully, close the Invite view.
+ LaunchedEffect(state.sendInvitesAction) {
+ if (state.sendInvitesAction.isReady()) {
+ navigateUp()
+ }
+ }
+
RoomInviteMembersView(
state = state,
modifier = modifier,
- onBackClick = { navigateUp() },
- onDone = { navigateUp() }
+ onBackClick = { navigateUp() }
) {
invitePeopleRenderer.Render(state, Modifier)
}
diff --git a/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/invite/RoomInviteMembersView.kt b/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/invite/RoomInviteMembersView.kt
index 8bec90707f..f7991a6e44 100644
--- a/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/invite/RoomInviteMembersView.kt
+++ b/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/invite/RoomInviteMembersView.kt
@@ -8,22 +8,29 @@
package io.element.android.features.roomdetails.impl.invite
import androidx.compose.foundation.layout.Box
+import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.consumeWindowInsets
import androidx.compose.foundation.layout.fillMaxWidth
+import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.material3.ExperimentalMaterial3Api
+import androidx.compose.material3.MaterialTheme
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.tooling.preview.PreviewParameter
+import androidx.compose.ui.unit.dp
+import io.element.android.compound.theme.ElementTheme
import io.element.android.features.invitepeople.api.InvitePeopleEvents
import io.element.android.features.invitepeople.api.InvitePeopleState
import io.element.android.features.invitepeople.api.InvitePeopleStateProvider
import io.element.android.features.roomdetails.impl.R
+import io.element.android.libraries.designsystem.components.ProgressDialog
import io.element.android.libraries.designsystem.components.button.BackButton
import io.element.android.libraries.designsystem.preview.ElementPreview
import io.element.android.libraries.designsystem.preview.PreviewsDayNight
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.TextButton
import io.element.android.libraries.designsystem.theme.components.TopAppBar
import io.element.android.libraries.ui.strings.CommonStrings
@@ -32,7 +39,6 @@ import io.element.android.libraries.ui.strings.CommonStrings
fun RoomInviteMembersView(
state: InvitePeopleState,
onBackClick: () -> Unit,
- onDone: () -> Unit,
modifier: Modifier = Modifier,
invitePeopleView: @Composable () -> Unit,
) {
@@ -49,7 +55,6 @@ fun RoomInviteMembersView(
},
onSubmitClick = {
state.eventSink(InvitePeopleEvents.SendInvites)
- onDone()
},
canSend = state.canInvite,
)
@@ -64,6 +69,10 @@ fun RoomInviteMembersView(
invitePeopleView()
}
}
+
+ if (state.sendInvitesAction.isLoading()) {
+ InviteProgressDialog()
+ }
}
@OptIn(ExperimentalMaterial3Api::class)
@@ -86,6 +95,24 @@ private fun RoomInviteMembersTopBar(
)
}
+@Composable
+private fun InviteProgressDialog() {
+ ProgressDialog {
+ Spacer(modifier = Modifier.height(8.dp))
+ Text(
+ text = stringResource(R.string.screen_room_details_invite_people_preparing),
+ color = ElementTheme.colors.textPrimary,
+ style = ElementTheme.typography.fontHeadingSmMedium,
+ )
+ Spacer(modifier = Modifier.height(16.dp))
+ Text(
+ text = stringResource(R.string.screen_room_details_invite_people_dont_close),
+ color = ElementTheme.colors.textSecondary,
+ style = MaterialTheme.typography.bodyMedium,
+ )
+ }
+}
+
@PreviewsDayNight
@Composable
internal fun RoomInviteMembersViewPreview(@PreviewParameter(InvitePeopleStateProvider::class) state: InvitePeopleState) = ElementPreview {
@@ -93,6 +120,5 @@ internal fun RoomInviteMembersViewPreview(@PreviewParameter(InvitePeopleStatePro
state = state,
invitePeopleView = {},
onBackClick = {},
- onDone = {},
)
}
diff --git a/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/members/RoomMemberListStateProvider.kt b/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/members/RoomMemberListStateProvider.kt
index 52acb6ebd6..a1cc9c3b92 100644
--- a/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/members/RoomMemberListStateProvider.kt
+++ b/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/members/RoomMemberListStateProvider.kt
@@ -148,7 +148,6 @@ fun aRoomMember(
membership: RoomMembershipState = RoomMembershipState.JOIN,
isNameAmbiguous: Boolean = false,
powerLevel: Long = 0L,
- normalizedPowerLevel: Long = 0L,
isIgnored: Boolean = false,
role: RoomMember.Role = RoomMember.Role.User,
membershipChangeReason: String? = null,
@@ -159,7 +158,6 @@ fun aRoomMember(
membership = membership,
isNameAmbiguous = isNameAmbiguous,
powerLevel = powerLevel,
- normalizedPowerLevel = normalizedPowerLevel,
isIgnored = isIgnored,
role = role,
membershipChangeReason = membershipChangeReason,
diff --git a/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/rolesandpermissions/permissions/ChangeRoomPermissionsNode.kt b/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/rolesandpermissions/permissions/ChangeRoomPermissionsNode.kt
index 2a3e5a2bad..906c97fb2e 100644
--- a/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/rolesandpermissions/permissions/ChangeRoomPermissionsNode.kt
+++ b/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/rolesandpermissions/permissions/ChangeRoomPermissionsNode.kt
@@ -34,10 +34,7 @@ class ChangeRoomPermissionsNode(
) : NodeInputs, Parcelable
private val inputs: Inputs = inputs()
-
- private val presenter = presenterFactory.run {
- create(inputs.section)
- }
+ private val presenter = presenterFactory.create(inputs.section)
@Composable
override fun View(modifier: Modifier) {
diff --git a/features/roomdetails/impl/src/main/res/values-cs/translations.xml b/features/roomdetails/impl/src/main/res/values-cs/translations.xml
index 9cc7f7b45d..e5186f1d4f 100644
--- a/features/roomdetails/impl/src/main/res/values-cs/translations.xml
+++ b/features/roomdetails/impl/src/main/res/values-cs/translations.xml
@@ -50,6 +50,8 @@
"Při načítání nastavení oznámení došlo k chybě."
"Ztišení této místnosti se nezdařilo, zkuste to prosím znovu."
"Nepodařilo se zrušit ztišení této místnosti, zkuste to prosím znovu."
+ "Nezavírejte aplikaci, dokud neskončíte."
+ "Příprava pozvánek…"
"Pozvat přátele"
"Opustit konverzaci"
"Opustit místnost"
diff --git a/features/roomdetails/impl/src/main/res/values-cy/translations.xml b/features/roomdetails/impl/src/main/res/values-cy/translations.xml
index 80726aa1f8..40c404d69b 100644
--- a/features/roomdetails/impl/src/main/res/values-cy/translations.xml
+++ b/features/roomdetails/impl/src/main/res/values-cy/translations.xml
@@ -7,7 +7,7 @@
"Pleidleisiau"
"Gweinyddwyr yn unig"
"Gwahardd pobl"
- "Dileu negeseuon"
+ "Tynnu negeseuon"
"Pawb"
"Gwahodd pobl a derbyn ceisiadau i ymuno"
"Cymedroli aelodau"
@@ -22,13 +22,17 @@
"Golygu Gweinyddwyr"
"Fyddwch chi ddim yn gallu dadwneud y weithred hon. Rydych chi\'n hyrwyddo\'r defnyddiwr i gael yr un lefel pŵer â chi."
"Ychwanegu Gweinyddwr?"
+ "Fyddwch chi ddim yn gallu dadwneud y weithred hon. Rydych yn trosglwyddo\'r berchnogaeth i\'r defnyddwyr a ddewiswyd. Unwaith y byddwch yn gadael bydd hyn yn barhaol."
+ "Trosglwyddo perchnogaeth?"
"Gostwng"
"Fyddwch chi ddim yn gallu dadwneud y newid hwn gan eich bod yn israddio eich hun, os mai chi yw\'r defnyddiwr breintiedig olaf yn yr ystafell bydd yn amhosibl adennill breintiau."
"Israddio eich hun?"
"%1$s (Yn aros)"
"Yn aros"
"Mae gan weinyddwyr freintiau cymedrolwr yn awtomatig"
+ "Mae gan berchnogion freintiau gweinyddwr yn awtomatig."
"Golygu Cymedrolwyr"
+ "Dewiswch Berchnogion"
"Gweinyddwyr"
"Cymedrolwyr"
"Aelodau"
@@ -46,6 +50,8 @@
"Digwyddodd gwall wrth lwytho gosodiadau hysbysu."
"Wedi methu tewi\'r ystafell hon, ceisiwch eto."
"Wedi methu dad-dewi\'r ystafell hon, ceisiwch eto."
+ "Peidiwch â chau\'r ap nes ei fod wedi gorffen."
+ "Wrthi\'n paratoi gwahoddiadau…"
"Gwahodd pobl"
"Gadael y sgwrs"
"Gadael yr ystafell"
@@ -83,6 +89,7 @@
"Dan ystyriaeth"
"Gweinyddwr"
"Cymedrolwr"
+ "Perchennog"
"Aelodau\'r ystafell"
"Dad-wahardd %1$s"
"Caniatáu gosodiad personol"
@@ -100,12 +107,14 @@
"Crybwylliadau ac Allweddeiriau\'n unig"
"Yn yr ystafell hon, rhowch wybod i mi am"
"Gweinyddwyr"
+ "Gweinyddwyr a pherchnogion"
"Newid fy rôl"
"Israddio aelod"
"Israddio cymedrolwr"
"Cymedroli aelodau"
"Negeseuon a chynnwys"
"Cymedrolwyr"
+ "Perchnogion"
"Caniatâd"
"Ailosod caniatâd"
"Ar ôl i chi ailosod caniatâd, byddwch yn colli\'r gosodiadau cyfredol."
diff --git a/features/roomdetails/impl/src/main/res/values-de/translations.xml b/features/roomdetails/impl/src/main/res/values-de/translations.xml
index 3bf75e97e2..4a4f8a44b6 100644
--- a/features/roomdetails/impl/src/main/res/values-de/translations.xml
+++ b/features/roomdetails/impl/src/main/res/values-de/translations.xml
@@ -50,6 +50,8 @@
"Beim Laden der Benachrichtigungseinstellungen ist ein Fehler aufgetreten."
"Die Stummschaltung ist fehlgeschlagen, bitte versuche es erneut."
"Die Deaktivierung der Stummschaltung ist fehlgeschlagen, bitte versuche es erneut."
+ "Schließ die App erst, wenn du fertig bist."
+ "Einladungen werden vorbereitet…"
"Nutzer einladen"
"Unterhaltung verlassen"
"Verlassen"
diff --git a/features/roomdetails/impl/src/main/res/values-eo/translations.xml b/features/roomdetails/impl/src/main/res/values-eo/translations.xml
new file mode 100644
index 0000000000..46471ca4f3
--- /dev/null
+++ b/features/roomdetails/impl/src/main/res/values-eo/translations.xml
@@ -0,0 +1,4 @@
+
+
+ "Messages are secured with locks. Only you and the recipients can unlock them."
+
diff --git a/features/roomdetails/impl/src/main/res/values-et/translations.xml b/features/roomdetails/impl/src/main/res/values-et/translations.xml
index 4426ca1e77..6de3107def 100644
--- a/features/roomdetails/impl/src/main/res/values-et/translations.xml
+++ b/features/roomdetails/impl/src/main/res/values-et/translations.xml
@@ -50,6 +50,8 @@
"Teavituste seadistuste laadimisel tekkis viga."
"Selle jututoa summutamine ei õnnestunud. Palun proovi uuesti."
"Selle jututoa summutamise eemaldamine ei õnnestunud. Palun proovi uuesti."
+ "Ära sulge rakendust enne, kui tegevus on lõppenud."
+ "Valmistan kutseid ette…"
"Kutsu osalejaid"
"Lahku vestlusest"
"Lahku jututoast"
diff --git a/features/roomdetails/impl/src/main/res/values-fi/translations.xml b/features/roomdetails/impl/src/main/res/values-fi/translations.xml
index 04c1411e50..e77b0ab2c6 100644
--- a/features/roomdetails/impl/src/main/res/values-fi/translations.xml
+++ b/features/roomdetails/impl/src/main/res/values-fi/translations.xml
@@ -21,12 +21,12 @@
"Viestien lähettäminen"
"Muokkaa ylläpitäjiä"
"Et voi peruuttaa tätä toimenpidettä. Ylennät käyttäjän samalle oikeustasolle kuin sinä."
- "Lisää ylläpitäjä?"
+ "Lisätäänkö ylläpitäjä?"
"Et voi kumota tätä toimintoa. Olet siirtämässä omistajuuden valituille käyttäjille. Kun poistut, muutos on pysyvä."
"Siirretäänkö omistajuus?"
"Alenna"
"Et voi perua tätä muutosta, koska olet alentamassa itseäsi. Jos olet viimeinen oikeutettu henkilö tässä huoneessa, oikeuksia ei voi enää saada takaisin."
- "Alenna itsesi?"
+ "Haluatko alentaa itsesi?"
"%1$s (Kutsuttu)"
"(Kutsuttu)"
"Ylläpitäjillä on automaattisesti valvojan oikeudet"
@@ -37,7 +37,7 @@
"Valvojat"
"Jäsenet"
"Sinulla on tallentamattomia muutoksia"
- "Tallenna muutokset?"
+ "Tallennetaanko muutokset?"
"Lisää aihe"
"Salattu"
"Ei salattu"
@@ -50,6 +50,8 @@
"Ilmoitusasetuksia ladattaessa tapahtui virhe."
"Tämän huoneen mykistäminen epäonnistui, yritä uudelleen."
"Tämän huoneen mykistyksen poistaminen epäonnistui, yritä uudelleen."
+ "Älä sulje sovellusta ennen kuin se on valmis."
+ "Valmistellaan kutsuja…"
"Kutsu ihmisiä"
"Poistu keskustelusta"
"Poistu huoneesta"
diff --git a/features/roomdetails/impl/src/main/res/values-fr/translations.xml b/features/roomdetails/impl/src/main/res/values-fr/translations.xml
index 066ce1ee0f..feea21919d 100644
--- a/features/roomdetails/impl/src/main/res/values-fr/translations.xml
+++ b/features/roomdetails/impl/src/main/res/values-fr/translations.xml
@@ -50,6 +50,7 @@
"Une erreur s’est produite lors du chargement des paramètres de notification."
"Échec de la mise en sourdine de ce salon, veuillez réessayer."
"Échec de la désactivation de la mise en sourdine de ce salon, veuillez réessayer."
+ "Préparation des invitations…"
"Inviter des amis"
"Quitter la discussion"
"Quitter le salon"
diff --git a/features/roomdetails/impl/src/main/res/values-zh-rTW/translations.xml b/features/roomdetails/impl/src/main/res/values-zh-rTW/translations.xml
index d2d6d0ef90..035de6fa4d 100644
--- a/features/roomdetails/impl/src/main/res/values-zh-rTW/translations.xml
+++ b/features/roomdetails/impl/src/main/res/values-zh-rTW/translations.xml
@@ -50,6 +50,8 @@
"載入通知設定時發生錯誤。"
"無法關閉聊天室通知,請再試一次。"
"無法開啟聊天室通知,請再試一次。"
+ "完成前請勿關閉應用程式。"
+ "正在準備邀請……"
"邀請夥伴"
"離開對話"
"離開聊天室"
diff --git a/features/roomdetails/impl/src/main/res/values/localazy.xml b/features/roomdetails/impl/src/main/res/values/localazy.xml
index 5dd185ec13..3f4541dacb 100644
--- a/features/roomdetails/impl/src/main/res/values/localazy.xml
+++ b/features/roomdetails/impl/src/main/res/values/localazy.xml
@@ -50,6 +50,8 @@
"An error occurred when loading notification settings."
"Failed muting this room, please try again."
"Failed unmuting this room, please try again."
+ "Don\'t close the app until finished."
+ "Preparing invitations…"
"Invite people"
"Leave conversation"
"Leave room"
diff --git a/features/roomdetails/impl/src/test/kotlin/io/element/android/features/roomdetails/impl/DefaultRoomDetailsEntryPointTest.kt b/features/roomdetails/impl/src/test/kotlin/io/element/android/features/roomdetails/impl/DefaultRoomDetailsEntryPointTest.kt
new file mode 100644
index 0000000000..f2412e616b
--- /dev/null
+++ b/features/roomdetails/impl/src/test/kotlin/io/element/android/features/roomdetails/impl/DefaultRoomDetailsEntryPointTest.kt
@@ -0,0 +1,123 @@
+/*
+ * Copyright 2025 New Vector Ltd.
+ *
+ * SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial
+ * Please see LICENSE files in the repository root for full details.
+ */
+
+package io.element.android.features.roomdetails.impl
+
+import androidx.arch.core.executor.testing.InstantTaskExecutorRule
+import com.bumble.appyx.core.modality.BuildContext
+import com.bumble.appyx.core.node.Node
+import com.bumble.appyx.testing.junit4.util.MainDispatcherRule
+import com.google.common.truth.Truth.assertThat
+import io.element.android.features.call.api.CallType
+import io.element.android.features.call.api.ElementCallEntryPoint
+import io.element.android.features.changeroommemberroes.api.ChangeRoomMemberRolesEntryPoint
+import io.element.android.features.knockrequests.api.list.KnockRequestsListEntryPoint
+import io.element.android.features.messages.api.MessagesEntryPoint
+import io.element.android.features.poll.api.history.PollHistoryEntryPoint
+import io.element.android.features.reportroom.api.ReportRoomEntryPoint
+import io.element.android.features.roomdetails.api.RoomDetailsEntryPoint
+import io.element.android.features.verifysession.api.OutgoingVerificationEntryPoint
+import io.element.android.libraries.matrix.api.core.EventId
+import io.element.android.libraries.matrix.api.core.RoomId
+import io.element.android.libraries.matrix.api.core.UserId
+import io.element.android.libraries.matrix.api.permalink.PermalinkData
+import io.element.android.libraries.matrix.test.A_USER_ID
+import io.element.android.libraries.matrix.test.room.FakeJoinedRoom
+import io.element.android.libraries.mediaviewer.api.MediaGalleryEntryPoint
+import io.element.android.libraries.mediaviewer.api.MediaViewerEntryPoint
+import io.element.android.services.analytics.test.FakeAnalyticsService
+import io.element.android.tests.testutils.lambda.lambdaError
+import io.element.android.tests.testutils.node.TestParentNode
+import org.junit.Rule
+import org.junit.Test
+
+class DefaultRoomDetailsEntryPointTest {
+ @get:Rule
+ val instantTaskExecutorRule = InstantTaskExecutorRule()
+
+ @get:Rule
+ val mainDispatcherRule = MainDispatcherRule()
+
+ @Test
+ fun `test node builder`() {
+ val entryPoint = DefaultRoomDetailsEntryPoint()
+
+ val parentNode = TestParentNode.create { buildContext, plugins ->
+ RoomDetailsFlowNode(
+ buildContext = buildContext,
+ plugins = plugins,
+ pollHistoryEntryPoint = object : PollHistoryEntryPoint {
+ override fun createNode(parentNode: Node, buildContext: BuildContext) = lambdaError()
+ },
+ elementCallEntryPoint = object : ElementCallEntryPoint {
+ override fun startCall(callType: CallType) = lambdaError()
+ override suspend fun handleIncomingCall(
+ callType: CallType.RoomCall,
+ eventId: EventId,
+ senderId: UserId,
+ roomName: String?,
+ senderName: String?,
+ avatarUrl: String?,
+ timestamp: Long,
+ expirationTimestamp: Long,
+ notificationChannelId: String,
+ textContent: String?
+ ) = lambdaError()
+ },
+ room = FakeJoinedRoom(),
+ analyticsService = FakeAnalyticsService(),
+ messagesEntryPoint = object : MessagesEntryPoint {
+ override fun nodeBuilder(parentNode: Node, buildContext: BuildContext) = lambdaError()
+ },
+ knockRequestsListEntryPoint = object : KnockRequestsListEntryPoint {
+ override fun createNode(parentNode: Node, buildContext: BuildContext) = lambdaError()
+ },
+ mediaViewerEntryPoint = object : MediaViewerEntryPoint {
+ override fun nodeBuilder(parentNode: Node, buildContext: BuildContext) = lambdaError()
+ },
+ mediaGalleryEntryPoint = object : MediaGalleryEntryPoint {
+ override fun nodeBuilder(parentNode: Node, buildContext: BuildContext) = lambdaError()
+ },
+ outgoingVerificationEntryPoint = object : OutgoingVerificationEntryPoint {
+ override fun nodeBuilder(parentNode: Node, buildContext: BuildContext) = lambdaError()
+ },
+ reportRoomEntryPoint = object : ReportRoomEntryPoint {
+ override fun createNode(parentNode: Node, buildContext: BuildContext, roomId: RoomId) = lambdaError()
+ },
+ changeRoomMemberRolesEntryPoint = object : ChangeRoomMemberRolesEntryPoint {
+ override fun builder(parentNode: Node, buildContext: BuildContext) = lambdaError()
+ },
+ )
+ }
+ val callback = object : RoomDetailsEntryPoint.Callback {
+ override fun onOpenGlobalNotificationSettings() = lambdaError()
+ override fun onOpenRoom(roomId: RoomId, serverNames: List) = lambdaError()
+ override fun onPermalinkClick(data: PermalinkData, pushToBackstack: Boolean) = lambdaError()
+ override fun onForwardedToSingleRoom(roomId: RoomId) = lambdaError()
+ }
+ val params = RoomDetailsEntryPoint.Params(
+ initialElement = RoomDetailsEntryPoint.InitialTarget.RoomDetails,
+ )
+ val result = entryPoint.nodeBuilder(parentNode, BuildContext.root(null))
+ .params(params)
+ .callback(callback)
+ .build()
+ assertThat(result).isInstanceOf(RoomDetailsFlowNode::class.java)
+ assertThat(result.plugins).contains(params)
+ assertThat(result.plugins).contains(callback)
+ }
+
+ @Test
+ fun `test initial target to nav target mapping`() {
+ assertThat(RoomDetailsEntryPoint.InitialTarget.RoomDetails.toNavTarget())
+ .isEqualTo(RoomDetailsFlowNode.NavTarget.RoomDetails)
+ assertThat(RoomDetailsEntryPoint.InitialTarget.RoomMemberDetails(A_USER_ID).toNavTarget())
+ .isEqualTo(RoomDetailsFlowNode.NavTarget.RoomMemberDetails(A_USER_ID))
+ assertThat(RoomDetailsEntryPoint.InitialTarget.RoomNotificationSettings.toNavTarget())
+ .isEqualTo(RoomDetailsFlowNode.NavTarget.RoomNotificationSettings(showUserDefinedSettingStyle = true))
+ }
+}
diff --git a/features/roomdirectory/impl/build.gradle.kts b/features/roomdirectory/impl/build.gradle.kts
index 813d6be1ff..ec858ced09 100644
--- a/features/roomdirectory/impl/build.gradle.kts
+++ b/features/roomdirectory/impl/build.gradle.kts
@@ -1,4 +1,5 @@
import extension.setupDependencyInjection
+import extension.testCommonDependencies
/*
* Copyright 2024 New Vector Ltd.
@@ -35,14 +36,6 @@ dependencies {
implementation(projects.libraries.testtags)
implementation(projects.services.analytics.api)
- testImplementation(libs.test.junit)
- testImplementation(libs.androidx.compose.ui.test.junit)
- testReleaseImplementation(libs.androidx.compose.ui.test.manifest)
- testImplementation(libs.test.robolectric)
- testImplementation(libs.coroutines.test)
- testImplementation(libs.molecule.runtime)
- testImplementation(libs.test.truth)
- testImplementation(libs.test.turbine)
+ testCommonDependencies(libs, true)
testImplementation(projects.libraries.matrix.test)
- testImplementation(projects.tests.testutils)
}
diff --git a/features/roomdirectory/impl/src/test/kotlin/io/element/android/features/roomdirectory/impl/DefaultRoomDirectoryEntryPointTest.kt b/features/roomdirectory/impl/src/test/kotlin/io/element/android/features/roomdirectory/impl/DefaultRoomDirectoryEntryPointTest.kt
new file mode 100644
index 0000000000..d544f55000
--- /dev/null
+++ b/features/roomdirectory/impl/src/test/kotlin/io/element/android/features/roomdirectory/impl/DefaultRoomDirectoryEntryPointTest.kt
@@ -0,0 +1,46 @@
+/*
+ * Copyright 2025 New Vector Ltd.
+ *
+ * SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial
+ * Please see LICENSE files in the repository root for full details.
+ */
+
+package io.element.android.features.roomdirectory.impl
+
+import androidx.arch.core.executor.testing.InstantTaskExecutorRule
+import com.bumble.appyx.core.modality.BuildContext
+import com.google.common.truth.Truth.assertThat
+import io.element.android.features.roomdirectory.api.RoomDescription
+import io.element.android.features.roomdirectory.api.RoomDirectoryEntryPoint
+import io.element.android.features.roomdirectory.impl.root.RoomDirectoryNode
+import io.element.android.features.roomdirectory.impl.root.createRoomDirectoryPresenter
+import io.element.android.tests.testutils.lambda.lambdaError
+import io.element.android.tests.testutils.node.TestParentNode
+import kotlinx.coroutines.test.runTest
+import org.junit.Rule
+import org.junit.Test
+
+class DefaultRoomDirectoryEntryPointTest {
+ @get:Rule
+ val instantTaskExecutorRule = InstantTaskExecutorRule()
+
+ @Test
+ fun `test node builder`() = runTest {
+ val entryPoint = DefaultRoomDirectoryEntryPoint()
+ val parentNode = TestParentNode.create { buildContext, plugins ->
+ RoomDirectoryNode(
+ buildContext = buildContext,
+ plugins = plugins,
+ presenter = createRoomDirectoryPresenter(),
+ )
+ }
+ val callback = object : RoomDirectoryEntryPoint.Callback {
+ override fun onResultClick(roomDescription: RoomDescription) = lambdaError()
+ }
+ val result = entryPoint.nodeBuilder(parentNode, BuildContext.root(null))
+ .callback(callback)
+ .build()
+ assertThat(result).isInstanceOf(RoomDirectoryNode::class.java)
+ assertThat(result.plugins).contains(callback)
+ }
+}
diff --git a/features/roomdirectory/impl/src/test/kotlin/io/element/android/features/roomdirectory/impl/root/RoomDirectoryPresenterTest.kt b/features/roomdirectory/impl/src/test/kotlin/io/element/android/features/roomdirectory/impl/root/RoomDirectoryPresenterTest.kt
index d6ebb6cd95..4af983b307 100644
--- a/features/roomdirectory/impl/src/test/kotlin/io/element/android/features/roomdirectory/impl/root/RoomDirectoryPresenterTest.kt
+++ b/features/roomdirectory/impl/src/test/kotlin/io/element/android/features/roomdirectory/impl/root/RoomDirectoryPresenterTest.kt
@@ -122,15 +122,15 @@ class RoomDirectoryPresenterTest {
.isCalledOnce()
.withNoParameter()
}
-
- private fun TestScope.createRoomDirectoryPresenter(
- roomDirectoryService: RoomDirectoryService = FakeRoomDirectoryService(
- createRoomDirectoryListFactory = { FakeRoomDirectoryList() }
- ),
- ): RoomDirectoryPresenter {
- return RoomDirectoryPresenter(
- dispatchers = testCoroutineDispatchers(),
- roomDirectoryService = roomDirectoryService,
- )
- }
+}
+
+internal fun TestScope.createRoomDirectoryPresenter(
+ roomDirectoryService: RoomDirectoryService = FakeRoomDirectoryService(
+ createRoomDirectoryListFactory = { FakeRoomDirectoryList() }
+ ),
+): RoomDirectoryPresenter {
+ return RoomDirectoryPresenter(
+ dispatchers = testCoroutineDispatchers(),
+ roomDirectoryService = roomDirectoryService,
+ )
}
diff --git a/features/roommembermoderation/impl/build.gradle.kts b/features/roommembermoderation/impl/build.gradle.kts
index 7208b5985f..a58b0ce02f 100644
--- a/features/roommembermoderation/impl/build.gradle.kts
+++ b/features/roommembermoderation/impl/build.gradle.kts
@@ -1,4 +1,5 @@
import extension.setupDependencyInjection
+import extension.testCommonDependencies
/*
* Copyright 2025 New Vector Ltd.
@@ -32,16 +33,8 @@ dependencies {
implementation(projects.libraries.uiStrings)
implementation(projects.services.analytics.compose)
- testImplementation(libs.test.junit)
- testImplementation(libs.coroutines.test)
- testImplementation(libs.molecule.runtime)
- testImplementation(libs.test.truth)
- testImplementation(libs.test.turbine)
+ testCommonDependencies(libs, true)
testImplementation(projects.libraries.matrix.test)
- testImplementation(projects.tests.testutils)
testImplementation(projects.services.analytics.test)
- testImplementation(libs.test.robolectric)
- testImplementation(libs.androidx.compose.ui.test.junit)
- testReleaseImplementation(libs.androidx.compose.ui.test.manifest)
testImplementation(projects.libraries.testtags)
}
diff --git a/features/roommembermoderation/impl/src/main/kotlin/io/element/android/features/roommembermoderation/impl/RoomMemberModerationView.kt b/features/roommembermoderation/impl/src/main/kotlin/io/element/android/features/roommembermoderation/impl/RoomMemberModerationView.kt
index d4b7a7b69e..248b6cd02b 100644
--- a/features/roommembermoderation/impl/src/main/kotlin/io/element/android/features/roommembermoderation/impl/RoomMemberModerationView.kt
+++ b/features/roommembermoderation/impl/src/main/kotlin/io/element/android/features/roommembermoderation/impl/RoomMemberModerationView.kt
@@ -242,7 +242,7 @@ private fun RoomMemberActionsBottomSheet(
)
}
Text(
- text = user.userId.toString(),
+ text = user.userId.value,
style = ElementTheme.typography.fontBodyLgRegular,
color = ElementTheme.colors.textSecondary,
maxLines = 1,
diff --git a/features/securebackup/impl/build.gradle.kts b/features/securebackup/impl/build.gradle.kts
index 399547108b..92a6013580 100644
--- a/features/securebackup/impl/build.gradle.kts
+++ b/features/securebackup/impl/build.gradle.kts
@@ -1,4 +1,5 @@
import extension.setupDependencyInjection
+import extension.testCommonDependencies
/*
* Copyright 2023, 2024 New Vector Ltd.
@@ -38,14 +39,6 @@ dependencies {
api(libs.statemachine)
api(projects.features.securebackup.api)
- testImplementation(libs.test.junit)
- testImplementation(libs.coroutines.test)
- testImplementation(libs.molecule.runtime)
- testImplementation(libs.test.truth)
- testImplementation(libs.test.turbine)
- testImplementation(libs.test.robolectric)
- testImplementation(libs.androidx.compose.ui.test.junit)
+ testCommonDependencies(libs, true)
testImplementation(projects.libraries.matrix.test)
- testImplementation(projects.tests.testutils)
- testReleaseImplementation(libs.androidx.compose.ui.test.manifest)
}
diff --git a/features/securebackup/impl/src/main/res/values-eo/translations.xml b/features/securebackup/impl/src/main/res/values-eo/translations.xml
new file mode 100644
index 0000000000..e3ea61ec1c
--- /dev/null
+++ b/features/securebackup/impl/src/main/res/values-eo/translations.xml
@@ -0,0 +1,44 @@
+
+
+ "Delete message backup"
+ "Store your account security and messages securely on the server. This will allow you to view your message history on any new devices. %1$s."
+ "Message backup"
+ "Turn on message backup to set it up."
+ "Upload messages from this device"
+ "Allow message backup"
+ "Change backup password"
+ "Restore your account security and message history with a backup password if you\'ve lost all your existing devices."
+ "Enter backup password"
+ "Your message backup is currently out of sync."
+ "Set up backup"
+ "When asked to confirm your device, select %1$s"
+ "Follow the instructions to create a new backup password"
+ "Save your new backup password in a password manager or encrypted note"
+ "You will need to confirm all your existing devices and verify contacts again"
+ "Only start fresh if you don\'t have access to another signed-in device and you\'ve lost your backup password."
+ "Can\'t confirm? You\'ll need to start fresh."
+ "Deleting message backup will remove your account security and messages from the server and turn off the following security features:"
+ "Are you sure you want to turn off message backup and delete it?"
+ "Get a new backup password if you\'ve lost your existing one. After changing your backup password, your old one will no longer work."
+ "Generate a new backup password"
+ "Backup password changed"
+ "Change backup password?"
+ "Please try again to confirm access to your message backup."
+ "Incorrect backup password"
+ "You might have seen the terms \"recovery key\", \"security key\" or \"security phrase\" instead of \"backup password\". Don\'t worry, this is all the same."
+ "Backup password confirmed"
+ "Enter your backup password"
+ "Copied backup password"
+ "Save backup password"
+ "Write down this backup password somewhere safe, like a password manager, encrypted note, or a physical safe."
+ "Tap to copy backup password"
+ "Save your backup password somewhere safe"
+ "You will not be able to access your new backup password after this step."
+ "Have you saved your backup password?"
+ "Your message backup is protected by a backup password. If you need a new backup password after setup, you can recreate it by selecting ‘Change backup password’."
+ "Generate your backup password"
+ "Backup setup successful"
+ "Set up backup"
+ "Are you sure you want to start fresh?"
+ "Confirm that you want to start fresh."
+
diff --git a/features/securebackup/impl/src/main/res/values-fi/translations.xml b/features/securebackup/impl/src/main/res/values-fi/translations.xml
index 7daf180c6b..4a0cc4e34d 100644
--- a/features/securebackup/impl/src/main/res/values-fi/translations.xml
+++ b/features/securebackup/impl/src/main/res/values-fi/translations.xml
@@ -37,7 +37,7 @@
"Luo uusi palautusavain"
"Älä jaa tätä kenenkään kanssa!"
"Palautusavain vaihdettu"
- "Vaihda palautusavain?"
+ "Vaihdetaanko palautusavain?"
"Luo uusi palautusavain"
"Varmista, ettei kukaan näe tätä ruutua!"
"Yritä uudelleen vahvistaaksesi pääsyn avainten säilytykseen."
diff --git a/features/securebackup/impl/src/test/kotlin/io/element/android/features/securebackup/impl/DefaultSecureBackupEntryPointTest.kt b/features/securebackup/impl/src/test/kotlin/io/element/android/features/securebackup/impl/DefaultSecureBackupEntryPointTest.kt
new file mode 100644
index 0000000000..7741b5141a
--- /dev/null
+++ b/features/securebackup/impl/src/test/kotlin/io/element/android/features/securebackup/impl/DefaultSecureBackupEntryPointTest.kt
@@ -0,0 +1,48 @@
+/*
+ * Copyright 2025 New Vector Ltd.
+ *
+ * SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial
+ * Please see LICENSE files in the repository root for full details.
+ */
+
+package io.element.android.features.securebackup.impl
+
+import androidx.arch.core.executor.testing.InstantTaskExecutorRule
+import com.bumble.appyx.core.modality.BuildContext
+import com.bumble.appyx.testing.junit4.util.MainDispatcherRule
+import com.google.common.truth.Truth.assertThat
+import io.element.android.features.securebackup.api.SecureBackupEntryPoint
+import io.element.android.tests.testutils.lambda.lambdaError
+import io.element.android.tests.testutils.node.TestParentNode
+import org.junit.Rule
+import org.junit.Test
+
+class DefaultSecureBackupEntryPointTest {
+ @get:Rule
+ val instantTaskExecutorRule = InstantTaskExecutorRule()
+
+ @get:Rule
+ val mainDispatcherRule = MainDispatcherRule()
+
+ @Test
+ fun `test node builder`() {
+ val entryPoint = DefaultSecureBackupEntryPoint()
+ val parentNode = TestParentNode.create { buildContext, plugins ->
+ SecureBackupFlowNode(
+ buildContext = buildContext,
+ plugins = plugins,
+ )
+ }
+ val callback = object : SecureBackupEntryPoint.Callback {
+ override fun onDone() = lambdaError()
+ }
+ val params = SecureBackupEntryPoint.Params(SecureBackupEntryPoint.InitialTarget.ResetIdentity)
+ val result = entryPoint.nodeBuilder(parentNode, BuildContext.root(null))
+ .params(params)
+ .callback(callback)
+ .build()
+ assertThat(result).isInstanceOf(SecureBackupFlowNode::class.java)
+ assertThat(result.plugins).contains(params)
+ assertThat(result.plugins).contains(callback)
+ }
+}
diff --git a/features/share/impl/build.gradle.kts b/features/share/impl/build.gradle.kts
index 3f8ef152fb..4c62a06352 100644
--- a/features/share/impl/build.gradle.kts
+++ b/features/share/impl/build.gradle.kts
@@ -1,4 +1,5 @@
import extension.setupDependencyInjection
+import extension.testCommonDependencies
/*
* Copyright 2023, 2024 New Vector Ltd.
@@ -41,16 +42,8 @@ dependencies {
api(libs.statemachine)
api(projects.features.share.api)
- testImplementation(libs.test.junit)
- testImplementation(libs.coroutines.test)
- testImplementation(libs.molecule.runtime)
- testImplementation(libs.test.truth)
- testImplementation(libs.test.turbine)
- testImplementation(libs.test.robolectric)
- testImplementation(libs.androidx.compose.ui.test.junit)
+ testCommonDependencies(libs, true)
testImplementation(projects.libraries.matrix.test)
testImplementation(projects.libraries.mediaupload.test)
testImplementation(projects.libraries.preferences.test)
- testImplementation(projects.tests.testutils)
- testReleaseImplementation(libs.androidx.compose.ui.test.manifest)
}
diff --git a/features/share/impl/src/main/kotlin/io/element/android/features/share/impl/SharePresenter.kt b/features/share/impl/src/main/kotlin/io/element/android/features/share/impl/SharePresenter.kt
index aaadf6f8d0..056d8b912e 100644
--- a/features/share/impl/src/main/kotlin/io/element/android/features/share/impl/SharePresenter.kt
+++ b/features/share/impl/src/main/kotlin/io/element/android/features/share/impl/SharePresenter.kt
@@ -43,7 +43,7 @@ class SharePresenter(
private val mediaOptimizationConfigProvider: MediaOptimizationConfigProvider,
) : Presenter {
@AssistedFactory
- interface Factory {
+ fun interface Factory {
fun create(intent: Intent): SharePresenter
}
diff --git a/features/share/impl/src/test/kotlin/io/element/android/features/share/impl/DefaultShareEntryPointTest.kt b/features/share/impl/src/test/kotlin/io/element/android/features/share/impl/DefaultShareEntryPointTest.kt
new file mode 100644
index 0000000000..66ee853d26
--- /dev/null
+++ b/features/share/impl/src/test/kotlin/io/element/android/features/share/impl/DefaultShareEntryPointTest.kt
@@ -0,0 +1,61 @@
+/*
+ * Copyright 2025 New Vector Ltd.
+ *
+ * SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial
+ * Please see LICENSE files in the repository root for full details.
+ */
+
+package io.element.android.features.share.impl
+
+import android.content.Intent
+import androidx.arch.core.executor.testing.InstantTaskExecutorRule
+import com.bumble.appyx.core.modality.BuildContext
+import com.bumble.appyx.core.node.Node
+import com.bumble.appyx.testing.junit4.util.MainDispatcherRule
+import com.google.common.truth.Truth.assertThat
+import io.element.android.features.share.api.ShareEntryPoint
+import io.element.android.libraries.matrix.api.core.RoomId
+import io.element.android.libraries.roomselect.api.RoomSelectEntryPoint
+import io.element.android.tests.testutils.lambda.lambdaError
+import io.element.android.tests.testutils.node.TestParentNode
+import kotlinx.coroutines.test.runTest
+import org.junit.Rule
+import org.junit.Test
+
+class DefaultShareEntryPointTest {
+ @get:Rule
+ val instantTaskExecutorRule = InstantTaskExecutorRule()
+
+ @get:Rule
+ val mainDispatcherRule = MainDispatcherRule()
+
+ @Test
+ fun `test node builder`() = runTest {
+ val entryPoint = DefaultShareEntryPoint()
+ val parentNode = TestParentNode.create { buildContext, plugins ->
+ ShareNode(
+ buildContext = buildContext,
+ plugins = plugins,
+ presenterFactory = { createSharePresenter() },
+ roomSelectEntryPoint = object : RoomSelectEntryPoint {
+ override fun nodeBuilder(parentNode: Node, buildContext: BuildContext): RoomSelectEntryPoint.NodeBuilder {
+ lambdaError()
+ }
+ },
+ )
+ }
+ val callback = object : ShareEntryPoint.Callback {
+ override fun onDone(roomIds: List) = lambdaError()
+ }
+ val params = ShareEntryPoint.Params(
+ intent = Intent(),
+ )
+ val result = entryPoint.nodeBuilder(parentNode, BuildContext.root(null))
+ .params(params)
+ .callback(callback)
+ .build()
+ assertThat(result).isInstanceOf(ShareNode::class.java)
+ assertThat(result.plugins).contains(ShareNode.Inputs(params.intent))
+ assertThat(result.plugins).contains(callback)
+ }
+}
diff --git a/features/share/impl/src/test/kotlin/io/element/android/features/share/impl/SharePresenterTest.kt b/features/share/impl/src/test/kotlin/io/element/android/features/share/impl/SharePresenterTest.kt
index 7ddb7d0ae4..b1b39b2e80 100644
--- a/features/share/impl/src/test/kotlin/io/element/android/features/share/impl/SharePresenterTest.kt
+++ b/features/share/impl/src/test/kotlin/io/element/android/features/share/impl/SharePresenterTest.kt
@@ -158,23 +158,23 @@ class SharePresenterTest {
sendFileResult.assertions().isCalledOnce()
}
}
-
- private fun TestScope.createSharePresenter(
- intent: Intent = Intent(),
- shareIntentHandler: ShareIntentHandler = FakeShareIntentHandler(),
- matrixClient: MatrixClient = FakeMatrixClient(),
- mediaPreProcessor: MediaPreProcessor = FakeMediaPreProcessor(),
- activeRoomsHolder: ActiveRoomsHolder = ActiveRoomsHolder(),
- mediaOptimizationConfigProvider: FakeMediaOptimizationConfigProvider = FakeMediaOptimizationConfigProvider(),
- ): SharePresenter {
- return SharePresenter(
- intent = intent,
- sessionCoroutineScope = this,
- shareIntentHandler = shareIntentHandler,
- matrixClient = matrixClient,
- mediaPreProcessor = mediaPreProcessor,
- activeRoomsHolder = activeRoomsHolder,
- mediaOptimizationConfigProvider = mediaOptimizationConfigProvider,
- )
- }
+}
+
+internal fun TestScope.createSharePresenter(
+ intent: Intent = Intent(),
+ shareIntentHandler: ShareIntentHandler = FakeShareIntentHandler(),
+ matrixClient: MatrixClient = FakeMatrixClient(),
+ mediaPreProcessor: MediaPreProcessor = FakeMediaPreProcessor(),
+ activeRoomsHolder: ActiveRoomsHolder = ActiveRoomsHolder(),
+ mediaOptimizationConfigProvider: FakeMediaOptimizationConfigProvider = FakeMediaOptimizationConfigProvider(),
+): SharePresenter {
+ return SharePresenter(
+ intent = intent,
+ sessionCoroutineScope = this,
+ shareIntentHandler = shareIntentHandler,
+ matrixClient = matrixClient,
+ mediaPreProcessor = mediaPreProcessor,
+ activeRoomsHolder = activeRoomsHolder,
+ mediaOptimizationConfigProvider = mediaOptimizationConfigProvider,
+ )
}
diff --git a/features/signedout/impl/build.gradle.kts b/features/signedout/impl/build.gradle.kts
index f4da2e48a4..f314cb8283 100644
--- a/features/signedout/impl/build.gradle.kts
+++ b/features/signedout/impl/build.gradle.kts
@@ -1,4 +1,5 @@
import extension.setupDependencyInjection
+import extension.testCommonDependencies
/*
* Copyright 2023, 2024 New Vector Ltd.
@@ -27,12 +28,7 @@ dependencies {
implementation(projects.libraries.designsystem)
implementation(projects.libraries.uiStrings)
- testImplementation(libs.test.junit)
- testImplementation(libs.coroutines.test)
- testImplementation(libs.molecule.runtime)
- testImplementation(libs.test.truth)
- testImplementation(libs.test.turbine)
+ testCommonDependencies(libs)
testImplementation(projects.libraries.matrix.test)
testImplementation(projects.libraries.sessionStorage.test)
- testImplementation(projects.tests.testutils)
}
diff --git a/features/signedout/impl/src/main/kotlin/io/element/android/features/signedout/impl/SignedOutPresenter.kt b/features/signedout/impl/src/main/kotlin/io/element/android/features/signedout/impl/SignedOutPresenter.kt
index 6516a2a1c6..9810892ff3 100644
--- a/features/signedout/impl/src/main/kotlin/io/element/android/features/signedout/impl/SignedOutPresenter.kt
+++ b/features/signedout/impl/src/main/kotlin/io/element/android/features/signedout/impl/SignedOutPresenter.kt
@@ -29,7 +29,7 @@ class SignedOutPresenter(
private val buildMeta: BuildMeta,
) : Presenter {
@AssistedFactory
- interface Factory {
+ fun interface Factory {
fun create(sessionId: String): SignedOutPresenter
}
diff --git a/features/signedout/impl/src/test/kotlin/io/element/android/features/signedout/impl/DefaultSignedOutEntryPointTest.kt b/features/signedout/impl/src/test/kotlin/io/element/android/features/signedout/impl/DefaultSignedOutEntryPointTest.kt
new file mode 100644
index 0000000000..860ad88d8a
--- /dev/null
+++ b/features/signedout/impl/src/test/kotlin/io/element/android/features/signedout/impl/DefaultSignedOutEntryPointTest.kt
@@ -0,0 +1,43 @@
+/*
+ * Copyright 2025 New Vector Ltd.
+ *
+ * SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial
+ * Please see LICENSE files in the repository root for full details.
+ */
+
+package io.element.android.features.signedout.impl
+
+import androidx.arch.core.executor.testing.InstantTaskExecutorRule
+import com.bumble.appyx.core.modality.BuildContext
+import com.google.common.truth.Truth.assertThat
+import io.element.android.features.signedout.api.SignedOutEntryPoint
+import io.element.android.libraries.matrix.test.A_SESSION_ID
+import io.element.android.tests.testutils.node.TestParentNode
+import org.junit.Rule
+import org.junit.Test
+
+class DefaultSignedOutEntryPointTest {
+ @get:Rule
+ val instantTaskExecutorRule = InstantTaskExecutorRule()
+
+ @Test
+ fun `test node builder`() {
+ val entryPoint = DefaultSignedOutEntryPoint()
+ val parentNode = TestParentNode.create { buildContext, plugins ->
+ SignedOutNode(
+ buildContext = buildContext,
+ plugins = plugins,
+ presenterFactory = { sessionId ->
+ assertThat(sessionId).isEqualTo(A_SESSION_ID.value)
+ createSignedOutPresenter()
+ }
+ )
+ }
+ val params = SignedOutEntryPoint.Params(A_SESSION_ID)
+ val result = entryPoint.nodeBuilder(parentNode, BuildContext.root(null))
+ .params(params)
+ .build()
+ assertThat(result).isInstanceOf(SignedOutNode::class.java)
+ assertThat(result.plugins).contains(SignedOutNode.Inputs(params.sessionId))
+ }
+}
diff --git a/features/signedout/impl/src/test/kotlin/io/element/android/features/signedout/impl/SignedOutPresenterTest.kt b/features/signedout/impl/src/test/kotlin/io/element/android/features/signedout/impl/SignedOutPresenterTest.kt
index 8674020f1e..de5634f269 100644
--- a/features/signedout/impl/src/test/kotlin/io/element/android/features/signedout/impl/SignedOutPresenterTest.kt
+++ b/features/signedout/impl/src/test/kotlin/io/element/android/features/signedout/impl/SignedOutPresenterTest.kt
@@ -12,6 +12,7 @@ import app.cash.molecule.moleculeFlow
import app.cash.turbine.test
import com.google.common.truth.Truth.assertThat
import io.element.android.libraries.matrix.api.core.SessionId
+import io.element.android.libraries.matrix.test.AN_APPLICATION_NAME
import io.element.android.libraries.matrix.test.A_SESSION_ID
import io.element.android.libraries.matrix.test.core.aBuildMeta
import io.element.android.libraries.sessionstorage.api.SessionStore
@@ -26,8 +27,6 @@ class SignedOutPresenterTest {
@get:Rule
val warmUpRule = WarmUpRule()
- private val appName = "AppName"
-
@Test
fun `present - initial state`() = runTest {
val aSessionData = aSessionData()
@@ -40,7 +39,7 @@ class SignedOutPresenterTest {
}.test {
skipItems(1)
val initialState = awaitItem()
- assertThat(initialState.appName).isEqualTo(appName)
+ assertThat(initialState.appName).isEqualTo(AN_APPLICATION_NAME)
assertThat(initialState.signedOutSession).isEqualTo(aSessionData)
}
}
@@ -64,15 +63,15 @@ class SignedOutPresenterTest {
assertThat(sessionStore.getAllSessions()).isEmpty()
}
}
-
- private fun createSignedOutPresenter(
- sessionId: SessionId = A_SESSION_ID,
- sessionStore: SessionStore = InMemorySessionStore(),
- ): SignedOutPresenter {
- return SignedOutPresenter(
- sessionId = sessionId.value,
- sessionStore = sessionStore,
- buildMeta = aBuildMeta(applicationName = appName),
- )
- }
+}
+
+internal fun createSignedOutPresenter(
+ sessionId: SessionId = A_SESSION_ID,
+ sessionStore: SessionStore = InMemorySessionStore(),
+): SignedOutPresenter {
+ return SignedOutPresenter(
+ sessionId = sessionId.value,
+ sessionStore = sessionStore,
+ buildMeta = aBuildMeta(applicationName = AN_APPLICATION_NAME),
+ )
}
diff --git a/features/space/api/build.gradle.kts b/features/space/api/build.gradle.kts
new file mode 100644
index 0000000000..dd19efefec
--- /dev/null
+++ b/features/space/api/build.gradle.kts
@@ -0,0 +1,18 @@
+/*
+ * Copyright 2025 New Vector Ltd.
+ *
+ * SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial
+ * Please see LICENSE files in the repository root for full details.
+ */
+plugins {
+ id("io.element.android-library")
+}
+
+android {
+ namespace = "io.element.android.features.space.api"
+}
+
+dependencies {
+ implementation(projects.libraries.architecture)
+ implementation(projects.libraries.matrix.api)
+}
diff --git a/features/space/api/src/main/kotlin/io/element/android/features/space/api/SpaceEntryPoint.kt b/features/space/api/src/main/kotlin/io/element/android/features/space/api/SpaceEntryPoint.kt
new file mode 100644
index 0000000000..5f7be8dba0
--- /dev/null
+++ b/features/space/api/src/main/kotlin/io/element/android/features/space/api/SpaceEntryPoint.kt
@@ -0,0 +1,36 @@
+/*
+ * Copyright 2025 New Vector Ltd.
+ *
+ * SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial
+ * Please see LICENSE files in the repository root for full details.
+ */
+
+package io.element.android.features.space.api
+
+import com.bumble.appyx.core.modality.BuildContext
+import com.bumble.appyx.core.node.Node
+import com.bumble.appyx.core.plugin.Plugin
+import io.element.android.libraries.architecture.FeatureEntryPoint
+import io.element.android.libraries.architecture.NodeInputs
+import io.element.android.libraries.matrix.api.core.RoomId
+
+interface SpaceEntryPoint : FeatureEntryPoint {
+ fun nodeBuilder(
+ parentNode: Node,
+ buildContext: BuildContext,
+ ): NodeBuilder
+
+ interface NodeBuilder {
+ fun inputs(inputs: Inputs): NodeBuilder
+ fun callback(callback: Callback): NodeBuilder
+ fun build(): Node
+ }
+
+ data class Inputs(
+ val roomId: RoomId
+ ) : NodeInputs
+
+ interface Callback : Plugin {
+ fun onOpenRoom(roomId: RoomId)
+ }
+}
diff --git a/features/space/impl/build.gradle.kts b/features/space/impl/build.gradle.kts
new file mode 100644
index 0000000000..b6afbdcb05
--- /dev/null
+++ b/features/space/impl/build.gradle.kts
@@ -0,0 +1,49 @@
+import extension.setupDependencyInjection
+import extension.testCommonDependencies
+
+/*
+ * Copyright 2025 New Vector Ltd.
+ *
+ * SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial
+ * Please see LICENSE files in the repository root for full details.
+ */
+
+plugins {
+ id("io.element.android-compose-library")
+ id("kotlin-parcelize")
+}
+
+android {
+ namespace = "io.element.android.features.space.impl"
+
+ testOptions {
+ unitTests {
+ isIncludeAndroidResources = true
+ }
+ }
+}
+
+setupDependencyInjection()
+
+dependencies {
+ implementation(projects.libraries.core)
+ implementation(projects.libraries.architecture)
+ implementation(projects.libraries.matrix.api)
+ implementation(projects.libraries.matrixui)
+ implementation(projects.libraries.designsystem)
+ implementation(projects.libraries.uiStrings)
+ implementation(projects.libraries.androidutils)
+ implementation(projects.libraries.deeplink.api)
+ implementation(projects.services.analytics.api)
+ implementation(libs.coil.compose)
+ implementation(projects.libraries.featureflag.api)
+ implementation(projects.features.invite.api)
+ implementation(projects.libraries.previewutils)
+ api(projects.features.space.api)
+
+ testCommonDependencies(libs, true)
+ testImplementation(projects.services.analytics.test)
+ testImplementation(projects.libraries.matrix.test)
+ testImplementation(projects.libraries.featureflag.test)
+ testImplementation(projects.features.invite.test)
+}
diff --git a/features/space/impl/src/main/kotlin/io/element/android/features/space/impl/DefaultSpaceEntryPoint.kt b/features/space/impl/src/main/kotlin/io/element/android/features/space/impl/DefaultSpaceEntryPoint.kt
new file mode 100644
index 0000000000..1ef8275b27
--- /dev/null
+++ b/features/space/impl/src/main/kotlin/io/element/android/features/space/impl/DefaultSpaceEntryPoint.kt
@@ -0,0 +1,40 @@
+/*
+ * Copyright 2025 New Vector Ltd.
+ *
+ * SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial
+ * Please see LICENSE files in the repository root for full details.
+ */
+
+package io.element.android.features.space.impl
+
+import com.bumble.appyx.core.modality.BuildContext
+import com.bumble.appyx.core.node.Node
+import com.bumble.appyx.core.plugin.Plugin
+import dev.zacsweers.metro.ContributesBinding
+import dev.zacsweers.metro.Inject
+import io.element.android.features.space.api.SpaceEntryPoint
+import io.element.android.libraries.architecture.createNode
+import io.element.android.libraries.di.SessionScope
+
+@ContributesBinding(SessionScope::class)
+@Inject
+class DefaultSpaceEntryPoint : SpaceEntryPoint {
+ override fun nodeBuilder(parentNode: Node, buildContext: BuildContext): SpaceEntryPoint.NodeBuilder {
+ val plugins = mutableSetOf()
+ return object : SpaceEntryPoint.NodeBuilder {
+ override fun inputs(inputs: SpaceEntryPoint.Inputs): SpaceEntryPoint.NodeBuilder {
+ plugins.add(inputs)
+ return this
+ }
+
+ override fun callback(callback: SpaceEntryPoint.Callback): SpaceEntryPoint.NodeBuilder {
+ plugins.add(callback)
+ return this
+ }
+
+ override fun build(): Node {
+ return parentNode.createNode(buildContext, plugins = plugins.toList())
+ }
+ }
+ }
+}
diff --git a/features/space/impl/src/main/kotlin/io/element/android/features/space/impl/SpaceEvents.kt b/features/space/impl/src/main/kotlin/io/element/android/features/space/impl/SpaceEvents.kt
new file mode 100644
index 0000000000..848dac3ebc
--- /dev/null
+++ b/features/space/impl/src/main/kotlin/io/element/android/features/space/impl/SpaceEvents.kt
@@ -0,0 +1,12 @@
+/*
+ * Copyright 2025 New Vector Ltd.
+ *
+ * SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial
+ * Please see LICENSE files in the repository root for full details.
+ */
+
+package io.element.android.features.space.impl
+
+sealed interface SpaceEvents {
+ data object LoadMore : SpaceEvents
+}
diff --git a/features/space/impl/src/main/kotlin/io/element/android/features/space/impl/SpaceNode.kt b/features/space/impl/src/main/kotlin/io/element/android/features/space/impl/SpaceNode.kt
new file mode 100644
index 0000000000..a4828fe9fe
--- /dev/null
+++ b/features/space/impl/src/main/kotlin/io/element/android/features/space/impl/SpaceNode.kt
@@ -0,0 +1,45 @@
+/*
+ * Copyright 2025 New Vector Ltd.
+ *
+ * SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial
+ * Please see LICENSE files in the repository root for full details.
+ */
+
+package io.element.android.features.space.impl
+
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.Modifier
+import com.bumble.appyx.core.modality.BuildContext
+import com.bumble.appyx.core.node.Node
+import com.bumble.appyx.core.plugin.Plugin
+import dev.zacsweers.metro.Assisted
+import dev.zacsweers.metro.Inject
+import io.element.android.annotations.ContributesNode
+import io.element.android.features.space.api.SpaceEntryPoint
+import io.element.android.libraries.architecture.inputs
+import io.element.android.libraries.di.SessionScope
+
+@ContributesNode(SessionScope::class)
+@Inject
+class SpaceNode(
+ @Assisted buildContext: BuildContext,
+ @Assisted plugins: List,
+ presenterFactory: SpacePresenter.Factory,
+) : Node(buildContext, plugins = plugins) {
+ private val inputs: SpaceEntryPoint.Inputs = inputs()
+ private val callback = plugins.filterIsInstance().single()
+ private val presenter = presenterFactory.create(inputs)
+
+ @Composable
+ override fun View(modifier: Modifier) {
+ val state = presenter.present()
+ SpaceView(
+ state = state,
+ onBackClick = ::navigateUp,
+ onRoomClick = { roomId ->
+ callback.onOpenRoom(roomId)
+ },
+ modifier = modifier
+ )
+ }
+}
diff --git a/features/space/impl/src/main/kotlin/io/element/android/features/space/impl/SpacePresenter.kt b/features/space/impl/src/main/kotlin/io/element/android/features/space/impl/SpacePresenter.kt
new file mode 100644
index 0000000000..1955ab652e
--- /dev/null
+++ b/features/space/impl/src/main/kotlin/io/element/android/features/space/impl/SpacePresenter.kt
@@ -0,0 +1,89 @@
+/*
+ * Copyright 2025 New Vector Ltd.
+ *
+ * SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial
+ * Please see LICENSE files in the repository root for full details.
+ */
+
+package io.element.android.features.space.impl
+
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.LaunchedEffect
+import androidx.compose.runtime.collectAsState
+import androidx.compose.runtime.getValue
+import androidx.compose.runtime.remember
+import androidx.compose.runtime.rememberCoroutineScope
+import dev.zacsweers.metro.Assisted
+import dev.zacsweers.metro.AssistedFactory
+import dev.zacsweers.metro.Inject
+import io.element.android.features.invite.api.SeenInvitesStore
+import io.element.android.features.space.api.SpaceEntryPoint
+import io.element.android.libraries.architecture.Presenter
+import io.element.android.libraries.core.coroutine.mapState
+import io.element.android.libraries.matrix.api.MatrixClient
+import io.element.android.libraries.matrix.api.spaces.SpaceRoomList
+import io.element.android.libraries.matrix.ui.safety.rememberHideInvitesAvatar
+import kotlinx.collections.immutable.persistentSetOf
+import kotlinx.collections.immutable.toPersistentList
+import kotlinx.collections.immutable.toPersistentSet
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.flow.map
+import kotlinx.coroutines.launch
+import java.util.Optional
+import kotlin.jvm.optionals.getOrNull
+
+@Inject
+class SpacePresenter(
+ @Assisted private val inputs: SpaceEntryPoint.Inputs,
+ private val client: MatrixClient,
+ private val seenInvitesStore: SeenInvitesStore,
+) : Presenter {
+ @AssistedFactory
+ fun interface Factory {
+ fun create(inputs: SpaceEntryPoint.Inputs): SpacePresenter
+ }
+
+ private val spaceRoomList = client.spaceService.spaceRoomList(inputs.roomId)
+
+ @Composable
+ override fun present(): SpaceState {
+ LaunchedEffect(Unit) {
+ paginate()
+ }
+ val hideInvitesAvatar by client.rememberHideInvitesAvatar()
+ val seenSpaceInvites by remember {
+ seenInvitesStore.seenRoomIds().map { it.toPersistentSet() }
+ }.collectAsState(persistentSetOf())
+
+ val coroutineScope = rememberCoroutineScope()
+ val children by spaceRoomList.spaceRoomsFlow.collectAsState(emptyList())
+ val hasMoreToLoad by remember {
+ spaceRoomList.paginationStatusFlow.mapState { status ->
+ when (status) {
+ is SpaceRoomList.PaginationStatus.Idle -> status.hasMoreToLoad
+ SpaceRoomList.PaginationStatus.Loading -> true
+ }
+ }
+ }.collectAsState()
+
+ val currentSpace by remember { spaceRoomList.currentSpaceFlow() }.collectAsState(Optional.empty())
+
+ fun handleEvents(event: SpaceEvents) {
+ when (event) {
+ SpaceEvents.LoadMore -> coroutineScope.paginate()
+ }
+ }
+ return SpaceState(
+ currentSpace = currentSpace.getOrNull(),
+ children = children.toPersistentList(),
+ seenSpaceInvites = seenSpaceInvites,
+ hideInvitesAvatar = hideInvitesAvatar,
+ hasMoreToLoad = hasMoreToLoad,
+ eventSink = ::handleEvents,
+ )
+ }
+
+ private fun CoroutineScope.paginate() = launch {
+ spaceRoomList.paginate()
+ }
+}
diff --git a/features/space/impl/src/main/kotlin/io/element/android/features/space/impl/SpaceState.kt b/features/space/impl/src/main/kotlin/io/element/android/features/space/impl/SpaceState.kt
new file mode 100644
index 0000000000..ad822283ca
--- /dev/null
+++ b/features/space/impl/src/main/kotlin/io/element/android/features/space/impl/SpaceState.kt
@@ -0,0 +1,22 @@
+/*
+ * Copyright 2025 New Vector Ltd.
+ *
+ * SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial
+ * Please see LICENSE files in the repository root for full details.
+ */
+
+package io.element.android.features.space.impl
+
+import io.element.android.libraries.matrix.api.core.RoomId
+import io.element.android.libraries.matrix.api.spaces.SpaceRoom
+import kotlinx.collections.immutable.ImmutableList
+import kotlinx.collections.immutable.ImmutableSet
+
+data class SpaceState(
+ val currentSpace: SpaceRoom?,
+ val children: ImmutableList,
+ val seenSpaceInvites: ImmutableSet,
+ val hideInvitesAvatar: Boolean,
+ val hasMoreToLoad: Boolean,
+ val eventSink: (SpaceEvents) -> Unit
+)
diff --git a/features/space/impl/src/main/kotlin/io/element/android/features/space/impl/SpaceStateProvider.kt b/features/space/impl/src/main/kotlin/io/element/android/features/space/impl/SpaceStateProvider.kt
new file mode 100644
index 0000000000..cf2fcf92b5
--- /dev/null
+++ b/features/space/impl/src/main/kotlin/io/element/android/features/space/impl/SpaceStateProvider.kt
@@ -0,0 +1,68 @@
+/*
+ * Copyright 2025 New Vector Ltd.
+ *
+ * SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial
+ * Please see LICENSE files in the repository root for full details.
+ */
+
+package io.element.android.features.space.impl
+
+import androidx.compose.ui.tooling.preview.PreviewParameterProvider
+import io.element.android.libraries.matrix.api.core.RoomId
+import io.element.android.libraries.matrix.api.spaces.SpaceRoom
+import io.element.android.libraries.previewutils.room.aSpaceRoom
+import kotlinx.collections.immutable.toImmutableList
+import kotlinx.collections.immutable.toImmutableSet
+
+open class SpaceStateProvider : PreviewParameterProvider {
+ override val values: Sequence
+ get() = sequenceOf(
+ aSpaceState(),
+ aSpaceState(
+ parentSpace = aSpaceRoom(
+ name = null,
+ numJoinedMembers = 5,
+ childrenCount = 10,
+ worldReadable = true,
+ ),
+ hasMoreToLoad = true,
+ ),
+ aSpaceState(
+ hasMoreToLoad = true,
+ children = aListOfSpaceRooms(),
+ ),
+ aSpaceState(
+ hasMoreToLoad = false,
+ children = aListOfSpaceRooms()
+ )
+ // Add other states here
+ )
+}
+
+fun aSpaceState(
+ parentSpace: SpaceRoom? = aSpaceRoom(
+ numJoinedMembers = 5,
+ childrenCount = 10,
+ worldReadable = true,
+ roomId = RoomId("!spaceId0:example.com"),
+ ),
+ children: List = emptyList(),
+ seenSpaceInvites: Set = emptySet(),
+ hideInvitesAvatar: Boolean = false,
+ hasMoreToLoad: Boolean = false,
+) = SpaceState(
+ currentSpace = parentSpace,
+ children = children.toImmutableList(),
+ seenSpaceInvites = seenSpaceInvites.toImmutableSet(),
+ hideInvitesAvatar = hideInvitesAvatar,
+ hasMoreToLoad = hasMoreToLoad,
+ eventSink = {}
+)
+
+private fun aListOfSpaceRooms(): List {
+ return listOf(
+ aSpaceRoom(roomId = RoomId("!spaceId0:example.com")),
+ aSpaceRoom(roomId = RoomId("!spaceId1:example.com")),
+ aSpaceRoom(roomId = RoomId("!spaceId2:example.com")),
+ )
+}
diff --git a/features/space/impl/src/main/kotlin/io/element/android/features/space/impl/SpaceView.kt b/features/space/impl/src/main/kotlin/io/element/android/features/space/impl/SpaceView.kt
new file mode 100644
index 0000000000..53aa61a0c7
--- /dev/null
+++ b/features/space/impl/src/main/kotlin/io/element/android/features/space/impl/SpaceView.kt
@@ -0,0 +1,205 @@
+/*
+ * Copyright 2025 New Vector Ltd.
+ *
+ * SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial
+ * Please see LICENSE files in the repository root for full details.
+ */
+
+package io.element.android.features.space.impl
+
+import androidx.compose.foundation.layout.Box
+import androidx.compose.foundation.layout.Row
+import androidx.compose.foundation.layout.fillMaxSize
+import androidx.compose.foundation.layout.fillMaxWidth
+import androidx.compose.foundation.layout.padding
+import androidx.compose.foundation.lazy.LazyColumn
+import androidx.compose.material3.ExperimentalMaterial3Api
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.LaunchedEffect
+import androidx.compose.runtime.getValue
+import androidx.compose.runtime.rememberUpdatedState
+import androidx.compose.ui.Alignment
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.res.stringResource
+import androidx.compose.ui.semantics.heading
+import androidx.compose.ui.semantics.semantics
+import androidx.compose.ui.text.font.FontStyle
+import androidx.compose.ui.text.style.TextOverflow
+import androidx.compose.ui.tooling.preview.PreviewParameter
+import androidx.compose.ui.unit.dp
+import io.element.android.compound.theme.ElementTheme
+import io.element.android.libraries.designsystem.components.avatar.Avatar
+import io.element.android.libraries.designsystem.components.avatar.AvatarData
+import io.element.android.libraries.designsystem.components.avatar.AvatarSize
+import io.element.android.libraries.designsystem.components.avatar.AvatarType
+import io.element.android.libraries.designsystem.components.button.BackButton
+import io.element.android.libraries.designsystem.preview.ElementPreview
+import io.element.android.libraries.designsystem.preview.PreviewsDayNight
+import io.element.android.libraries.designsystem.theme.components.CircularProgressIndicator
+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.matrix.api.core.RoomId
+import io.element.android.libraries.matrix.api.room.CurrentUserMembership
+import io.element.android.libraries.matrix.api.spaces.SpaceRoom
+import io.element.android.libraries.matrix.ui.components.SpaceHeaderView
+import io.element.android.libraries.matrix.ui.components.SpaceRoomItemView
+import io.element.android.libraries.matrix.ui.model.getAvatarData
+import io.element.android.libraries.ui.strings.CommonStrings
+import kotlinx.collections.immutable.toImmutableList
+
+@Composable
+fun SpaceView(
+ state: SpaceState,
+ onBackClick: () -> Unit,
+ onRoomClick: (roomId: RoomId) -> Unit,
+ modifier: Modifier = Modifier,
+) {
+ Scaffold(
+ modifier = modifier,
+ topBar = {
+ SpaceViewTopBar(currentSpace = state.currentSpace, onBackClick = onBackClick)
+ },
+ content = { padding ->
+ Box(
+ modifier = Modifier.padding(padding)
+ ) {
+ SpaceViewContent(
+ state = state,
+ onRoomClick = onRoomClick
+ )
+ }
+ },
+ )
+}
+
+@Composable
+private fun SpaceViewContent(
+ state: SpaceState,
+ onRoomClick: (roomId: RoomId) -> Unit,
+ modifier: Modifier = Modifier,
+) {
+ LazyColumn(modifier.fillMaxSize()) {
+ val currentSpace = state.currentSpace
+ if (currentSpace != null) {
+ item {
+ SpaceHeaderView(
+ avatarData = currentSpace.getAvatarData(AvatarSize.SpaceHeader),
+ name = currentSpace.name,
+ topic = currentSpace.topic,
+ joinRule = currentSpace.joinRule,
+ heroes = currentSpace.heroes.toImmutableList(),
+ numberOfMembers = currentSpace.numJoinedMembers,
+ numberOfRooms = currentSpace.childrenCount,
+ )
+ }
+ }
+ state.children.forEach { spaceRoom ->
+ item {
+ val isInvitation = spaceRoom.state == CurrentUserMembership.INVITED
+ SpaceRoomItemView(
+ spaceRoom = spaceRoom,
+ showUnreadIndicator = isInvitation && spaceRoom.roomId !in state.seenSpaceInvites,
+ hideAvatars = isInvitation && state.hideInvitesAvatar,
+ onClick = {
+ onRoomClick(spaceRoom.roomId)
+ },
+ onLongClick = {
+ // TODO
+ }
+ )
+ }
+ }
+ if (state.hasMoreToLoad) {
+ item {
+ LoadingMoreIndicator(eventSink = state.eventSink)
+ }
+ }
+ }
+}
+
+@Composable
+private fun LoadingMoreIndicator(
+ eventSink: (SpaceEvents) -> Unit,
+ modifier: Modifier = Modifier
+) {
+ Box(
+ modifier = modifier.fillMaxWidth(),
+ contentAlignment = Alignment.Center,
+ ) {
+ CircularProgressIndicator(
+ strokeWidth = 2.dp,
+ modifier = Modifier.padding(vertical = 8.dp)
+ )
+ val latestEventSink by rememberUpdatedState(eventSink)
+ LaunchedEffect(Unit) {
+ latestEventSink(SpaceEvents.LoadMore)
+ }
+ }
+}
+
+@OptIn(ExperimentalMaterial3Api::class)
+@Composable
+private fun SpaceViewTopBar(
+ currentSpace: SpaceRoom?,
+ onBackClick: () -> Unit,
+ modifier: Modifier = Modifier,
+) {
+ TopAppBar(
+ modifier = modifier,
+ navigationIcon = {
+ BackButton(onClick = onBackClick)
+ },
+ title = {
+ if (currentSpace != null) {
+ SpaceAvatarAndNameRow(
+ name = currentSpace.name,
+ avatarData = currentSpace.getAvatarData(AvatarSize.TimelineRoom),
+ )
+ }
+ },
+ actions = {
+ },
+ )
+}
+
+@Composable
+private fun SpaceAvatarAndNameRow(
+ name: String?,
+ avatarData: AvatarData,
+ modifier: Modifier = Modifier
+) {
+ Row(
+ modifier = modifier,
+ verticalAlignment = Alignment.CenterVertically
+ ) {
+ Avatar(
+ avatarData = avatarData,
+ avatarType = AvatarType.Space(),
+ )
+ Text(
+ modifier = Modifier
+ .padding(horizontal = 8.dp)
+ .semantics {
+ heading()
+ },
+ text = name ?: stringResource(CommonStrings.common_no_space_name),
+ style = ElementTheme.typography.fontBodyLgMedium,
+ fontStyle = FontStyle.Italic.takeIf { name == null },
+ maxLines = 1,
+ overflow = TextOverflow.Ellipsis
+ )
+ }
+}
+
+@PreviewsDayNight
+@Composable
+internal fun SpaceViewPreview(
+ @PreviewParameter(SpaceStateProvider::class) state: SpaceState
+) = ElementPreview {
+ SpaceView(
+ state = state,
+ onRoomClick = {},
+ onBackClick = {},
+ )
+}
diff --git a/features/space/impl/src/test/kotlin/io/element/android/features/space/impl/DefaultSpaceEntryPointTest.kt b/features/space/impl/src/test/kotlin/io/element/android/features/space/impl/DefaultSpaceEntryPointTest.kt
new file mode 100644
index 0000000000..465fde3425
--- /dev/null
+++ b/features/space/impl/src/test/kotlin/io/element/android/features/space/impl/DefaultSpaceEntryPointTest.kt
@@ -0,0 +1,64 @@
+/*
+ * Copyright 2025 New Vector Ltd.
+ *
+ * SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial
+ * Please see LICENSE files in the repository root for full details.
+ */
+
+package io.element.android.features.space.impl
+
+import androidx.arch.core.executor.testing.InstantTaskExecutorRule
+import com.bumble.appyx.core.modality.BuildContext
+import com.google.common.truth.Truth.assertThat
+import io.element.android.features.invite.test.InMemorySeenInvitesStore
+import io.element.android.features.space.api.SpaceEntryPoint
+import io.element.android.libraries.matrix.api.core.RoomId
+import io.element.android.libraries.matrix.test.A_ROOM_ID
+import io.element.android.libraries.matrix.test.FakeMatrixClient
+import io.element.android.libraries.matrix.test.spaces.FakeSpaceRoomList
+import io.element.android.libraries.matrix.test.spaces.FakeSpaceService
+import io.element.android.tests.testutils.lambda.lambdaError
+import io.element.android.tests.testutils.node.TestParentNode
+import org.junit.Rule
+import org.junit.Test
+
+class DefaultSpaceEntryPointTest {
+ @get:Rule
+ val instantTaskExecutorRule = InstantTaskExecutorRule()
+
+ @Test
+ fun `test node builder`() {
+ val entryPoint = DefaultSpaceEntryPoint()
+ val nodeInputs = SpaceEntryPoint.Inputs(A_ROOM_ID)
+ val parentNode = TestParentNode.create { buildContext, plugins ->
+ SpaceNode(
+ buildContext = buildContext,
+ plugins = plugins,
+ presenterFactory = { inputs ->
+ assertThat(inputs).isEqualTo(nodeInputs)
+ SpacePresenter(
+ inputs = inputs,
+ client = FakeMatrixClient(
+ spaceService = FakeSpaceService(
+ spaceRoomListResult = { FakeSpaceRoomList() },
+ )
+ ),
+ seenInvitesStore = InMemorySeenInvitesStore(),
+ )
+ },
+ )
+ }
+ val callback = object : SpaceEntryPoint.Callback {
+ override fun onOpenRoom(roomId: RoomId) {
+ lambdaError()
+ }
+ }
+ val result = entryPoint.nodeBuilder(parentNode, BuildContext.root(null))
+ .inputs(nodeInputs)
+ .callback(callback)
+ .build()
+ assertThat(result).isInstanceOf(SpaceNode::class.java)
+ assertThat(result.plugins).contains(nodeInputs)
+ assertThat(result.plugins).contains(callback)
+ }
+}
diff --git a/features/space/impl/src/test/kotlin/io/element/android/features/space/impl/SpacePresenterTest.kt b/features/space/impl/src/test/kotlin/io/element/android/features/space/impl/SpacePresenterTest.kt
new file mode 100644
index 0000000000..0bcd1303ae
--- /dev/null
+++ b/features/space/impl/src/test/kotlin/io/element/android/features/space/impl/SpacePresenterTest.kt
@@ -0,0 +1,167 @@
+/*
+ * Copyright 2025 New Vector Ltd.
+ *
+ * SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial
+ * Please see LICENSE files in the repository root for full details.
+ */
+
+@file:OptIn(ExperimentalCoroutinesApi::class)
+
+package io.element.android.features.space.impl
+
+import com.google.common.truth.Truth.assertThat
+import io.element.android.features.invite.api.SeenInvitesStore
+import io.element.android.features.invite.test.InMemorySeenInvitesStore
+import io.element.android.features.space.api.SpaceEntryPoint
+import io.element.android.libraries.matrix.api.MatrixClient
+import io.element.android.libraries.matrix.api.spaces.SpaceRoomList
+import io.element.android.libraries.matrix.test.A_ROOM_ID
+import io.element.android.libraries.matrix.test.FakeMatrixClient
+import io.element.android.libraries.matrix.test.spaces.FakeSpaceRoomList
+import io.element.android.libraries.matrix.test.spaces.FakeSpaceService
+import io.element.android.libraries.previewutils.room.aSpaceRoom
+import io.element.android.tests.testutils.lambda.lambdaRecorder
+import io.element.android.tests.testutils.test
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.test.advanceUntilIdle
+import kotlinx.coroutines.test.runTest
+import org.junit.Test
+
+class SpacePresenterTest {
+ @Test
+ fun `present - initial state`() = runTest {
+ val paginateResult = lambdaRecorder> {
+ Result.success(Unit)
+ }
+ val presenter = createSpacePresenter(
+ client = FakeMatrixClient(
+ spaceService = FakeSpaceService(
+ spaceRoomListResult = {
+ FakeSpaceRoomList(
+ paginateResult = paginateResult,
+ )
+ },
+ ),
+ ),
+ )
+ presenter.test {
+ val state = awaitItem()
+ assertThat(state.currentSpace).isNull()
+ assertThat(state.children).isEmpty()
+ assertThat(state.seenSpaceInvites).isEmpty()
+ assertThat(state.hideInvitesAvatar).isFalse()
+ assertThat(state.hasMoreToLoad).isTrue()
+ advanceUntilIdle()
+ paginateResult.assertions().isCalledOnce()
+ }
+ }
+
+ @Test
+ fun `present - load more`() = runTest {
+ val paginateResult = lambdaRecorder> {
+ Result.success(Unit)
+ }
+ val presenter = createSpacePresenter(
+ client = FakeMatrixClient(
+ spaceService = FakeSpaceService(
+ spaceRoomListResult = {
+ FakeSpaceRoomList(
+ paginateResult = paginateResult,
+ )
+ },
+ ),
+ ),
+ )
+ presenter.test {
+ val state = awaitItem()
+ advanceUntilIdle()
+ paginateResult.assertions().isCalledOnce()
+ state.eventSink(SpaceEvents.LoadMore)
+ advanceUntilIdle()
+ paginateResult.assertions().isCalledExactly(2)
+ }
+ }
+
+ @Test
+ fun `present - has more to load value`() = runTest {
+ val fakeSpaceRoomList = FakeSpaceRoomList(
+ paginateResult = { Result.success(Unit) },
+ )
+ val presenter = createSpacePresenter(
+ client = FakeMatrixClient(
+ spaceService = FakeSpaceService(
+ spaceRoomListResult = { fakeSpaceRoomList },
+ ),
+ ),
+ )
+ presenter.test {
+ val state = awaitItem()
+ advanceUntilIdle()
+ assertThat(state.hasMoreToLoad).isTrue()
+ fakeSpaceRoomList.emitPaginationStatus(
+ SpaceRoomList.PaginationStatus.Idle(hasMoreToLoad = false)
+ )
+ assertThat(awaitItem().hasMoreToLoad).isFalse()
+ fakeSpaceRoomList.emitPaginationStatus(
+ SpaceRoomList.PaginationStatus.Idle(hasMoreToLoad = true)
+ )
+ assertThat(awaitItem().hasMoreToLoad).isTrue()
+ }
+ }
+
+ @Test
+ fun `present - current space value`() = runTest {
+ val fakeSpaceRoomList = FakeSpaceRoomList(
+ paginateResult = { Result.success(Unit) },
+ )
+ val presenter = createSpacePresenter(
+ client = FakeMatrixClient(
+ spaceService = FakeSpaceService(
+ spaceRoomListResult = { fakeSpaceRoomList },
+ ),
+ ),
+ )
+ presenter.test {
+ val state = awaitItem()
+ advanceUntilIdle()
+ assertThat(state.currentSpace).isNull()
+ val aSpace = aSpaceRoom()
+ fakeSpaceRoomList.emitCurrentSpace(aSpace)
+ assertThat(awaitItem().currentSpace).isEqualTo(aSpace)
+ }
+ }
+
+ @Test
+ fun `present - children value`() = runTest {
+ val fakeSpaceRoomList = FakeSpaceRoomList(
+ paginateResult = { Result.success(Unit) },
+ )
+ val presenter = createSpacePresenter(
+ client = FakeMatrixClient(
+ spaceService = FakeSpaceService(
+ spaceRoomListResult = { fakeSpaceRoomList },
+ ),
+ ),
+ )
+ presenter.test {
+ val state = awaitItem()
+ advanceUntilIdle()
+ assertThat(state.children).isEmpty()
+ val aSpace = aSpaceRoom()
+ fakeSpaceRoomList.emitSpaceRooms(listOf(aSpace))
+ assertThat(awaitItem().children).containsExactly(aSpace)
+ }
+ }
+
+ private fun createSpacePresenter(
+ inputs: SpaceEntryPoint.Inputs = SpaceEntryPoint.Inputs(A_ROOM_ID),
+ client: MatrixClient = FakeMatrixClient(),
+ seenInvitesStore: SeenInvitesStore = InMemorySeenInvitesStore(),
+ ): SpacePresenter {
+ return SpacePresenter(
+ inputs = inputs,
+ client = client,
+ seenInvitesStore = seenInvitesStore,
+ )
+ }
+}
diff --git a/features/startchat/impl/build.gradle.kts b/features/startchat/impl/build.gradle.kts
index 42d5263d58..8ba7593b36 100644
--- a/features/startchat/impl/build.gradle.kts
+++ b/features/startchat/impl/build.gradle.kts
@@ -1,4 +1,5 @@
import extension.setupDependencyInjection
+import extension.testCommonDependencies
/*
* Copyright 2022-2024 New Vector Ltd.
@@ -43,13 +44,7 @@ dependencies {
implementation(projects.features.createroom.api)
api(projects.features.startchat.api)
- testImplementation(libs.test.junit)
- testImplementation(libs.test.mockk)
- testImplementation(libs.coroutines.test)
- testImplementation(libs.molecule.runtime)
- testImplementation(libs.test.truth)
- testImplementation(libs.test.turbine)
- testImplementation(libs.test.robolectric)
+ testCommonDependencies(libs, true)
testImplementation(projects.services.analytics.test)
testImplementation(projects.libraries.matrix.test)
testImplementation(projects.libraries.mediapickers.test)
@@ -58,7 +53,4 @@ dependencies {
testImplementation(projects.libraries.usersearch.test)
testImplementation(projects.features.startchat.test)
testImplementation(projects.libraries.featureflag.test)
- testImplementation(projects.tests.testutils)
- testImplementation(libs.androidx.compose.ui.test.junit)
- testReleaseImplementation(libs.androidx.compose.ui.test.manifest)
}
diff --git a/features/startchat/impl/src/test/kotlin/io/element/android/features/startchat/impl/DefaultStartChatEntryPointTest.kt b/features/startchat/impl/src/test/kotlin/io/element/android/features/startchat/impl/DefaultStartChatEntryPointTest.kt
new file mode 100644
index 0000000000..8f4a41a3fa
--- /dev/null
+++ b/features/startchat/impl/src/test/kotlin/io/element/android/features/startchat/impl/DefaultStartChatEntryPointTest.kt
@@ -0,0 +1,52 @@
+/*
+ * Copyright 2025 New Vector Ltd.
+ *
+ * SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial
+ * Please see LICENSE files in the repository root for full details.
+ */
+
+package io.element.android.features.startchat.impl
+
+import androidx.arch.core.executor.testing.InstantTaskExecutorRule
+import com.bumble.appyx.core.modality.BuildContext
+import com.bumble.appyx.core.node.Node
+import com.bumble.appyx.testing.junit4.util.MainDispatcherRule
+import com.google.common.truth.Truth.assertThat
+import io.element.android.features.createroom.api.CreateRoomEntryPoint
+import io.element.android.features.startchat.api.StartChatEntryPoint
+import io.element.android.libraries.matrix.api.core.RoomIdOrAlias
+import io.element.android.tests.testutils.lambda.lambdaError
+import io.element.android.tests.testutils.node.TestParentNode
+import org.junit.Rule
+import org.junit.Test
+
+class DefaultStartChatEntryPointTest {
+ @get:Rule
+ val instantTaskExecutorRule = InstantTaskExecutorRule()
+
+ @get:Rule
+ val mainDispatcherRule = MainDispatcherRule()
+
+ @Test
+ fun `test node builder`() {
+ val entryPoint = DefaultStartChatEntryPoint()
+ val parentNode = TestParentNode.create { buildContext, plugins ->
+ StartChatFlowNode(
+ buildContext = buildContext,
+ plugins = plugins,
+ createRoomEntryPoint = object : CreateRoomEntryPoint {
+ override fun nodeBuilder(parentNode: Node, buildContext: BuildContext) = lambdaError()
+ },
+ )
+ }
+ val callback = object : StartChatEntryPoint.Callback {
+ override fun onOpenRoom(roomIdOrAlias: RoomIdOrAlias, serverNames: List) = lambdaError()
+ override fun onOpenRoomDirectory() = lambdaError()
+ }
+ val result = entryPoint.nodeBuilder(parentNode, BuildContext.root(null))
+ .callback(callback)
+ .build()
+ assertThat(result).isInstanceOf(StartChatFlowNode::class.java)
+ assertThat(result.plugins).contains(callback)
+ }
+}
diff --git a/features/startchat/impl/src/test/kotlin/io/element/android/features/startchat/impl/root/StartChatPresenterTest.kt b/features/startchat/impl/src/test/kotlin/io/element/android/features/startchat/impl/root/StartChatPresenterTest.kt
index 59a8838c6b..7340981053 100644
--- a/features/startchat/impl/src/test/kotlin/io/element/android/features/startchat/impl/root/StartChatPresenterTest.kt
+++ b/features/startchat/impl/src/test/kotlin/io/element/android/features/startchat/impl/root/StartChatPresenterTest.kt
@@ -177,23 +177,23 @@ class StartChatPresenterTest {
}
}
}
-
- private fun createStartChatPresenter(
- startDMAction: StartDMAction = FakeStartDMAction(),
- isRoomDirectorySearchEnabled: Boolean = false,
- ): StartChatPresenter {
- val featureFlagService = FakeFeatureFlagService(
- initialState = mapOf(
- FeatureFlags.RoomDirectorySearch.key to isRoomDirectorySearchEnabled,
- ),
- )
- return StartChatPresenter(
- presenterFactory = FakeUserListPresenterFactory(FakeUserListPresenter()),
- userRepository = FakeUserRepository(),
- userListDataStore = UserListDataStore(),
- startDMAction = startDMAction,
- featureFlagService = featureFlagService,
- buildMeta = aBuildMeta(),
- )
- }
+}
+
+internal fun createStartChatPresenter(
+ startDMAction: StartDMAction = FakeStartDMAction(),
+ isRoomDirectorySearchEnabled: Boolean = false,
+): StartChatPresenter {
+ val featureFlagService = FakeFeatureFlagService(
+ initialState = mapOf(
+ FeatureFlags.RoomDirectorySearch.key to isRoomDirectorySearchEnabled,
+ ),
+ )
+ return StartChatPresenter(
+ presenterFactory = FakeUserListPresenterFactory(FakeUserListPresenter()),
+ userRepository = FakeUserRepository(),
+ userListDataStore = UserListDataStore(),
+ startDMAction = startDMAction,
+ featureFlagService = featureFlagService,
+ buildMeta = aBuildMeta(),
+ )
}
diff --git a/features/userprofile/impl/build.gradle.kts b/features/userprofile/impl/build.gradle.kts
index 0805f0d7fc..f0c214c22e 100644
--- a/features/userprofile/impl/build.gradle.kts
+++ b/features/userprofile/impl/build.gradle.kts
@@ -1,4 +1,5 @@
import extension.setupDependencyInjection
+import extension.testCommonDependencies
/*
* Copyright 2024 New Vector Ltd.
@@ -41,17 +42,8 @@ dependencies {
implementation(projects.features.startchat.api)
implementation(projects.services.analytics.api)
- testImplementation(libs.test.junit)
- testImplementation(libs.coroutines.test)
- testImplementation(libs.molecule.runtime)
- testImplementation(libs.test.truth)
- testImplementation(libs.test.turbine)
- testImplementation(libs.test.mockk)
- testImplementation(libs.test.robolectric)
+ testCommonDependencies(libs, true)
testImplementation(projects.libraries.matrix.test)
testImplementation(projects.features.startchat.test)
testImplementation(projects.features.enterprise.test)
- testImplementation(projects.tests.testutils)
- testImplementation(libs.androidx.compose.ui.test.junit)
- testReleaseImplementation(libs.androidx.compose.ui.test.manifest)
}
diff --git a/features/userprofile/impl/src/test/kotlin/io/element/android/features/userprofile/impl/DefaultUserProfileEntryPointTest.kt b/features/userprofile/impl/src/test/kotlin/io/element/android/features/userprofile/impl/DefaultUserProfileEntryPointTest.kt
new file mode 100644
index 0000000000..1537167d20
--- /dev/null
+++ b/features/userprofile/impl/src/test/kotlin/io/element/android/features/userprofile/impl/DefaultUserProfileEntryPointTest.kt
@@ -0,0 +1,86 @@
+/*
+ * Copyright 2025 New Vector Ltd.
+ *
+ * SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial
+ * Please see LICENSE files in the repository root for full details.
+ */
+
+package io.element.android.features.userprofile.impl
+
+import androidx.arch.core.executor.testing.InstantTaskExecutorRule
+import com.bumble.appyx.core.modality.BuildContext
+import com.bumble.appyx.core.node.Node
+import com.bumble.appyx.testing.junit4.util.MainDispatcherRule
+import com.google.common.truth.Truth.assertThat
+import io.element.android.features.call.api.CallType
+import io.element.android.features.call.api.ElementCallEntryPoint
+import io.element.android.features.userprofile.api.UserProfileEntryPoint
+import io.element.android.features.verifysession.api.OutgoingVerificationEntryPoint
+import io.element.android.libraries.matrix.api.core.EventId
+import io.element.android.libraries.matrix.api.core.RoomId
+import io.element.android.libraries.matrix.api.core.UserId
+import io.element.android.libraries.matrix.api.user.CurrentSessionIdHolder
+import io.element.android.libraries.matrix.test.A_USER_ID
+import io.element.android.libraries.matrix.test.FakeMatrixClient
+import io.element.android.libraries.mediaviewer.api.MediaViewerEntryPoint
+import io.element.android.tests.testutils.lambda.lambdaError
+import io.element.android.tests.testutils.node.TestParentNode
+import org.junit.Rule
+import org.junit.Test
+
+class DefaultUserProfileEntryPointTest {
+ @get:Rule
+ val instantTaskExecutorRule = InstantTaskExecutorRule()
+
+ @get:Rule
+ val mainDispatcherRule = MainDispatcherRule()
+
+ @Test
+ fun `test node builder`() {
+ val entryPoint = DefaultUserProfileEntryPoint()
+
+ val parentNode = TestParentNode.create { buildContext, plugins ->
+ UserProfileFlowNode(
+ buildContext = buildContext,
+ plugins = plugins,
+ sessionIdHolder = CurrentSessionIdHolder(FakeMatrixClient()),
+ elementCallEntryPoint = object : ElementCallEntryPoint {
+ override fun startCall(callType: CallType) = lambdaError()
+ override suspend fun handleIncomingCall(
+ callType: CallType.RoomCall,
+ eventId: EventId,
+ senderId: UserId,
+ roomName: String?,
+ senderName: String?,
+ avatarUrl: String?,
+ timestamp: Long,
+ expirationTimestamp: Long,
+ notificationChannelId: String,
+ textContent: String?
+ ) = lambdaError()
+ },
+ mediaViewerEntryPoint = object : MediaViewerEntryPoint {
+ override fun nodeBuilder(parentNode: Node, buildContext: BuildContext) = lambdaError()
+ },
+ outgoingVerificationEntryPoint = object : OutgoingVerificationEntryPoint {
+ override fun nodeBuilder(parentNode: Node, buildContext: BuildContext) = lambdaError()
+ },
+ )
+ }
+ val callback = object : UserProfileEntryPoint.Callback {
+ override fun onOpenRoom(roomId: RoomId) {
+ lambdaError()
+ }
+ }
+ val params = UserProfileEntryPoint.Params(
+ userId = A_USER_ID,
+ )
+ val result = entryPoint.nodeBuilder(parentNode, BuildContext.root(null))
+ .params(params)
+ .callback(callback)
+ .build()
+ assertThat(result).isInstanceOf(UserProfileFlowNode::class.java)
+ assertThat(result.plugins).contains(params)
+ assertThat(result.plugins).contains(callback)
+ }
+}
diff --git a/features/userprofile/shared/build.gradle.kts b/features/userprofile/shared/build.gradle.kts
index c49b78866f..95f64154cf 100644
--- a/features/userprofile/shared/build.gradle.kts
+++ b/features/userprofile/shared/build.gradle.kts
@@ -1,3 +1,5 @@
+import extension.testCommonDependencies
+
/*
* Copyright 2024 New Vector Ltd.
*
@@ -38,14 +40,6 @@ dependencies {
implementation(projects.features.startchat.api)
implementation(projects.services.analytics.api)
- testImplementation(libs.test.junit)
- testImplementation(libs.coroutines.test)
- testImplementation(libs.molecule.runtime)
- testImplementation(libs.test.truth)
- testImplementation(libs.test.turbine)
- testImplementation(libs.test.robolectric)
+ testCommonDependencies(libs, true)
testImplementation(projects.libraries.matrix.test)
- testImplementation(projects.tests.testutils)
- testImplementation(libs.androidx.compose.ui.test.junit)
- testReleaseImplementation(libs.androidx.compose.ui.test.manifest)
}
diff --git a/features/userprofile/shared/src/main/res/values-pt/translations.xml b/features/userprofile/shared/src/main/res/values-pt/translations.xml
index eae68be0b7..ec919a456a 100644
--- a/features/userprofile/shared/src/main/res/values-pt/translations.xml
+++ b/features/userprofile/shared/src/main/res/values-pt/translations.xml
@@ -14,6 +14,6 @@
"Poderás voltar a ver todas as suas mensagens."
"Desbloquear utilizador"
"Utiliza a aplicação Web para verificar este utilizador."
- "Verifique %1$s"
+ "Verifica %1$s"
"Ocorreu um erro ao tentar iniciar uma conversa"
diff --git a/features/verifysession/impl/build.gradle.kts b/features/verifysession/impl/build.gradle.kts
index b318b10fce..13e9010e7f 100644
--- a/features/verifysession/impl/build.gradle.kts
+++ b/features/verifysession/impl/build.gradle.kts
@@ -1,4 +1,5 @@
import extension.setupDependencyInjection
+import extension.testCommonDependencies
/*
* Copyright 2023, 2024 New Vector Ltd.
@@ -37,17 +38,9 @@ dependencies {
api(libs.statemachine)
api(projects.features.verifysession.api)
- testImplementation(libs.test.junit)
- testImplementation(libs.coroutines.test)
- testImplementation(libs.molecule.runtime)
- testImplementation(libs.test.robolectric)
- testImplementation(libs.test.truth)
- testImplementation(libs.test.turbine)
+ testCommonDependencies(libs, true)
testImplementation(projects.features.logout.test)
testImplementation(projects.libraries.dateformatter.test)
testImplementation(projects.libraries.matrix.test)
testImplementation(projects.libraries.preferences.test)
- testImplementation(projects.tests.testutils)
- testImplementation(libs.androidx.compose.ui.test.junit)
- testReleaseImplementation(libs.androidx.compose.ui.test.manifest)
}
diff --git a/features/verifysession/impl/src/main/kotlin/io/element/android/features/verifysession/impl/incoming/IncomingVerificationPresenter.kt b/features/verifysession/impl/src/main/kotlin/io/element/android/features/verifysession/impl/incoming/IncomingVerificationPresenter.kt
index aab6ff0329..8be176f117 100644
--- a/features/verifysession/impl/src/main/kotlin/io/element/android/features/verifysession/impl/incoming/IncomingVerificationPresenter.kt
+++ b/features/verifysession/impl/src/main/kotlin/io/element/android/features/verifysession/impl/incoming/IncomingVerificationPresenter.kt
@@ -48,7 +48,7 @@ class IncomingVerificationPresenter(
private val dateFormatter: DateFormatter,
) : Presenter {
@AssistedFactory
- interface Factory {
+ fun interface Factory {
fun create(
verificationRequest: VerificationRequest.Incoming,
navigator: IncomingVerificationNavigator,
diff --git a/features/verifysession/impl/src/main/kotlin/io/element/android/features/verifysession/impl/outgoing/OutgoingVerificationPresenter.kt b/features/verifysession/impl/src/main/kotlin/io/element/android/features/verifysession/impl/outgoing/OutgoingVerificationPresenter.kt
index 5b6004845d..84ebec96de 100644
--- a/features/verifysession/impl/src/main/kotlin/io/element/android/features/verifysession/impl/outgoing/OutgoingVerificationPresenter.kt
+++ b/features/verifysession/impl/src/main/kotlin/io/element/android/features/verifysession/impl/outgoing/OutgoingVerificationPresenter.kt
@@ -42,7 +42,7 @@ class OutgoingVerificationPresenter(
private val encryptionService: EncryptionService,
) : Presenter {
@AssistedFactory
- interface Factory {
+ fun interface Factory {
fun create(
verificationRequest: VerificationRequest.Outgoing,
showDeviceVerifiedScreen: Boolean,
diff --git a/features/verifysession/impl/src/main/res/values-eo/translations.xml b/features/verifysession/impl/src/main/res/values-eo/translations.xml
new file mode 100644
index 0000000000..d4b40184a1
--- /dev/null
+++ b/features/verifysession/impl/src/main/res/values-eo/translations.xml
@@ -0,0 +1,13 @@
+
+
+ "Create a new backup password"
+ "Confirm this device to set up secure messaging."
+ "Confirm it\'s you"
+ "Use backup password"
+ "Device confirmed"
+ "Now you can trust this user when sending or receiving messages."
+ "Enter backup password"
+ "Device confirmed"
+ "Open the app on another confirmed device"
+ "For extra security, another user wants to verify you. You\'ll be shown a set of emojis to compare."
+
diff --git a/features/verifysession/impl/src/main/res/values-pt/translations.xml b/features/verifysession/impl/src/main/res/values-pt/translations.xml
index 1386091254..ce2eb2af15 100644
--- a/features/verifysession/impl/src/main/res/values-pt/translations.xml
+++ b/features/verifysession/impl/src/main/res/values-pt/translations.xml
@@ -30,7 +30,7 @@
"Sessão iniciada"
"O pedido expirou, o pedido foi recusado ou houve um erro de verificação."
"A verificação falhou"
- "Continue apenas se tiver iniciado esta verificação."
+ "Continua apenas se tiveres iniciado esta verificação."
"Verifique o outro dispositivo para manter o histórico de mensagens seguro."
"Agora podes ler ou enviar mensagens de forma segura no teu outro dispositivo."
"Dispositivo verificado"
diff --git a/features/verifysession/impl/src/test/kotlin/io/element/android/features/verifysession/impl/incoming/DefaultIncomingVerificationEntryPointTest.kt b/features/verifysession/impl/src/test/kotlin/io/element/android/features/verifysession/impl/incoming/DefaultIncomingVerificationEntryPointTest.kt
new file mode 100644
index 0000000000..ad586fc7fb
--- /dev/null
+++ b/features/verifysession/impl/src/test/kotlin/io/element/android/features/verifysession/impl/incoming/DefaultIncomingVerificationEntryPointTest.kt
@@ -0,0 +1,48 @@
+/*
+ * Copyright 2025 New Vector Ltd.
+ *
+ * SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial
+ * Please see LICENSE files in the repository root for full details.
+ */
+
+package io.element.android.features.verifysession.impl.incoming
+
+import androidx.arch.core.executor.testing.InstantTaskExecutorRule
+import com.bumble.appyx.core.modality.BuildContext
+import com.google.common.truth.Truth.assertThat
+import io.element.android.features.verifysession.api.IncomingVerificationEntryPoint
+import io.element.android.tests.testutils.lambda.lambdaError
+import io.element.android.tests.testutils.node.TestParentNode
+import kotlinx.coroutines.test.runTest
+import org.junit.Rule
+import org.junit.Test
+
+class DefaultIncomingVerificationEntryPointTest {
+ @get:Rule
+ val instantTaskExecutorRule = InstantTaskExecutorRule()
+
+ @Test
+ fun `test node builder`() = runTest {
+ val entryPoint = DefaultIncomingVerificationEntryPoint()
+ val parentNode = TestParentNode.create { buildContext, plugins ->
+ IncomingVerificationNode(
+ buildContext = buildContext,
+ plugins = plugins,
+ presenterFactory = { _, _ -> createPresenter() }
+ )
+ }
+ val callback = object : IncomingVerificationEntryPoint.Callback {
+ override fun onDone() = lambdaError()
+ }
+ val params = IncomingVerificationEntryPoint.Params(
+ verificationRequest = anIncomingSessionVerificationRequest()
+ )
+ val result = entryPoint.nodeBuilder(parentNode, BuildContext.root(null))
+ .params(params)
+ .callback(callback)
+ .build()
+ assertThat(result).isInstanceOf(IncomingVerificationNode::class.java)
+ assertThat(result.plugins).contains(params)
+ assertThat(result.plugins).contains(callback)
+ }
+}
diff --git a/features/verifysession/impl/src/test/kotlin/io/element/android/features/verifysession/impl/incoming/IncomingVerificationPresenterTest.kt b/features/verifysession/impl/src/test/kotlin/io/element/android/features/verifysession/impl/incoming/IncomingVerificationPresenterTest.kt
index 8fdf62df4f..06c4956ea9 100644
--- a/features/verifysession/impl/src/test/kotlin/io/element/android/features/verifysession/impl/incoming/IncomingVerificationPresenterTest.kt
+++ b/features/verifysession/impl/src/test/kotlin/io/element/android/features/verifysession/impl/incoming/IncomingVerificationPresenterTest.kt
@@ -289,31 +289,31 @@ class IncomingVerificationPresenterTest {
navigatorLambda.assertions().isCalledOnce()
}
}
-
- private val anIncomingSessionVerificationRequest = VerificationRequest.Incoming.OtherSession(
- details = SessionVerificationRequestDetails(
- senderProfile = SessionVerificationRequestDetails.SenderProfile(
- userId = A_USER_ID,
- displayName = "a device name",
- avatarUrl = null,
- ),
- flowId = FlowId("flowId"),
- deviceId = A_DEVICE_ID,
- firstSeenTimestamp = A_TIMESTAMP,
- )
- )
-
- private fun TestScope.createPresenter(
- verificationRequest: VerificationRequest.Incoming = anIncomingSessionVerificationRequest,
- navigator: IncomingVerificationNavigator = IncomingVerificationNavigator { lambdaError() },
- service: SessionVerificationService = FakeSessionVerificationService(),
- dateFormatter: DateFormatter = FakeDateFormatter(),
- ) = IncomingVerificationPresenter(
- verificationRequest = verificationRequest,
- navigator = navigator,
- sessionVerificationService = service,
- stateMachine = IncomingVerificationStateMachine(service),
- dateFormatter = dateFormatter,
- sessionCoroutineScope = backgroundScope,
- )
}
+
+private val anIncomingSessionVerificationRequest = VerificationRequest.Incoming.OtherSession(
+ details = SessionVerificationRequestDetails(
+ senderProfile = SessionVerificationRequestDetails.SenderProfile(
+ userId = A_USER_ID,
+ displayName = "a device name",
+ avatarUrl = null,
+ ),
+ flowId = FlowId("flowId"),
+ deviceId = A_DEVICE_ID,
+ firstSeenTimestamp = A_TIMESTAMP,
+ )
+)
+
+internal fun TestScope.createPresenter(
+ verificationRequest: VerificationRequest.Incoming = anIncomingSessionVerificationRequest,
+ navigator: IncomingVerificationNavigator = IncomingVerificationNavigator { lambdaError() },
+ service: SessionVerificationService = FakeSessionVerificationService(),
+ dateFormatter: DateFormatter = FakeDateFormatter(),
+) = IncomingVerificationPresenter(
+ verificationRequest = verificationRequest,
+ navigator = navigator,
+ sessionVerificationService = service,
+ stateMachine = IncomingVerificationStateMachine(service),
+ dateFormatter = dateFormatter,
+ sessionCoroutineScope = backgroundScope,
+)
diff --git a/features/verifysession/impl/src/test/kotlin/io/element/android/features/verifysession/impl/outgoing/DefaultOutgoingVerificationEntryPointTest.kt b/features/verifysession/impl/src/test/kotlin/io/element/android/features/verifysession/impl/outgoing/DefaultOutgoingVerificationEntryPointTest.kt
new file mode 100644
index 0000000000..52ff36dbd6
--- /dev/null
+++ b/features/verifysession/impl/src/test/kotlin/io/element/android/features/verifysession/impl/outgoing/DefaultOutgoingVerificationEntryPointTest.kt
@@ -0,0 +1,53 @@
+/*
+ * Copyright 2025 New Vector Ltd.
+ *
+ * SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial
+ * Please see LICENSE files in the repository root for full details.
+ */
+
+package io.element.android.features.verifysession.impl.outgoing
+
+import androidx.arch.core.executor.testing.InstantTaskExecutorRule
+import com.bumble.appyx.core.modality.BuildContext
+import com.google.common.truth.Truth.assertThat
+import io.element.android.features.verifysession.api.OutgoingVerificationEntryPoint
+import io.element.android.tests.testutils.lambda.lambdaError
+import io.element.android.tests.testutils.node.TestParentNode
+import org.junit.Rule
+import org.junit.Test
+
+class DefaultOutgoingVerificationEntryPointTest {
+ @get:Rule
+ val instantTaskExecutorRule = InstantTaskExecutorRule()
+
+ @Test
+ fun `test node builder`() {
+ val entryPoint = DefaultOutgoingVerificationEntryPoint()
+
+ val parentNode = TestParentNode.create { buildContext, plugins ->
+ OutgoingVerificationNode(
+ buildContext = buildContext,
+ plugins = plugins,
+ presenterFactory = { _, _ ->
+ createOutgoingVerificationPresenter()
+ }
+ )
+ }
+ val callback = object : OutgoingVerificationEntryPoint.Callback {
+ override fun onLearnMoreAboutEncryption() = lambdaError()
+ override fun onBack() = lambdaError()
+ override fun onDone() = lambdaError()
+ }
+ val params = OutgoingVerificationEntryPoint.Params(
+ showDeviceVerifiedScreen = true,
+ verificationRequest = anOutgoingSessionVerificationRequest(),
+ )
+ val result = entryPoint.nodeBuilder(parentNode, BuildContext.root(null))
+ .params(params)
+ .callback(callback)
+ .build()
+ assertThat(result).isInstanceOf(OutgoingVerificationNode::class.java)
+ assertThat(result.plugins).contains(params)
+ assertThat(result.plugins).contains(callback)
+ }
+}
diff --git a/features/verifysession/impl/src/test/kotlin/io/element/android/features/verifysession/impl/outgoing/OutgoingVerificationPresenterTest.kt b/features/verifysession/impl/src/test/kotlin/io/element/android/features/verifysession/impl/outgoing/OutgoingVerificationPresenterTest.kt
index 06940f37a5..2eac19d018 100644
--- a/features/verifysession/impl/src/test/kotlin/io/element/android/features/verifysession/impl/outgoing/OutgoingVerificationPresenterTest.kt
+++ b/features/verifysession/impl/src/test/kotlin/io/element/android/features/verifysession/impl/outgoing/OutgoingVerificationPresenterTest.kt
@@ -321,18 +321,18 @@ class OutgoingVerificationPresenterTest {
emitVerifiedStatus(SessionVerifiedStatus.NotVerified)
}
}
-
- private fun createOutgoingVerificationPresenter(
- service: SessionVerificationService,
- verificationRequest: VerificationRequest.Outgoing = anOutgoingSessionVerificationRequest(),
- encryptionService: EncryptionService = FakeEncryptionService(),
- showDeviceVerifiedScreen: Boolean = false,
- ): OutgoingVerificationPresenter {
- return OutgoingVerificationPresenter(
- showDeviceVerifiedScreen = showDeviceVerifiedScreen,
- verificationRequest = verificationRequest,
- sessionVerificationService = service,
- encryptionService = encryptionService,
- )
- }
+}
+
+internal fun createOutgoingVerificationPresenter(
+ service: SessionVerificationService = FakeSessionVerificationService(),
+ verificationRequest: VerificationRequest.Outgoing = anOutgoingSessionVerificationRequest(),
+ encryptionService: EncryptionService = FakeEncryptionService(),
+ showDeviceVerifiedScreen: Boolean = false,
+): OutgoingVerificationPresenter {
+ return OutgoingVerificationPresenter(
+ showDeviceVerifiedScreen = showDeviceVerifiedScreen,
+ verificationRequest = verificationRequest,
+ sessionVerificationService = service,
+ encryptionService = encryptionService,
+ )
}
diff --git a/features/viewfolder/impl/build.gradle.kts b/features/viewfolder/impl/build.gradle.kts
index 023f3c5762..0c7ef17b22 100644
--- a/features/viewfolder/impl/build.gradle.kts
+++ b/features/viewfolder/impl/build.gradle.kts
@@ -1,4 +1,5 @@
import extension.setupDependencyInjection
+import extension.testCommonDependencies
/*
* Copyright 2024 New Vector Ltd.
@@ -26,12 +27,6 @@ dependencies {
implementation(projects.libraries.uiStrings)
api(projects.features.viewfolder.api)
- testImplementation(libs.test.junit)
- testImplementation(libs.test.robolectric)
- testImplementation(libs.coroutines.test)
- testImplementation(libs.molecule.runtime)
- testImplementation(libs.test.truth)
- testImplementation(libs.test.turbine)
- testImplementation(projects.tests.testutils)
+ testCommonDependencies(libs)
testImplementation(projects.libraries.matrix.test)
}
diff --git a/features/viewfolder/impl/src/main/kotlin/io/element/android/features/viewfolder/impl/DefaultViewFolderEntryPoint.kt b/features/viewfolder/impl/src/main/kotlin/io/element/android/features/viewfolder/impl/DefaultViewFolderEntryPoint.kt
index 64d469c34f..330ca68a8c 100644
--- a/features/viewfolder/impl/src/main/kotlin/io/element/android/features/viewfolder/impl/DefaultViewFolderEntryPoint.kt
+++ b/features/viewfolder/impl/src/main/kotlin/io/element/android/features/viewfolder/impl/DefaultViewFolderEntryPoint.kt
@@ -14,7 +14,7 @@ import dev.zacsweers.metro.AppScope
import dev.zacsweers.metro.ContributesBinding
import dev.zacsweers.metro.Inject
import io.element.android.features.viewfolder.api.ViewFolderEntryPoint
-import io.element.android.features.viewfolder.impl.root.ViewFolderRootNode
+import io.element.android.features.viewfolder.impl.root.ViewFolderFlowNode
import io.element.android.libraries.architecture.createNode
@ContributesBinding(AppScope::class)
@@ -25,7 +25,7 @@ class DefaultViewFolderEntryPoint : ViewFolderEntryPoint {
return object : ViewFolderEntryPoint.NodeBuilder {
override fun params(params: ViewFolderEntryPoint.Params): ViewFolderEntryPoint.NodeBuilder {
- plugins += ViewFolderRootNode.Inputs(params.rootPath)
+ plugins += ViewFolderFlowNode.Inputs(params.rootPath)
return this
}
@@ -35,7 +35,7 @@ class DefaultViewFolderEntryPoint : ViewFolderEntryPoint {
}
override fun build(): Node {
- return parentNode.createNode(buildContext, plugins)
+ return parentNode.createNode(buildContext, plugins)
}
}
}
diff --git a/features/viewfolder/impl/src/main/kotlin/io/element/android/features/viewfolder/impl/root/ViewFolderRootNode.kt b/features/viewfolder/impl/src/main/kotlin/io/element/android/features/viewfolder/impl/root/ViewFolderFlowNode.kt
similarity index 98%
rename from features/viewfolder/impl/src/main/kotlin/io/element/android/features/viewfolder/impl/root/ViewFolderRootNode.kt
rename to features/viewfolder/impl/src/main/kotlin/io/element/android/features/viewfolder/impl/root/ViewFolderFlowNode.kt
index 984c2e1f10..2eb6712364 100644
--- a/features/viewfolder/impl/src/main/kotlin/io/element/android/features/viewfolder/impl/root/ViewFolderRootNode.kt
+++ b/features/viewfolder/impl/src/main/kotlin/io/element/android/features/viewfolder/impl/root/ViewFolderFlowNode.kt
@@ -34,10 +34,10 @@ import kotlinx.parcelize.Parcelize
@ContributesNode(AppScope::class)
@Inject
-class ViewFolderRootNode(
+class ViewFolderFlowNode(
@Assisted buildContext: BuildContext,
@Assisted plugins: List,
-) : BaseFlowNode(
+) : BaseFlowNode(
backstack = BackStack(
initialElement = NavTarget.Root,
savedStateMap = buildContext.savedStateMap,
diff --git a/features/viewfolder/impl/src/test/kotlin/io/element/android/features/viewfolder/impl/DefaultViewFolderEntryPointTest.kt b/features/viewfolder/impl/src/test/kotlin/io/element/android/features/viewfolder/impl/DefaultViewFolderEntryPointTest.kt
new file mode 100644
index 0000000000..47d5992d8c
--- /dev/null
+++ b/features/viewfolder/impl/src/test/kotlin/io/element/android/features/viewfolder/impl/DefaultViewFolderEntryPointTest.kt
@@ -0,0 +1,51 @@
+/*
+ * Copyright 2025 New Vector Ltd.
+ *
+ * SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial
+ * Please see LICENSE files in the repository root for full details.
+ */
+
+package io.element.android.features.viewfolder.impl
+
+import androidx.arch.core.executor.testing.InstantTaskExecutorRule
+import com.bumble.appyx.core.modality.BuildContext
+import com.bumble.appyx.testing.junit4.util.MainDispatcherRule
+import com.google.common.truth.Truth.assertThat
+import io.element.android.features.viewfolder.api.ViewFolderEntryPoint
+import io.element.android.features.viewfolder.impl.root.ViewFolderFlowNode
+import io.element.android.tests.testutils.lambda.lambdaError
+import io.element.android.tests.testutils.node.TestParentNode
+import org.junit.Rule
+import org.junit.Test
+
+class DefaultViewFolderEntryPointTest {
+ @get:Rule
+ val instantTaskExecutorRule = InstantTaskExecutorRule()
+
+ @get:Rule
+ val mainDispatcherRule = MainDispatcherRule()
+
+ @Test
+ fun `test node builder`() {
+ val entryPoint = DefaultViewFolderEntryPoint()
+ val parentNode = TestParentNode.create { buildContext, plugins ->
+ ViewFolderFlowNode(
+ buildContext = buildContext,
+ plugins = plugins,
+ )
+ }
+ val callback = object : ViewFolderEntryPoint.Callback {
+ override fun onDone() = lambdaError()
+ }
+ val params = ViewFolderEntryPoint.Params(
+ rootPath = "path",
+ )
+ val result = entryPoint.nodeBuilder(parentNode, BuildContext.root(null))
+ .params(params)
+ .callback(callback)
+ .build()
+ assertThat(result).isInstanceOf(ViewFolderFlowNode::class.java)
+ assertThat(result.plugins).contains(ViewFolderFlowNode.Inputs(params.rootPath))
+ assertThat(result.plugins).contains(callback)
+ }
+}
diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml
index 0825c5049e..ea78e146b4 100644
--- a/gradle/libs.versions.toml
+++ b/gradle/libs.versions.toml
@@ -17,9 +17,9 @@ datastore = "1.1.7"
constraintlayout = "2.2.1"
constraintlayout_compose = "1.1.1"
lifecycle = "2.9.2"
-activity = "1.10.1"
+activity = "1.11.0"
media3 = "1.8.0"
-camera = "1.4.2"
+camera = "1.5.0"
# Compose
compose_bom = "2025.07.00"
@@ -44,11 +44,11 @@ showkase = "1.0.5"
appyx = "1.7.1"
sqldelight = "2.1.0"
wysiwyg = "2.39.0"
-telephoto = "0.16.0"
+telephoto = "0.17.0"
haze = "1.6.10"
# Dependency analysis
-dependencyAnalysis = "2.19.0"
+dependencyAnalysis = "3.0.4"
# DI
metro = "0.6.4"
@@ -74,7 +74,7 @@ kotlinpoet-ksp = { module = "com.squareup:kotlinpoet-ksp", version.ref = "kotlin
kover_gradle_plugin = { module = "org.jetbrains.kotlinx:kover-gradle-plugin", version.ref = "kover" }
ksp_gradle_plugin = { module = "com.google.devtools.ksp:com.google.devtools.ksp.gradle.plugin", version.ref = "ksp" }
# https://firebase.google.com/docs/android/setup#available-libraries
-google_firebase_bom = "com.google.firebase:firebase-bom:34.2.0"
+google_firebase_bom = "com.google.firebase:firebase-bom:34.3.0"
firebase_appdistribution_gradle = { module = "com.google.firebase:firebase-appdistribution-gradle", version.ref = "firebaseAppDistribution" }
autonomousapps_dependencyanalysis_plugin = { module = "com.autonomousapps:dependency-analysis-gradle-plugin", version.ref = "dependencyAnalysis" }
ksp_plugin = { module = "com.google.devtools.ksp:symbol-processing-api", version.ref = "ksp" }
@@ -152,14 +152,22 @@ test_runner = "androidx.test:runner:1.7.0"
test_mockk = "io.mockk:mockk:1.14.5"
test_konsist = "com.lemonappdev:konsist:0.17.3"
test_turbine = "app.cash.turbine:turbine:1.2.1"
-test_truth = "com.google.truth:truth:1.4.4"
-test_parameter_injector = "com.google.testparameterinjector:test-parameter-injector:1.18"
+test_truth = "com.google.truth:truth:1.4.5"
+test_parameter_injector = "com.google.testparameterinjector:test-parameter-injector:1.19"
test_robolectric = "org.robolectric:robolectric:4.15.1"
test_appyx_junit = { module = "com.bumble.appyx:testing-junit4", version.ref = "appyx" }
test_composable_preview_scanner = "io.github.sergio-sastre.ComposablePreviewScanner:android:0.7.0"
test_detekt_api = { module = "io.gitlab.arturbosch.detekt:detekt-api", version.ref = "detekt" }
test_detekt_test = { module = "io.gitlab.arturbosch.detekt:detekt-test", version.ref = "detekt" }
+# Matrix SDK
+# When upgrading the library, you may want to check what's new in the FFI layer by having a look to the
+# latest commits from the history of this file:
+# https://github.com/matrix-org/matrix-rust-components-kotlin/commits/main/sdk/sdk-android/src/main/kotlin/org/matrix/rustcomponents/sdk/matrix_sdk_ffi.kt
+# All new features should not be implemented in the pull request that upgrades the version, developers should
+# only fix API breaks and may add some TODOs.
+matrix_sdk = "org.matrix.rustcomponents:sdk-android:25.9.23"
+
# Others
coil = { module = "io.coil-kt.coil3:coil", version.ref = "coil" }
coil_network_okhttp = { module = "io.coil-kt.coil3:coil-network-okhttp", version.ref = "coil" }
@@ -176,20 +184,19 @@ jsoup = "org.jsoup:jsoup:1.21.2"
appyx_core = { module = "com.bumble.appyx:core", version.ref = "appyx" }
molecule-runtime = "app.cash.molecule:molecule-runtime:2.1.0"
timber = "com.jakewharton.timber:timber:5.0.1"
-matrix_sdk = "org.matrix.rustcomponents:sdk-android:25.9.1"
matrix_richtexteditor = { module = "io.element.android:wysiwyg", version.ref = "wysiwyg" }
matrix_richtexteditor_compose = { module = "io.element.android:wysiwyg-compose", version.ref = "wysiwyg" }
sqldelight-driver-android = { module = "app.cash.sqldelight:android-driver", version.ref = "sqldelight" }
sqldelight-driver-jvm = { module = "app.cash.sqldelight:sqlite-driver", version.ref = "sqldelight" }
sqldelight-coroutines = { module = "app.cash.sqldelight:coroutines-extensions", version.ref = "sqldelight" }
sqlcipher = "net.zetetic:sqlcipher-android:4.10.0"
-sqlite = "androidx.sqlite:sqlite-ktx:2.5.2"
+sqlite = "androidx.sqlite:sqlite-ktx:2.6.0"
unifiedpush = "org.unifiedpush.android:connector:3.0.10"
vanniktech_blurhash = "com.vanniktech:blurhash:0.3.0"
telephoto_zoomableimage = { module = "me.saket.telephoto:zoomable-image-coil", version.ref = "telephoto" }
telephoto_flick = { module = "me.saket.telephoto:flick-android", version.ref = "telephoto" }
statemachine = "com.freeletics.flowredux:compose:1.2.2"
-maplibre = "org.maplibre.gl:android-sdk:11.13.1"
+maplibre = "org.maplibre.gl:android-sdk:11.13.5"
maplibre_ktx = "org.maplibre.gl:android-sdk-ktx-v7:3.0.2"
maplibre_annotation = "org.maplibre.gl:android-plugin-annotation-v9:3.0.2"
opusencoder = "io.element.android:opusencoder:1.2.0"
@@ -198,8 +205,8 @@ haze = { module = "dev.chrisbanes.haze:haze", version.ref = "haze" }
haze_materials = { module = "dev.chrisbanes.haze:haze-materials", version.ref = "haze" }
# Analytics
-posthog = "com.posthog:posthog-android:3.21.1"
-sentry = "io.sentry:sentry-android:8.21.0"
+posthog = "com.posthog:posthog-android:3.21.2"
+sentry = "io.sentry:sentry-android:8.22.0"
# main branch can be tested replacing the version with main-SNAPSHOT
matrix_analytics_events = "com.github.matrix-org:matrix-analytics-events:0.28.0"
@@ -212,7 +219,7 @@ inject = "javax.inject:javax.inject:1"
metro_runtime = { module = "dev.zacsweers.metro:runtime", version.ref = "metro" }
# Element Call
-element_call_embedded = "io.element.android:element-call-embedded:0.15.0"
+element_call_embedded = "io.element.android:element-call-embedded:0.16.0-rc.4"
# Auto services
google_autoservice = { module = "com.google.auto.service:auto-service", version.ref = "autoservice" }
@@ -234,7 +241,7 @@ metro = { id = "dev.zacsweers.metro", version.ref = "metro" }
detekt = { id = "io.gitlab.arturbosch.detekt", version.ref = "detekt" }
ktlint = "org.jlleitschuh.gradle.ktlint:13.1.0"
dependencygraph = "com.savvasdalkitsis.module-dependency-graph:0.12"
-dependencycheck = "org.owasp.dependencycheck:12.1.3"
+dependencycheck = "org.owasp.dependencycheck:12.1.5"
dependencyanalysis = { id = "com.autonomousapps.dependency-analysis", version.ref = "dependencyAnalysis" }
paparazzi = "app.cash.paparazzi:2.0.0-alpha02"
sqldelight = { id = "app.cash.sqldelight", version.ref = "sqldelight" }
diff --git a/libraries/androidutils/build.gradle.kts b/libraries/androidutils/build.gradle.kts
index d35fc0c4bd..ac1e317b48 100644
--- a/libraries/androidutils/build.gradle.kts
+++ b/libraries/androidutils/build.gradle.kts
@@ -1,4 +1,5 @@
import extension.setupDependencyInjection
+import extension.testCommonDependencies
/*
* Copyright 2023, 2024 New Vector Ltd.
@@ -33,12 +34,7 @@ dependencies {
implementation(libs.androidx.datastore.preferences)
api(libs.androidx.browser)
- testImplementation(projects.tests.testutils)
- testImplementation(libs.test.junit)
- testImplementation(libs.test.truth)
- testImplementation(libs.test.robolectric)
- testImplementation(libs.androidx.test.ext.junit)
+ testCommonDependencies(libs)
testImplementation(libs.coroutines.core)
- testImplementation(libs.coroutines.test)
testImplementation(projects.services.toolbox.test)
}
diff --git a/libraries/architecture/build.gradle.kts b/libraries/architecture/build.gradle.kts
index e481aff77a..55b79abca0 100644
--- a/libraries/architecture/build.gradle.kts
+++ b/libraries/architecture/build.gradle.kts
@@ -1,4 +1,5 @@
import extension.setupDependencyInjection
+import extension.testCommonDependencies
/*
* Copyright 2023, 2024 New Vector Ltd.
@@ -25,7 +26,5 @@ dependencies {
api(libs.androidx.lifecycle.runtime)
api(libs.molecule.runtime)
- testImplementation(libs.test.junit)
- testImplementation(libs.coroutines.test)
- testImplementation(libs.test.truth)
+ testCommonDependencies(libs)
}
diff --git a/libraries/architecture/src/main/kotlin/io/element/android/libraries/architecture/AssistedNodeFactory.kt b/libraries/architecture/src/main/kotlin/io/element/android/libraries/architecture/AssistedNodeFactory.kt
index 508038fb4c..d333eae1cd 100644
--- a/libraries/architecture/src/main/kotlin/io/element/android/libraries/architecture/AssistedNodeFactory.kt
+++ b/libraries/architecture/src/main/kotlin/io/element/android/libraries/architecture/AssistedNodeFactory.kt
@@ -11,6 +11,6 @@ import com.bumble.appyx.core.modality.BuildContext
import com.bumble.appyx.core.node.Node
import com.bumble.appyx.core.plugin.Plugin
-interface AssistedNodeFactory {
+fun interface AssistedNodeFactory {
fun create(buildContext: BuildContext, plugins: List): NODE
}
diff --git a/libraries/architecture/src/main/kotlin/io/element/android/libraries/architecture/FeatureEntryPoint.kt b/libraries/architecture/src/main/kotlin/io/element/android/libraries/architecture/FeatureEntryPoint.kt
index 2a64bb7c98..d5a932b705 100644
--- a/libraries/architecture/src/main/kotlin/io/element/android/libraries/architecture/FeatureEntryPoint.kt
+++ b/libraries/architecture/src/main/kotlin/io/element/android/libraries/architecture/FeatureEntryPoint.kt
@@ -18,6 +18,6 @@ interface FeatureEntryPoint
/**
* Can be used when the feature only exposes a simple node without the need of plugins.
*/
-interface SimpleFeatureEntryPoint : FeatureEntryPoint {
+fun interface SimpleFeatureEntryPoint : FeatureEntryPoint {
fun createNode(parentNode: Node, buildContext: BuildContext): Node
}
diff --git a/libraries/architecture/src/main/kotlin/io/element/android/libraries/architecture/NodeFactories.kt b/libraries/architecture/src/main/kotlin/io/element/android/libraries/architecture/NodeFactories.kt
index 4bddbc5541..63cb4c4ed9 100644
--- a/libraries/architecture/src/main/kotlin/io/element/android/libraries/architecture/NodeFactories.kt
+++ b/libraries/architecture/src/main/kotlin/io/element/android/libraries/architecture/NodeFactories.kt
@@ -7,7 +7,6 @@
package io.element.android.libraries.architecture
-import android.content.Context
import com.bumble.appyx.core.modality.BuildContext
import com.bumble.appyx.core.node.Node
import com.bumble.appyx.core.plugin.Plugin
@@ -22,17 +21,9 @@ inline fun Node.createNode(
return bindings.createNode(buildContext, plugins)
}
-inline fun Context.createNode(
- buildContext: BuildContext,
- plugins: List = emptyList()
-): N {
- val bindings: NodeFactoriesBindings = bindings()
- return bindings.createNode(buildContext, plugins)
-}
-
inline fun NodeFactoriesBindings.createNode(
buildContext: BuildContext,
- plugins: List = emptyList()
+ plugins: List,
): N {
val nodeClass = N::class
val nodeFactoryMap = nodeFactories()
@@ -46,8 +37,7 @@ inline fun NodeFactoriesBindings.createNode(
return node as N
}
-// @BindingContainer
-interface NodeFactoriesBindings {
+fun interface NodeFactoriesBindings {
@Multibinds
fun nodeFactories(): Map, AssistedNodeFactory<*>>
}
diff --git a/libraries/cryptography/impl/build.gradle.kts b/libraries/cryptography/impl/build.gradle.kts
index f15c070585..5e130b64e2 100644
--- a/libraries/cryptography/impl/build.gradle.kts
+++ b/libraries/cryptography/impl/build.gradle.kts
@@ -1,4 +1,5 @@
import extension.setupDependencyInjection
+import extension.testCommonDependencies
/*
* Copyright 2023, 2024 New Vector Ltd.
@@ -21,6 +22,5 @@ dependencies {
implementation(projects.libraries.di)
api(projects.libraries.cryptography.api)
- testImplementation(libs.test.junit)
- testImplementation(libs.test.truth)
+ testCommonDependencies(libs)
}
diff --git a/libraries/dateformatter/api/build.gradle.kts b/libraries/dateformatter/api/build.gradle.kts
index 88fd41f039..cebb9d4049 100644
--- a/libraries/dateformatter/api/build.gradle.kts
+++ b/libraries/dateformatter/api/build.gradle.kts
@@ -1,3 +1,5 @@
+import extension.testCommonDependencies
+
/*
* Copyright 2022-2024 New Vector Ltd.
*
@@ -13,7 +15,6 @@ android {
namespace = "io.element.android.libraries.dateformatter.api"
dependencies {
- testImplementation(libs.test.junit)
- testImplementation(libs.test.truth)
+ testCommonDependencies(libs)
}
}
diff --git a/libraries/dateformatter/impl/build.gradle.kts b/libraries/dateformatter/impl/build.gradle.kts
index 69e311ac8e..72da2f81f6 100644
--- a/libraries/dateformatter/impl/build.gradle.kts
+++ b/libraries/dateformatter/impl/build.gradle.kts
@@ -1,4 +1,5 @@
import extension.setupDependencyInjection
+import extension.testCommonDependencies
/*
* Copyright 2022-2024 New Vector Ltd.
@@ -40,13 +41,8 @@ android {
api(projects.libraries.dateformatter.api)
api(libs.datetime)
- testImplementation(libs.test.junit)
- testImplementation(libs.test.truth)
- testImplementation(libs.test.turbine)
- testImplementation(libs.test.robolectric)
+ testCommonDependencies(libs, true)
testImplementation(projects.libraries.dateformatter.test)
testImplementation(projects.services.toolbox.test)
- testImplementation(projects.tests.testutils)
- testImplementation(libs.androidx.compose.ui.test.junit)
}
}
diff --git a/libraries/deeplink/api/src/main/kotlin/io/element/android/libraries/deeplink/api/usecase/InviteFriendsUseCase.kt b/libraries/deeplink/api/src/main/kotlin/io/element/android/libraries/deeplink/api/usecase/InviteFriendsUseCase.kt
index 5c5bcf5043..7c8910e156 100644
--- a/libraries/deeplink/api/src/main/kotlin/io/element/android/libraries/deeplink/api/usecase/InviteFriendsUseCase.kt
+++ b/libraries/deeplink/api/src/main/kotlin/io/element/android/libraries/deeplink/api/usecase/InviteFriendsUseCase.kt
@@ -9,6 +9,6 @@ package io.element.android.libraries.deeplink.api.usecase
import android.app.Activity
-interface InviteFriendsUseCase {
+fun interface InviteFriendsUseCase {
fun execute(activity: Activity)
}
diff --git a/libraries/deeplink/impl/build.gradle.kts b/libraries/deeplink/impl/build.gradle.kts
index 8c652037c5..074e144b3a 100644
--- a/libraries/deeplink/impl/build.gradle.kts
+++ b/libraries/deeplink/impl/build.gradle.kts
@@ -1,4 +1,5 @@
import extension.setupDependencyInjection
+import extension.testCommonDependencies
/*
* Copyright 2022-2024 New Vector Ltd.
@@ -28,9 +29,6 @@ dependencies {
implementation(projects.libraries.uiStrings)
implementation(projects.services.toolbox.api)
- testImplementation(libs.test.junit)
- testImplementation(libs.test.truth)
- testImplementation(libs.test.robolectric)
+ testCommonDependencies(libs)
testImplementation(projects.libraries.matrix.test)
- testImplementation(projects.tests.testutils)
}
diff --git a/libraries/designsystem/build.gradle.kts b/libraries/designsystem/build.gradle.kts
index 0d1efa1ed1..c2eec20b8c 100644
--- a/libraries/designsystem/build.gradle.kts
+++ b/libraries/designsystem/build.gradle.kts
@@ -1,3 +1,5 @@
+import extension.testCommonDependencies
+
/*
* Copyright 2022-2024 New Vector Ltd.
*
@@ -42,10 +44,6 @@ android {
ksp(libs.showkase.processor)
implementation(libs.showkase)
- testImplementation(libs.test.junit)
- testImplementation(libs.coroutines.test)
- testImplementation(libs.molecule.runtime)
- testImplementation(libs.test.truth)
- testImplementation(libs.test.turbine)
+ testCommonDependencies(libs)
}
}
diff --git a/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/atomic/atoms/RoomPreviewDescriptionAtom.kt b/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/atomic/atoms/RoomPreviewDescriptionAtom.kt
index 8ca1a01e6b..3aece9889e 100644
--- a/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/atomic/atoms/RoomPreviewDescriptionAtom.kt
+++ b/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/atomic/atoms/RoomPreviewDescriptionAtom.kt
@@ -15,14 +15,18 @@ import io.element.android.compound.theme.ElementTheme
import io.element.android.libraries.designsystem.theme.components.Text
@Composable
-fun RoomPreviewDescriptionAtom(description: String, modifier: Modifier = Modifier) {
+fun RoomPreviewDescriptionAtom(
+ description: String,
+ modifier: Modifier = Modifier,
+ maxLines: Int = Int.MAX_VALUE,
+) {
Text(
modifier = modifier,
text = description,
- style = ElementTheme.typography.fontBodySmRegular,
+ style = ElementTheme.typography.fontBodyMdRegular,
textAlign = TextAlign.Center,
- color = ElementTheme.colors.textSecondary,
- maxLines = 3,
+ color = ElementTheme.colors.textPrimary,
+ maxLines = maxLines,
overflow = TextOverflow.Ellipsis,
)
}
diff --git a/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/atomic/atoms/RoomPreviewSubtitleAtom.kt b/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/atomic/atoms/RoomPreviewSubtitleAtom.kt
index ae705e6bfb..4fe52f5443 100644
--- a/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/atomic/atoms/RoomPreviewSubtitleAtom.kt
+++ b/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/atomic/atoms/RoomPreviewSubtitleAtom.kt
@@ -18,7 +18,7 @@ fun RoomPreviewSubtitleAtom(subtitle: String, modifier: Modifier = Modifier) {
Text(
modifier = modifier,
text = subtitle,
- style = ElementTheme.typography.fontBodyMdRegular,
+ style = ElementTheme.typography.fontBodyLgRegular,
textAlign = TextAlign.Center,
color = ElementTheme.colors.textSecondary,
)
diff --git a/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/atomic/atoms/RoomPreviewTitleAtom.kt b/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/atomic/atoms/RoomPreviewTitleAtom.kt
index 2ede537931..2c77dc8461 100644
--- a/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/atomic/atoms/RoomPreviewTitleAtom.kt
+++ b/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/atomic/atoms/RoomPreviewTitleAtom.kt
@@ -23,7 +23,7 @@ fun RoomPreviewTitleAtom(
Text(
modifier = modifier,
text = title,
- style = ElementTheme.typography.fontHeadingMdBold,
+ style = ElementTheme.typography.fontHeadingLgBold,
textAlign = TextAlign.Center,
fontStyle = fontStyle,
color = ElementTheme.colors.textPrimary,
diff --git a/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/atomic/organisms/RoomPreviewOrganism.kt b/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/atomic/organisms/RoomPreviewOrganism.kt
index 511eb298ea..dac9f00a7c 100644
--- a/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/atomic/organisms/RoomPreviewOrganism.kt
+++ b/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/atomic/organisms/RoomPreviewOrganism.kt
@@ -34,14 +34,13 @@ fun RoomPreviewOrganism(
title()
Spacer(modifier = Modifier.height(8.dp))
subtitle()
- Spacer(modifier = Modifier.height(8.dp))
if (memberCount != null) {
+ Spacer(modifier = Modifier.height(8.dp))
memberCount()
}
- Spacer(modifier = Modifier.height(8.dp))
if (description != null) {
+ Spacer(modifier = Modifier.height(16.dp))
description()
}
- Spacer(modifier = Modifier.height(24.dp))
}
}
diff --git a/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/components/ProgressDialog.kt b/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/components/ProgressDialog.kt
index f5d8a50ce0..fe18daaaea 100644
--- a/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/components/ProgressDialog.kt
+++ b/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/components/ProgressDialog.kt
@@ -38,6 +38,18 @@ import io.element.android.libraries.designsystem.theme.components.TextButton
import io.element.android.libraries.ui.strings.CommonStrings
import timber.log.Timber
+/**
+ * A progress dialog, with a spinner, and optional text content.
+ *
+ * @param modifier
+ * @param text Optional text to show under the spinner.
+ * @param type
+ * @param properties
+ * @param showCancelButton
+ * @param onDismissRequest
+ * @param content Optional additional content to show under the spinner, and above the cancel button (if shown). If both `text` and `content` are supplied,
+ * `text` is shown above `content`.
+ */
@Composable
fun ProgressDialog(
modifier: Modifier = Modifier,
@@ -46,6 +58,7 @@ fun ProgressDialog(
properties: DialogProperties = DialogProperties(dismissOnBackPress = false, dismissOnClickOutside = false),
showCancelButton: Boolean = false,
onDismissRequest: () -> Unit = {},
+ content: @Composable () -> Unit = {},
) {
DisposableEffect(Unit) {
onDispose {
@@ -75,7 +88,8 @@ fun ProgressDialog(
)
}
}
- }
+ },
+ content,
)
}
}
@@ -96,7 +110,8 @@ private fun ProgressDialogContent(
CircularProgressIndicator(
color = ElementTheme.colors.iconPrimary
)
- }
+ },
+ content: @Composable () -> Unit,
) {
Box(
contentAlignment = Alignment.Center,
@@ -118,6 +133,7 @@ private fun ProgressDialogContent(
color = ElementTheme.colors.textPrimary,
)
}
+ content()
if (showCancelButton) {
Spacer(modifier = Modifier.height(24.dp))
Box(
@@ -138,7 +154,7 @@ private fun ProgressDialogContent(
@Composable
internal fun ProgressDialogContentPreview() = ElementThemedPreview {
DialogPreview {
- ProgressDialogContent(text = "test dialog content", showCancelButton = true)
+ ProgressDialogContent(text = "test dialog content", showCancelButton = true, content = {})
}
}
@@ -147,3 +163,34 @@ internal fun ProgressDialogContentPreview() = ElementThemedPreview {
internal fun ProgressDialogPreview() = ElementPreview {
ProgressDialog(text = "test dialog content", showCancelButton = true)
}
+
+@PreviewsDayNight
+@Composable
+internal fun ProgressDialogWithContentPreview() = ElementPreview {
+ ProgressDialog(showCancelButton = true) {
+ Spacer(modifier = Modifier.height(8.dp))
+ Text(
+ text = "Heading",
+ color = ElementTheme.colors.textPrimary,
+ style = ElementTheme.typography.fontHeadingSmMedium,
+ )
+ Spacer(modifier = Modifier.height(16.dp))
+ Text(
+ text = "Subtext",
+ color = ElementTheme.colors.textSecondary,
+ style = MaterialTheme.typography.bodyMedium,
+ )
+ }
+}
+
+@PreviewsDayNight
+@Composable
+internal fun ProgressDialogWithTextAndContentPreview() = ElementPreview {
+ ProgressDialog(text = "Text Content") {
+ Text(
+ text = "blah blah",
+ color = ElementTheme.colors.textPrimary,
+ style = ElementTheme.typography.fontHeadingSmMedium,
+ )
+ }
+}
diff --git a/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/components/avatar/AvatarSize.kt b/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/components/avatar/AvatarSize.kt
index 9e9ebb6181..72cf62c76a 100644
--- a/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/components/avatar/AvatarSize.kt
+++ b/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/components/avatar/AvatarSize.kt
@@ -14,7 +14,7 @@ enum class AvatarSize(val dp: Dp) {
CurrentUserTopBar(32.dp),
IncomingCall(140.dp),
- RoomHeader(96.dp),
+ RoomDetailsHeader(96.dp),
RoomListItem(52.dp),
SpaceListItem(52.dp),
@@ -34,6 +34,7 @@ enum class AvatarSize(val dp: Dp) {
TimelineRoom(32.dp),
TimelineSender(32.dp),
TimelineReadReceipt(16.dp),
+ TimelineThreadLatestEventSender(24.dp),
ComposerAlert(32.dp),
@@ -68,5 +69,7 @@ enum class AvatarSize(val dp: Dp) {
OrganizationHeader(64.dp),
SpaceHeader(64.dp),
+ RoomPreviewHeader(64.dp),
+ RoomPreviewInviter(56.dp),
SpaceMember(24.dp),
}
diff --git a/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/theme/components/AlertDialogContent.kt b/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/theme/components/AlertDialogContent.kt
index 51fe275ee1..7811c26c4a 100644
--- a/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/theme/components/AlertDialogContent.kt
+++ b/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/theme/components/AlertDialogContent.kt
@@ -142,7 +142,7 @@ internal fun SimpleAlertDialogContent(
Text(
text = titleText,
style = ElementTheme.typography.fontHeadingSmMedium,
- textAlign = TextAlign.Center,
+ textAlign = if (icon != null) TextAlign.Center else TextAlign.Start,
)
}
},
@@ -510,3 +510,43 @@ internal fun DialogWithThirdButtonPreview() {
}
}
}
+
+@Preview(group = PreviewGroup.Dialogs, name = "Dialog with a very long title")
+@Composable
+@Suppress("MaxLineLength")
+internal fun DialogWithVeryLongTitlePreview() {
+ ElementThemedPreview(showBackground = false) {
+ DialogPreview {
+ SimpleAlertDialogContent(
+ title = "Dialog Title that takes more than one line",
+ content = "A dialog is a type of modal window that appears in front of app content to provide critical information," +
+ " or prompt for a decision to be made. Learn more",
+ submitText = "OK",
+ onSubmitClick = {},
+ )
+ }
+ }
+}
+
+@Preview(group = PreviewGroup.Dialogs, name = "Dialog with a very long title and icon")
+@Composable
+@Suppress("MaxLineLength")
+internal fun DialogWithVeryLongTitleAndIconPreview() {
+ ElementThemedPreview(showBackground = false) {
+ DialogPreview {
+ SimpleAlertDialogContent(
+ icon = {
+ Icon(
+ imageVector = CompoundIcons.NotificationsSolid(),
+ contentDescription = null
+ )
+ },
+ title = "Dialog Title that takes more than one line",
+ content = "A dialog is a type of modal window that appears in front of app content to provide critical information," +
+ " or prompt for a decision to be made. Learn more",
+ submitText = "OK",
+ onSubmitClick = {},
+ )
+ }
+ }
+}
diff --git a/libraries/eventformatter/api/src/main/kotlin/io/element/android/libraries/eventformatter/api/TimelineEventFormatter.kt b/libraries/eventformatter/api/src/main/kotlin/io/element/android/libraries/eventformatter/api/TimelineEventFormatter.kt
index c22ae6eb13..71920f3c4e 100644
--- a/libraries/eventformatter/api/src/main/kotlin/io/element/android/libraries/eventformatter/api/TimelineEventFormatter.kt
+++ b/libraries/eventformatter/api/src/main/kotlin/io/element/android/libraries/eventformatter/api/TimelineEventFormatter.kt
@@ -7,8 +7,19 @@
package io.element.android.libraries.eventformatter.api
+import io.element.android.libraries.matrix.api.core.UserId
+import io.element.android.libraries.matrix.api.timeline.item.event.EventContent
import io.element.android.libraries.matrix.api.timeline.item.event.EventTimelineItem
+import io.element.android.libraries.matrix.api.timeline.item.event.getDisambiguatedDisplayName
interface TimelineEventFormatter {
- fun format(event: EventTimelineItem): CharSequence?
+ fun format(event: EventTimelineItem): CharSequence? {
+ return format(
+ content = event.content,
+ isOutgoing = event.isOwn,
+ sender = event.sender,
+ senderDisambiguatedDisplayName = event.senderProfile.getDisambiguatedDisplayName(event.sender),
+ )
+ }
+ fun format(content: EventContent, isOutgoing: Boolean, sender: UserId, senderDisambiguatedDisplayName: String): CharSequence?
}
diff --git a/libraries/eventformatter/impl/build.gradle.kts b/libraries/eventformatter/impl/build.gradle.kts
index 2f97cab31b..3b726da654 100644
--- a/libraries/eventformatter/impl/build.gradle.kts
+++ b/libraries/eventformatter/impl/build.gradle.kts
@@ -1,4 +1,5 @@
import extension.setupDependencyInjection
+import extension.testCommonDependencies
/*
* Copyright 2023, 2024 New Vector Ltd.
@@ -32,9 +33,7 @@ dependencies {
implementation(projects.services.toolbox.api)
api(projects.libraries.eventformatter.api)
+ testCommonDependencies(libs)
testImplementation(projects.services.toolbox.impl)
- testImplementation(libs.test.junit)
- testImplementation(libs.test.robolectric)
- testImplementation(libs.test.truth)
testImplementation(projects.libraries.matrix.test)
}
diff --git a/libraries/eventformatter/impl/src/main/kotlin/io/element/android/libraries/eventformatter/impl/DefaultTimelineEventFormatter.kt b/libraries/eventformatter/impl/src/main/kotlin/io/element/android/libraries/eventformatter/impl/DefaultTimelineEventFormatter.kt
index ba12d03d9c..6cbe734733 100644
--- a/libraries/eventformatter/impl/src/main/kotlin/io/element/android/libraries/eventformatter/impl/DefaultTimelineEventFormatter.kt
+++ b/libraries/eventformatter/impl/src/main/kotlin/io/element/android/libraries/eventformatter/impl/DefaultTimelineEventFormatter.kt
@@ -13,7 +13,9 @@ import io.element.android.libraries.core.meta.BuildMeta
import io.element.android.libraries.di.SessionScope
import io.element.android.libraries.eventformatter.api.TimelineEventFormatter
import io.element.android.libraries.eventformatter.impl.mode.RenderingMode
+import io.element.android.libraries.matrix.api.core.UserId
import io.element.android.libraries.matrix.api.timeline.item.event.CallNotifyContent
+import io.element.android.libraries.matrix.api.timeline.item.event.EventContent
import io.element.android.libraries.matrix.api.timeline.item.event.EventTimelineItem
import io.element.android.libraries.matrix.api.timeline.item.event.FailedToParseMessageLikeContent
import io.element.android.libraries.matrix.api.timeline.item.event.FailedToParseStateContent
@@ -43,12 +45,16 @@ class DefaultTimelineEventFormatter(
override fun format(event: EventTimelineItem): CharSequence? {
val isOutgoing = event.isOwn
val senderDisambiguatedDisplayName = event.senderProfile.getDisambiguatedDisplayName(event.sender)
- return when (val content = event.content) {
+ return format(event.content, isOutgoing, event.sender, senderDisambiguatedDisplayName)
+ }
+
+ override fun format(content: EventContent, isOutgoing: Boolean, sender: UserId, senderDisambiguatedDisplayName: String): CharSequence? {
+ return when (content) {
is RoomMembershipContent -> {
roomMembershipContentFormatter.format(content, senderDisambiguatedDisplayName, isOutgoing)
}
is ProfileChangeContent -> {
- profileChangeContentFormatter.format(content, event.sender, senderDisambiguatedDisplayName, isOutgoing)
+ profileChangeContentFormatter.format(content, sender, senderDisambiguatedDisplayName, isOutgoing)
}
is StateContent -> {
stateContentFormatter.format(content, senderDisambiguatedDisplayName, isOutgoing, RenderingMode.Timeline)
@@ -66,7 +72,7 @@ class DefaultTimelineEventFormatter(
is FailedToParseStateContent,
is UnknownContent -> {
if (buildMeta.isDebuggable) {
- error("You should not use this formatter for this event: $event")
+ error("You should not use this formatter for this event content: $content")
}
sp.getString(CommonStrings.common_unsupported_event)
}
diff --git a/libraries/eventformatter/impl/src/test/kotlin/io/element/android/libraries/eventformatter/impl/DefaultBaseRoomLastMessageFormatterTest.kt b/libraries/eventformatter/impl/src/test/kotlin/io/element/android/libraries/eventformatter/impl/DefaultBaseRoomLastMessageFormatterTest.kt
index ee56fcf2c5..8fb4ac0bf4 100644
--- a/libraries/eventformatter/impl/src/test/kotlin/io/element/android/libraries/eventformatter/impl/DefaultBaseRoomLastMessageFormatterTest.kt
+++ b/libraries/eventformatter/impl/src/test/kotlin/io/element/android/libraries/eventformatter/impl/DefaultBaseRoomLastMessageFormatterTest.kt
@@ -14,7 +14,6 @@ import com.google.common.truth.Truth.assertWithMessage
import io.element.android.libraries.matrix.api.core.UserId
import io.element.android.libraries.matrix.api.media.ImageInfo
import io.element.android.libraries.matrix.api.media.MediaSource
-import io.element.android.libraries.matrix.api.timeline.item.EventThreadInfo
import io.element.android.libraries.matrix.api.timeline.item.event.AudioMessageType
import io.element.android.libraries.matrix.api.timeline.item.event.EmoteMessageType
import io.element.android.libraries.matrix.api.timeline.item.event.EventContent
@@ -102,7 +101,7 @@ class DefaultBaseRoomLastMessageFormatterTest {
val info = ImageInfo(null, null, null, null, null, null, null)
val message = createRoomEvent(false, null, aStickerContent(body, info, aMediaSource(url = "url")))
val result = formatter.format(message, false)
- val expectedBody = someoneElseId.toString() + ": Sticker (a sticker body)"
+ val expectedBody = someoneElseId.value + ": Sticker (a sticker body)"
assertThat(result.toString()).isEqualTo(expectedBody)
}
@@ -175,7 +174,7 @@ class DefaultBaseRoomLastMessageFormatterTest {
) {
val body = "Shared body"
fun createMessageContent(type: MessageType): MessageContent {
- return MessageContent(body, null, false, EventThreadInfo(null, null), type)
+ return MessageContent(body, null, false, null, type)
}
val sharedContentMessagesTypes = arrayOf(
diff --git a/libraries/eventformatter/impl/src/test/kotlin/io/element/android/libraries/eventformatter/impl/DefaultPinnedMessagesBannerFormatterTest.kt b/libraries/eventformatter/impl/src/test/kotlin/io/element/android/libraries/eventformatter/impl/DefaultPinnedMessagesBannerFormatterTest.kt
index 349cd2585f..442357f386 100644
--- a/libraries/eventformatter/impl/src/test/kotlin/io/element/android/libraries/eventformatter/impl/DefaultPinnedMessagesBannerFormatterTest.kt
+++ b/libraries/eventformatter/impl/src/test/kotlin/io/element/android/libraries/eventformatter/impl/DefaultPinnedMessagesBannerFormatterTest.kt
@@ -14,7 +14,6 @@ import com.google.common.truth.Truth.assertWithMessage
import io.element.android.libraries.matrix.api.core.UserId
import io.element.android.libraries.matrix.api.media.ImageInfo
import io.element.android.libraries.matrix.api.media.MediaSource
-import io.element.android.libraries.matrix.api.timeline.item.EventThreadInfo
import io.element.android.libraries.matrix.api.timeline.item.event.AudioMessageType
import io.element.android.libraries.matrix.api.timeline.item.event.EmoteMessageType
import io.element.android.libraries.matrix.api.timeline.item.event.EventContent
@@ -130,7 +129,7 @@ class DefaultPinnedMessagesBannerFormatterTest {
fun `Message contents`() {
val body = "Shared body"
fun createMessageContent(type: MessageType): MessageContent {
- return MessageContent(body, null, false, EventThreadInfo(null, null), type)
+ return MessageContent(body, null, false, null, type)
}
val sharedContentMessagesTypes = arrayOf(
diff --git a/libraries/featureflag/impl/build.gradle.kts b/libraries/featureflag/impl/build.gradle.kts
index 5886e01c94..c54f95a293 100644
--- a/libraries/featureflag/impl/build.gradle.kts
+++ b/libraries/featureflag/impl/build.gradle.kts
@@ -1,4 +1,5 @@
import extension.setupDependencyInjection
+import extension.testCommonDependencies
/*
* Copyright 2023, 2024 New Vector Ltd.
@@ -27,9 +28,7 @@ dependencies {
implementation(projects.libraries.core)
implementation(projects.libraries.preferences.api)
implementation(libs.coroutines.core)
- testImplementation(libs.test.junit)
- testImplementation(libs.coroutines.test)
- testImplementation(libs.test.truth)
- testImplementation(libs.test.turbine)
+
+ testCommonDependencies(libs)
testImplementation(projects.libraries.matrix.test)
}
diff --git a/libraries/fullscreenintent/impl/build.gradle.kts b/libraries/fullscreenintent/impl/build.gradle.kts
index 40a65d48e8..2ccb7f80b8 100644
--- a/libraries/fullscreenintent/impl/build.gradle.kts
+++ b/libraries/fullscreenintent/impl/build.gradle.kts
@@ -1,4 +1,5 @@
import extension.setupDependencyInjection
+import extension.testCommonDependencies
/*
* Copyright 2024 New Vector Ltd.
@@ -27,19 +28,10 @@ dependencies {
implementation(projects.services.toolbox.api)
implementation(libs.androidx.datastore.preferences)
- testImplementation(libs.test.junit)
- testImplementation(libs.coroutines.test)
- testImplementation(libs.molecule.runtime)
- testImplementation(libs.test.truth)
- testImplementation(libs.test.turbine)
- testImplementation(projects.tests.testutils)
+ testCommonDependencies(libs, true)
testImplementation(projects.libraries.matrix.test)
testImplementation(projects.libraries.permissions.test)
testImplementation(projects.libraries.preferences.test)
testImplementation(projects.libraries.testtags)
- testImplementation(libs.test.robolectric)
- testImplementation(libs.test.mockk)
- testImplementation(libs.androidx.compose.ui.test.junit)
testImplementation(projects.services.toolbox.test)
- testReleaseImplementation(libs.androidx.compose.ui.test.manifest)
}
diff --git a/libraries/indicator/impl/build.gradle.kts b/libraries/indicator/impl/build.gradle.kts
index 9a75cbee26..2596b9fe67 100644
--- a/libraries/indicator/impl/build.gradle.kts
+++ b/libraries/indicator/impl/build.gradle.kts
@@ -1,4 +1,5 @@
import extension.setupDependencyInjection
+import extension.testCommonDependencies
/*
* Copyright 2022-2024 New Vector Ltd.
@@ -26,11 +27,7 @@ dependencies {
api(projects.libraries.indicator.api)
+ testCommonDependencies(libs)
testImplementation(projects.libraries.featureflag.test)
testImplementation(projects.libraries.matrix.test)
- testImplementation(libs.test.junit)
- testImplementation(libs.coroutines.test)
- testImplementation(libs.molecule.runtime)
- testImplementation(libs.test.turbine)
- testImplementation(libs.test.truth)
}
diff --git a/libraries/matrix/api/build.gradle.kts b/libraries/matrix/api/build.gradle.kts
index 272527dc9f..04a45654b2 100644
--- a/libraries/matrix/api/build.gradle.kts
+++ b/libraries/matrix/api/build.gradle.kts
@@ -1,6 +1,7 @@
import config.BuildTimeConfig
import extension.buildConfigFieldStr
import extension.setupDependencyInjection
+import extension.testCommonDependencies
/*
* Copyright 2022-2024 New Vector Ltd.
@@ -54,7 +55,6 @@ dependencies {
implementation(libs.coroutines.core)
api(projects.libraries.architecture)
- testImplementation(libs.test.junit)
- testImplementation(libs.test.truth)
+ testCommonDependencies(libs)
testImplementation(projects.libraries.matrix.test)
}
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 bc7ec21152..db4439332b 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
@@ -156,11 +156,6 @@ interface MatrixClient {
*/
suspend fun currentSlidingSyncVersion(): Result
- /**
- * Returns the available sliding sync versions for the current user.
- */
- suspend fun availableSlidingSyncVersions(): Result>
-
fun canDeactivateAccount(): Boolean
suspend fun deactivateAccount(password: String, eraseData: Boolean): Result
diff --git a/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/auth/MatrixAuthenticationService.kt b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/auth/MatrixAuthenticationService.kt
index d1c47ae663..38777944ee 100644
--- a/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/auth/MatrixAuthenticationService.kt
+++ b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/auth/MatrixAuthenticationService.kt
@@ -13,14 +13,9 @@ import io.element.android.libraries.matrix.api.auth.external.ExternalSession
import io.element.android.libraries.matrix.api.auth.qrlogin.MatrixQrCodeLoginData
import io.element.android.libraries.matrix.api.auth.qrlogin.QrCodeLoginStep
import io.element.android.libraries.matrix.api.core.SessionId
-import io.element.android.libraries.sessionstorage.api.LoggedInState
-import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.StateFlow
interface MatrixAuthenticationService {
- fun loggedInStateFlow(): Flow
- suspend fun getLatestSessionId(): SessionId?
-
/**
* Restore a session from a [sessionId].
* Do not restore anything it the access token is not valid anymore.
diff --git a/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/core/MatrixPatterns.kt b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/core/MatrixPatterns.kt
index a44e00b664..26a030d361 100644
--- a/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/core/MatrixPatterns.kt
+++ b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/core/MatrixPatterns.kt
@@ -151,7 +151,7 @@ object MatrixPatterns {
val urlMatch = match.groupValues[1]
when (val permalink = permalinkParser.parse(urlMatch)) {
is PermalinkData.UserLink -> {
- add(MatrixPatternResult(MatrixPatternType.USER_ID, permalink.userId.toString(), match.range.first, match.range.last + 1))
+ add(MatrixPatternResult(MatrixPatternType.USER_ID, permalink.userId.value, match.range.first, match.range.last + 1))
}
is PermalinkData.RoomLink -> {
when (permalink.roomIdOrAlias) {
diff --git a/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/core/RoomId.kt b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/core/RoomId.kt
index 1fab64020d..8d339ae704 100644
--- a/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/core/RoomId.kt
+++ b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/core/RoomId.kt
@@ -20,5 +20,3 @@ value class RoomId(val value: String) : Serializable {
override fun toString(): String = value
}
-
-fun RoomId.toSpaceId(): SpaceId = SpaceId(this.value)
diff --git a/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/notification/NotificationData.kt b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/notification/NotificationData.kt
index 338193ed44..1a58ced0fd 100644
--- a/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/notification/NotificationData.kt
+++ b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/notification/NotificationData.kt
@@ -49,9 +49,10 @@ sealed interface NotificationContent {
val senderId: UserId,
) : MessageLike
- data class CallNotify(
+ data class RtcNotification(
val senderId: UserId,
- val type: CallNotifyType,
+ val type: RtcNotificationType,
+ val expirationTimestampMillis: Long
) : MessageLike
data object CallHangup : MessageLike
@@ -118,7 +119,7 @@ sealed interface NotificationContent {
) : NotificationContent
}
-enum class CallNotifyType {
+enum class RtcNotificationType {
RING,
NOTIFY
}
diff --git a/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/room/BaseRoom.kt b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/room/BaseRoom.kt
index 7e902a66fa..84aae82b66 100644
--- a/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/room/BaseRoom.kt
+++ b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/room/BaseRoom.kt
@@ -18,6 +18,7 @@ import io.element.android.libraries.matrix.api.room.tombstone.PredecessorRoom
import io.element.android.libraries.matrix.api.roomdirectory.RoomVisibility
import io.element.android.libraries.matrix.api.timeline.ReceiptType
import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.StateFlow
import java.io.Closeable
@@ -239,7 +240,11 @@ interface BaseRoom : Closeable {
*/
suspend fun reportRoom(reason: String?): Result
- /**
+ suspend fun declineCall(notificationEventId: EventId): Result
+
+ suspend fun subscribeToCallDecline(notificationEventId: EventId): Flow
+
+ /**
* Destroy the room and release all resources associated to it.
*/
fun destroy()
diff --git a/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/room/MessageEventType.kt b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/room/MessageEventType.kt
index ce98ecfe6b..5d20840cf7 100644
--- a/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/room/MessageEventType.kt
+++ b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/room/MessageEventType.kt
@@ -12,7 +12,7 @@ enum class MessageEventType {
CALL_INVITE,
CALL_HANGUP,
CALL_CANDIDATES,
- CALL_NOTIFY,
+ RTC_NOTIFICATION,
KEY_VERIFICATION_READY,
KEY_VERIFICATION_START,
KEY_VERIFICATION_CANCEL,
diff --git a/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/room/RoomMember.kt b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/room/RoomMember.kt
index c2db1e9ec5..f1b1104a27 100644
--- a/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/room/RoomMember.kt
+++ b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/room/RoomMember.kt
@@ -17,7 +17,6 @@ data class RoomMember(
val membership: RoomMembershipState,
val isNameAmbiguous: Boolean,
val powerLevel: Long,
- val normalizedPowerLevel: Long,
val isIgnored: Boolean,
val role: Role,
val membershipChangeReason: String?,
diff --git a/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/spaces/SpaceRoom.kt b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/spaces/SpaceRoom.kt
index ce697089c7..d4e1d57826 100644
--- a/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/spaces/SpaceRoom.kt
+++ b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/spaces/SpaceRoom.kt
@@ -8,7 +8,7 @@
package io.element.android.libraries.matrix.api.spaces
import io.element.android.libraries.matrix.api.core.RoomAlias
-import io.element.android.libraries.matrix.api.core.SpaceId
+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.RoomType
import io.element.android.libraries.matrix.api.room.join.JoinRule
@@ -23,9 +23,11 @@ data class SpaceRoom(
val heroes: List,
val joinRule: JoinRule?,
val numJoinedMembers: Int,
- val spaceId: SpaceId,
+ val roomId: RoomId,
val roomType: RoomType,
val state: CurrentUserMembership?,
val topic: String?,
val worldReadable: Boolean,
-)
+) {
+ val isSpace = roomType == RoomType.Space
+}
diff --git a/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/spaces/SpaceRoomList.kt b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/spaces/SpaceRoomList.kt
new file mode 100644
index 0000000000..e55e1b87bd
--- /dev/null
+++ b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/spaces/SpaceRoomList.kt
@@ -0,0 +1,25 @@
+/*
+ * Copyright 2025 New Vector Ltd.
+ *
+ * SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial
+ * Please see LICENSE files in the repository root for full details.
+ */
+
+package io.element.android.libraries.matrix.api.spaces
+
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.StateFlow
+import java.util.Optional
+
+interface SpaceRoomList {
+ sealed interface PaginationStatus {
+ data object Loading : PaginationStatus
+ data class Idle(val hasMoreToLoad: Boolean) : PaginationStatus
+ }
+
+ fun currentSpaceFlow(): StateFlow>
+
+ val spaceRoomsFlow: Flow>
+ val paginationStatusFlow: StateFlow
+ suspend fun paginate(): Result
+}
diff --git a/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/spaces/SpaceService.kt b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/spaces/SpaceService.kt
index 58494502f7..b4572ad0bb 100644
--- a/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/spaces/SpaceService.kt
+++ b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/spaces/SpaceService.kt
@@ -7,9 +7,12 @@
package io.element.android.libraries.matrix.api.spaces
+import io.element.android.libraries.matrix.api.core.RoomId
import kotlinx.coroutines.flow.SharedFlow
interface SpaceService {
- val spaceRooms: SharedFlow>
+ val spaceRoomsFlow: SharedFlow>
suspend fun joinedSpaces(): Result>
+
+ fun spaceRoomList(id: RoomId): SpaceRoomList
}
diff --git a/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/timeline/Timeline.kt b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/timeline/Timeline.kt
index 4eceeac4da..f8f5793368 100644
--- a/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/timeline/Timeline.kt
+++ b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/timeline/Timeline.kt
@@ -151,7 +151,7 @@ interface Timeline : AutoCloseable {
suspend fun redactEvent(eventOrTransactionId: EventOrTransactionId, reason: String?): Result
- suspend fun toggleReaction(emoji: String, eventOrTransactionId: EventOrTransactionId): Result
+ suspend fun toggleReaction(emoji: String, eventOrTransactionId: EventOrTransactionId): Result
suspend fun forwardEvent(eventId: EventId, roomIds: List): Result
diff --git a/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/timeline/item/ThreadSummary.kt b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/timeline/item/ThreadSummary.kt
index 4960330448..c34e4c9ac3 100644
--- a/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/timeline/item/ThreadSummary.kt
+++ b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/timeline/item/ThreadSummary.kt
@@ -14,10 +14,10 @@ import io.element.android.libraries.matrix.api.timeline.item.event.EventContent
import io.element.android.libraries.matrix.api.timeline.item.event.EventOrTransactionId
import io.element.android.libraries.matrix.api.timeline.item.event.ProfileTimelineDetails
-data class EventThreadInfo(
- val threadRootId: ThreadId?,
- val threadSummary: ThreadSummary?,
-)
+sealed interface EventThreadInfo {
+ data class ThreadRoot(val summary: ThreadSummary) : EventThreadInfo
+ data class ThreadResponse(val threadRootId: ThreadId) : EventThreadInfo
+}
data class ThreadSummary(
val latestEvent: AsyncData,
diff --git a/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/timeline/item/event/EventContent.kt b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/timeline/item/event/EventContent.kt
index a6bea83565..5fefe8ae31 100644
--- a/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/timeline/item/event/EventContent.kt
+++ b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/timeline/item/event/EventContent.kt
@@ -24,7 +24,7 @@ data class MessageContent(
val body: String,
val inReplyTo: InReplyTo?,
val isEdited: Boolean,
- val threadInfo: EventThreadInfo,
+ val threadInfo: EventThreadInfo?,
val type: MessageType
) : EventContent
diff --git a/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/timeline/item/event/EventType.kt b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/timeline/item/event/EventType.kt
index 41d0dc7483..d6b354376c 100644
--- a/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/timeline/item/event/EventType.kt
+++ b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/timeline/item/event/EventType.kt
@@ -15,5 +15,6 @@ object EventType {
// Call Events
const val CALL_INVITE = "m.call.invite"
- const val CALL_NOTIFY = "m.call.notify"
+
+ const val RTC_NOTIFICATION = "org.matrix.msc4075.rtc.notification"
}
diff --git a/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/user/CurrentSessionIdHolder.kt b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/user/CurrentSessionIdHolder.kt
index b5a42fb9c3..171f8337e0 100644
--- a/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/user/CurrentSessionIdHolder.kt
+++ b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/user/CurrentSessionIdHolder.kt
@@ -11,12 +11,9 @@ import dev.zacsweers.metro.Inject
import dev.zacsweers.metro.SingleIn
import io.element.android.libraries.di.SessionScope
import io.element.android.libraries.matrix.api.MatrixClient
-import io.element.android.libraries.matrix.api.core.SessionId
@SingleIn(SessionScope::class)
@Inject
class CurrentSessionIdHolder(matrixClient: MatrixClient) {
val current = matrixClient.sessionId
-
- fun isCurrentSession(sessionId: SessionId?): Boolean = current == sessionId
}
diff --git a/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/widget/CallWidgetSettingsProvider.kt b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/widget/CallWidgetSettingsProvider.kt
index 7a735bbf92..8334fb5fde 100644
--- a/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/widget/CallWidgetSettingsProvider.kt
+++ b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/widget/CallWidgetSettingsProvider.kt
@@ -15,5 +15,6 @@ interface CallWidgetSettingsProvider {
widgetId: String = UUID.randomUUID().toString(),
encrypted: Boolean,
direct: Boolean,
+ hasActiveCall: Boolean,
): MatrixWidgetSettings
}
diff --git a/libraries/matrix/impl/build.gradle.kts b/libraries/matrix/impl/build.gradle.kts
index a0fa346be2..33ab700022 100644
--- a/libraries/matrix/impl/build.gradle.kts
+++ b/libraries/matrix/impl/build.gradle.kts
@@ -1,4 +1,5 @@
import extension.setupDependencyInjection
+import extension.testCommonDependencies
/*
* Copyright 2022-2024 New Vector Ltd.
@@ -41,16 +42,12 @@ dependencies {
implementation(libs.serialization.json)
implementation(libs.kotlinx.collections.immutable)
- testImplementation(libs.test.junit)
- testImplementation(libs.test.truth)
- testImplementation(libs.test.robolectric)
+ testCommonDependencies(libs)
testImplementation(projects.libraries.featureflag.test)
testImplementation(projects.libraries.matrix.test)
testImplementation(projects.libraries.preferences.test)
+ testImplementation(projects.libraries.previewutils)
testImplementation(projects.libraries.sessionStorage.test)
testImplementation(projects.services.analytics.test)
testImplementation(projects.services.toolbox.test)
- testImplementation(projects.tests.testutils)
- testImplementation(libs.coroutines.test)
- testImplementation(libs.test.turbine)
}
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 e193d8f37d..956e645571 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
@@ -287,7 +287,6 @@ class RustMatrixClient(
}
override suspend fun getRoom(roomId: RoomId): BaseRoom? = withContext(sessionDispatcher) {
- innerClient.rooms()
roomFactory.getBaseRoom(roomId)
}
@@ -689,12 +688,6 @@ class RustMatrixClient(
})
}.buffer(Channel.UNLIMITED)
- override suspend fun availableSlidingSyncVersions(): Result> = withContext(sessionDispatcher) {
- runCatchingExceptions {
- innerClient.availableSlidingSyncVersions().map { it.map() }
- }
- }
-
override suspend fun currentSlidingSyncVersion(): Result = withContext(sessionDispatcher) {
runCatchingExceptions {
innerClient.session().slidingSyncVersion.map()
diff --git a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/auth/RustMatrixAuthenticationService.kt b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/auth/RustMatrixAuthenticationService.kt
index be2263eb86..24201aaf63 100644
--- a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/auth/RustMatrixAuthenticationService.kt
+++ b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/auth/RustMatrixAuthenticationService.kt
@@ -33,11 +33,9 @@ import io.element.android.libraries.matrix.impl.keys.PassphraseGenerator
import io.element.android.libraries.matrix.impl.mapper.toSessionData
import io.element.android.libraries.matrix.impl.paths.SessionPaths
import io.element.android.libraries.matrix.impl.paths.SessionPathsFactory
-import io.element.android.libraries.sessionstorage.api.LoggedInState
import io.element.android.libraries.sessionstorage.api.LoginType
import io.element.android.libraries.sessionstorage.api.SessionStore
import kotlinx.coroutines.CancellationException
-import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.withContext
@@ -83,14 +81,6 @@ class RustMatrixAuthenticationService(
.also { sessionPaths = it }
}
- override fun loggedInStateFlow(): Flow {
- return sessionStore.isLoggedIn()
- }
-
- override suspend fun getLatestSessionId(): SessionId? = withContext(coroutineDispatchers.io) {
- sessionStore.getLatestSession()?.userId?.let { SessionId(it) }
- }
-
override suspend fun restoreSession(sessionId: SessionId): Result = withContext(coroutineDispatchers.io) {
runCatchingExceptions {
val sessionData = sessionStore.getSession(sessionId.value)
@@ -158,7 +148,7 @@ class RustMatrixAuthenticationService(
)
val matrixClient = rustMatrixClientFactory.create(client)
newMatrixClientObservers.forEach { it.invoke(matrixClient) }
- sessionStore.storeData(sessionData)
+ sessionStore.addSession(sessionData)
// Clean up the strong reference held here since it's no longer necessary
currentClient = null
@@ -182,7 +172,7 @@ class RustMatrixAuthenticationService(
sessionPaths = currentSessionPaths,
)
clear()
- sessionStore.storeData(sessionData)
+ sessionStore.addSession(sessionData)
SessionId(sessionData.userId)
}
}
@@ -250,7 +240,7 @@ class RustMatrixAuthenticationService(
val matrixClient = rustMatrixClientFactory.create(client)
newMatrixClientObservers.forEach { it.invoke(matrixClient) }
- sessionStore.storeData(sessionData)
+ sessionStore.addSession(sessionData)
// Clean up the strong reference held here since it's no longer necessary
currentClient = null
@@ -295,7 +285,7 @@ class RustMatrixAuthenticationService(
)
val matrixClient = rustMatrixClientFactory.create(client)
newMatrixClientObservers.forEach { it.invoke(matrixClient) }
- sessionStore.storeData(sessionData)
+ sessionStore.addSession(sessionData)
// Clean up the strong reference held here since it's no longer necessary
currentClient = null
diff --git a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/notification/TimelineEventToNotificationContentMapper.kt b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/notification/TimelineEventToNotificationContentMapper.kt
index 85f87b271f..2ca4a3c823 100644
--- a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/notification/TimelineEventToNotificationContentMapper.kt
+++ b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/notification/TimelineEventToNotificationContentMapper.kt
@@ -10,16 +10,16 @@ package io.element.android.libraries.matrix.impl.notification
import io.element.android.libraries.core.extensions.runCatchingExceptions
import io.element.android.libraries.matrix.api.core.EventId
import io.element.android.libraries.matrix.api.core.UserId
-import io.element.android.libraries.matrix.api.notification.CallNotifyType
import io.element.android.libraries.matrix.api.notification.NotificationContent
+import io.element.android.libraries.matrix.api.notification.RtcNotificationType
import io.element.android.libraries.matrix.impl.room.member.RoomMemberMapper
import io.element.android.libraries.matrix.impl.timeline.item.event.EventMessageMapper
import org.matrix.rustcomponents.sdk.MessageLikeEventContent
-import org.matrix.rustcomponents.sdk.NotifyType
import org.matrix.rustcomponents.sdk.StateEventContent
import org.matrix.rustcomponents.sdk.TimelineEvent
import org.matrix.rustcomponents.sdk.TimelineEventType
import org.matrix.rustcomponents.sdk.use
+import org.matrix.rustcomponents.sdk.RtcNotificationType as SdkRtcNotificationType
class TimelineEventToNotificationContentMapper {
fun map(timelineEvent: TimelineEvent): Result {
@@ -78,7 +78,11 @@ private fun MessageLikeEventContent.toContent(senderId: UserId): NotificationCon
MessageLikeEventContent.CallCandidates -> NotificationContent.MessageLike.CallCandidates
MessageLikeEventContent.CallHangup -> NotificationContent.MessageLike.CallHangup
MessageLikeEventContent.CallInvite -> NotificationContent.MessageLike.CallInvite(senderId)
- is MessageLikeEventContent.CallNotify -> NotificationContent.MessageLike.CallNotify(senderId, notifyType.map())
+ is MessageLikeEventContent.RtcNotification -> NotificationContent.MessageLike.RtcNotification(
+ senderId = senderId,
+ type = notificationType.map(),
+ expirationTimestampMillis = expirationTs.toLong()
+ )
MessageLikeEventContent.KeyVerificationAccept -> NotificationContent.MessageLike.KeyVerificationAccept
MessageLikeEventContent.KeyVerificationCancel -> NotificationContent.MessageLike.KeyVerificationCancel
MessageLikeEventContent.KeyVerificationDone -> NotificationContent.MessageLike.KeyVerificationDone
@@ -101,7 +105,7 @@ private fun MessageLikeEventContent.toContent(senderId: UserId): NotificationCon
}
}
-private fun NotifyType.map(): CallNotifyType = when (this) {
- NotifyType.NOTIFY -> CallNotifyType.NOTIFY
- NotifyType.RING -> CallNotifyType.RING
+private fun SdkRtcNotificationType.map(): RtcNotificationType = when (this) {
+ SdkRtcNotificationType.NOTIFICATION -> RtcNotificationType.NOTIFY
+ SdkRtcNotificationType.RING -> RtcNotificationType.RING
}
diff --git a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/room/MessageEventType.kt b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/room/MessageEventType.kt
index 0f7faf0317..4e88f0971e 100644
--- a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/room/MessageEventType.kt
+++ b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/room/MessageEventType.kt
@@ -15,7 +15,7 @@ fun MessageEventType.map(): MessageLikeEventType = when (this) {
MessageEventType.CALL_INVITE -> MessageLikeEventType.CALL_INVITE
MessageEventType.CALL_HANGUP -> MessageLikeEventType.CALL_HANGUP
MessageEventType.CALL_CANDIDATES -> MessageLikeEventType.CALL_CANDIDATES
- MessageEventType.CALL_NOTIFY -> MessageLikeEventType.CALL_NOTIFY
+ MessageEventType.RTC_NOTIFICATION -> MessageLikeEventType.RTC_NOTIFICATION
MessageEventType.KEY_VERIFICATION_READY -> MessageLikeEventType.KEY_VERIFICATION_READY
MessageEventType.KEY_VERIFICATION_START -> MessageLikeEventType.KEY_VERIFICATION_START
MessageEventType.KEY_VERIFICATION_CANCEL -> MessageLikeEventType.KEY_VERIFICATION_CANCEL
@@ -41,7 +41,7 @@ fun MessageLikeEventType.map(): MessageEventType = when (this) {
MessageLikeEventType.CALL_INVITE -> MessageEventType.CALL_INVITE
MessageLikeEventType.CALL_HANGUP -> MessageEventType.CALL_HANGUP
MessageLikeEventType.CALL_CANDIDATES -> MessageEventType.CALL_CANDIDATES
- MessageLikeEventType.CALL_NOTIFY -> MessageEventType.CALL_NOTIFY
+ MessageLikeEventType.RTC_NOTIFICATION -> MessageEventType.RTC_NOTIFICATION
MessageLikeEventType.KEY_VERIFICATION_READY -> MessageEventType.KEY_VERIFICATION_READY
MessageLikeEventType.KEY_VERIFICATION_START -> MessageEventType.KEY_VERIFICATION_START
MessageLikeEventType.KEY_VERIFICATION_CANCEL -> MessageEventType.KEY_VERIFICATION_CANCEL
diff --git a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/room/RustBaseRoom.kt b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/room/RustBaseRoom.kt
index 975185242b..1ca5915c71 100644
--- a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/room/RustBaseRoom.kt
+++ b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/room/RustBaseRoom.kt
@@ -38,10 +38,12 @@ import io.element.android.libraries.matrix.impl.timeline.toRustReceiptType
import io.element.android.libraries.matrix.impl.util.mxCallbackFlow
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.cancel
+import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.stateIn
import kotlinx.coroutines.withContext
+import org.matrix.rustcomponents.sdk.CallDeclineListener
import org.matrix.rustcomponents.sdk.RoomInfoListener
import org.matrix.rustcomponents.sdk.use
import timber.log.Timber
@@ -300,4 +302,20 @@ class RustBaseRoom(
innerRoom.reportRoom(reason.orEmpty())
}
}
+
+ override suspend fun declineCall(notificationEventId: EventId): Result = withContext(roomDispatcher) {
+ runCatchingExceptions {
+ innerRoom.declineCall(notificationEventId.value)
+ }
+ }
+
+ override suspend fun subscribeToCallDecline(notificationEventId: EventId): Flow = withContext(roomDispatcher) {
+ mxCallbackFlow {
+ innerRoom.subscribeToCallDeclineEvents(notificationEventId.value, object : CallDeclineListener {
+ override fun call(declinerUserId: String) {
+ trySend(UserId(declinerUserId))
+ }
+ })
+ }
+ }
}
diff --git a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/room/join/AllowRule.kt b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/room/join/AllowRule.kt
index ae74e1edc0..a93ce58236 100644
--- a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/room/join/AllowRule.kt
+++ b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/room/join/AllowRule.kt
@@ -20,7 +20,7 @@ fun RustAllowRule.map(): AllowRule {
fun AllowRule.map(): RustAllowRule {
return when (this) {
- is AllowRule.RoomMembership -> RustAllowRule.RoomMembership(roomId.toString())
+ is AllowRule.RoomMembership -> RustAllowRule.RoomMembership(roomId.value)
is AllowRule.Custom -> RustAllowRule.Custom(json)
}
}
diff --git a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/room/member/RoomMemberMapper.kt b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/room/member/RoomMemberMapper.kt
index 9411ae3aab..af7376e445 100644
--- a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/room/member/RoomMemberMapper.kt
+++ b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/room/member/RoomMemberMapper.kt
@@ -25,7 +25,6 @@ object RoomMemberMapper {
membership = mapMembership(roomMember.membership),
isNameAmbiguous = roomMember.isNameAmbiguous,
powerLevel = powerLevel,
- normalizedPowerLevel = roomMember.normalizedPowerLevel.into(),
isIgnored = roomMember.isIgnored,
role = mapRole(roomMember.suggestedRoleForPowerLevel, powerLevel),
membershipChangeReason = roomMember.membershipChangeReason
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 66931a1f13..e26cea1c94 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
@@ -33,6 +33,12 @@ class RoomSummaryListProcessor(
updates.forEach { update ->
applyUpdate(update)
}
+
+ // TODO remove once https://github.com/element-hq/element-x-android/issues/5031 has been confirmed as fixed
+ val duplicates = groupingBy { it.roomId }.eachCount().filter { it.value > 1 }
+ if (duplicates.isNotEmpty()) {
+ Timber.e("Found duplicates in room summaries after a list update from the SDK: $duplicates. Updates: $updates")
+ }
}
}
diff --git a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/spaces/RustSpaceRoomList.kt b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/spaces/RustSpaceRoomList.kt
new file mode 100644
index 0000000000..1a940bd2f0
--- /dev/null
+++ b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/spaces/RustSpaceRoomList.kt
@@ -0,0 +1,81 @@
+/*
+ * Copyright 2025 New Vector Ltd.
+ *
+ * SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial
+ * Please see LICENSE files in the repository root for full details.
+ */
+
+package io.element.android.libraries.matrix.impl.spaces
+
+import io.element.android.libraries.core.extensions.runCatchingExceptions
+import io.element.android.libraries.matrix.api.core.RoomId
+import io.element.android.libraries.matrix.api.spaces.SpaceRoom
+import io.element.android.libraries.matrix.api.spaces.SpaceRoomList
+import kotlinx.coroutines.CompletableDeferred
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.flow.MutableSharedFlow
+import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.coroutines.flow.StateFlow
+import kotlinx.coroutines.flow.collect
+import kotlinx.coroutines.flow.onEach
+import kotlinx.coroutines.launch
+import uniffi.matrix_sdk_ui.SpaceRoomListPaginationState
+import java.util.Optional
+import org.matrix.rustcomponents.sdk.SpaceRoomList as InnerSpaceRoomList
+
+class RustSpaceRoomList(
+ private val roomId: RoomId,
+ private val innerProvider: suspend () -> InnerSpaceRoomList,
+ sessionCoroutineScope: CoroutineScope,
+ spaceRoomMapper: SpaceRoomMapper,
+ private val spaceRoomCache: SpaceRoomCache,
+) : SpaceRoomList {
+ private val inner = CompletableDeferred()
+
+ override fun currentSpaceFlow(): StateFlow> {
+ return spaceRoomCache.getSpaceRoomFlow(roomId)
+ }
+
+ override val spaceRoomsFlow = MutableSharedFlow>(replay = 1, extraBufferCapacity = Int.MAX_VALUE)
+ override val paginationStatusFlow: MutableStateFlow =
+ MutableStateFlow(SpaceRoomList.PaginationStatus.Idle(hasMoreToLoad = false))
+ private val spaceListUpdateProcessor = SpaceListUpdateProcessor(
+ spaceRoomsFlow = spaceRoomsFlow,
+ mapper = spaceRoomMapper,
+ spaceRoomCache = spaceRoomCache
+ )
+
+ init {
+ sessionCoroutineScope.launch {
+ inner.complete(innerProvider())
+ }
+ sessionCoroutineScope.launch {
+ inner.await().paginationStateFlow()
+ .onEach { paginationStatus ->
+ paginationStatusFlow.emit(paginationStatus.into())
+ }
+ .collect()
+ }
+
+ sessionCoroutineScope.launch {
+ inner.await().spaceListUpdateFlow()
+ .onEach { updates ->
+ spaceListUpdateProcessor.postUpdates(updates)
+ }
+ .collect()
+ }
+ }
+
+ override suspend fun paginate(): Result {
+ return runCatchingExceptions {
+ inner.await().paginate()
+ }
+ }
+
+ private fun SpaceRoomListPaginationState.into(): SpaceRoomList.PaginationStatus {
+ return when (this) {
+ is SpaceRoomListPaginationState.Idle -> SpaceRoomList.PaginationStatus.Idle(hasMoreToLoad = !endReached)
+ SpaceRoomListPaginationState.Loading -> SpaceRoomList.PaginationStatus.Loading
+ }
+ }
+}
diff --git a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/spaces/RustSpaceService.kt b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/spaces/RustSpaceService.kt
index b059d476bc..2a63367577 100644
--- a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/spaces/RustSpaceService.kt
+++ b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/spaces/RustSpaceService.kt
@@ -8,7 +8,9 @@
package io.element.android.libraries.matrix.impl.spaces
import io.element.android.libraries.core.extensions.runCatchingExceptions
+import io.element.android.libraries.matrix.api.core.RoomId
import io.element.android.libraries.matrix.api.spaces.SpaceRoom
+import io.element.android.libraries.matrix.api.spaces.SpaceRoomList
import io.element.android.libraries.matrix.api.spaces.SpaceService
import io.element.android.libraries.matrix.impl.util.cancelAndDestroy
import kotlinx.coroutines.CoroutineDispatcher
@@ -21,11 +23,8 @@ import kotlinx.coroutines.flow.MutableSharedFlow
import kotlinx.coroutines.flow.buffer
import kotlinx.coroutines.flow.callbackFlow
import kotlinx.coroutines.flow.catch
-import kotlinx.coroutines.flow.first
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach
-import kotlinx.coroutines.sync.Mutex
-import kotlinx.coroutines.sync.withLock
import kotlinx.coroutines.withContext
import org.matrix.rustcomponents.sdk.SpaceListUpdate
import org.matrix.rustcomponents.sdk.SpaceServiceInterface
@@ -38,104 +37,55 @@ class RustSpaceService(
private val sessionCoroutineScope: CoroutineScope,
private val sessionDispatcher: CoroutineDispatcher,
) : SpaceService {
- private val mapper = SpaceRoomMapper()
- private val mutex = Mutex()
-
- override val spaceRooms = MutableSharedFlow>(replay = 1, extraBufferCapacity = 1)
+ private val spaceRoomMapper = SpaceRoomMapper()
+ private val spaceRoomCache = SpaceRoomCache()
+ override val spaceRoomsFlow = MutableSharedFlow>(replay = 1, extraBufferCapacity = 1)
+ private val spaceListUpdateProcessor = SpaceListUpdateProcessor(
+ spaceRoomsFlow = spaceRoomsFlow,
+ mapper = spaceRoomMapper,
+ spaceRoomCache = spaceRoomCache
+ )
override suspend fun joinedSpaces(): Result> = withContext(sessionDispatcher) {
runCatchingExceptions {
innerSpaceService.joinedSpaces()
.map {
- it.let(mapper::map)
+ it.let(spaceRoomMapper::map)
}
}
}
- // override suspend fun spaceRoomList(spaceId: SpaceId): Result> = withContext(sessionDispatcher) {
- // runCatchingExceptions {
- // innerSpaceService.spaceRoomList(spaceId.value)
- // }
- // }
+ override fun spaceRoomList(id: RoomId): SpaceRoomList {
+ return RustSpaceRoomList(
+ roomId = id,
+ innerProvider = { innerSpaceService.spaceRoomList(id.value) },
+ sessionCoroutineScope = sessionCoroutineScope,
+ spaceRoomMapper = spaceRoomMapper,
+ spaceRoomCache = spaceRoomCache,
+ )
+ }
init {
innerSpaceService
- .spaceDiffFlow()
- .onEach {
- handeUpdate(it)
+ .spaceListUpdate()
+ .onEach { updates ->
+ spaceListUpdateProcessor.postUpdates(updates)
}
.launchIn(sessionCoroutineScope)
}
-
- private suspend fun handeUpdate(spaceListUpdates: List) {
- mutex.withLock {
- val current = if (spaceRooms.replayCache.isNotEmpty()) {
- spaceRooms.first().toMutableList()
- } else {
- mutableListOf()
- }
- spaceListUpdates.forEach { update ->
- current.applyUpdate(update)
- }
- spaceRooms.emit(current)
- }
- }
-
- private fun MutableList.applyUpdate(update: SpaceListUpdate) {
- when (update) {
- is SpaceListUpdate.Append -> {
- val newSpaces = update.values.map(mapper::map)
- addAll(newSpaces)
- }
- SpaceListUpdate.Clear -> clear()
- is SpaceListUpdate.Insert -> {
- val newSpace = mapper.map(update.value)
- add(update.index.toInt(), newSpace)
- }
- SpaceListUpdate.PopBack -> {
- removeAt(lastIndex)
- }
- SpaceListUpdate.PopFront -> {
- removeAt(0)
- }
- is SpaceListUpdate.PushBack -> {
- val newSpace = mapper.map(update.value)
- add(newSpace)
- }
- is SpaceListUpdate.PushFront -> {
- val newSpace = mapper.map(update.value)
- add(0, newSpace)
- }
- is SpaceListUpdate.Remove -> {
- removeAt(update.index.toInt())
- }
- is SpaceListUpdate.Reset -> {
- clear()
- val newSpaces = update.values.map(mapper::map)
- addAll(newSpaces)
- }
- is SpaceListUpdate.Set -> {
- val newSpace = mapper.map(update.value)
- this[update.index.toInt()] = newSpace
- }
- is SpaceListUpdate.Truncate -> {
- subList(update.length.toInt(), size).clear()
- }
- }
- }
}
-internal fun SpaceServiceInterface.spaceDiffFlow(): Flow> =
+internal fun SpaceServiceInterface.spaceListUpdate(): Flow> =
callbackFlow {
val listener = object : SpaceServiceJoinedSpacesListener {
override fun onUpdate(roomUpdates: List) {
trySendBlocking(roomUpdates)
}
}
- Timber.d("Open spaceDiffFlow for SpaceServiceInterface ${this@spaceDiffFlow}")
+ Timber.d("Open spaceDiffFlow for SpaceServiceInterface ${this@spaceListUpdate}")
val taskHandle = subscribeToJoinedSpaces(listener)
awaitClose {
- Timber.d("Close spaceDiffFlow for SpaceServiceInterface ${this@spaceDiffFlow}")
+ Timber.d("Close spaceDiffFlow for SpaceServiceInterface ${this@spaceListUpdate}")
taskHandle.cancelAndDestroy()
}
}.catch {
diff --git a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/spaces/SpaceListUpdateProcessor.kt b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/spaces/SpaceListUpdateProcessor.kt
new file mode 100644
index 0000000000..f1193661ea
--- /dev/null
+++ b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/spaces/SpaceListUpdateProcessor.kt
@@ -0,0 +1,86 @@
+/*
+ * Copyright 2023, 2024 New Vector Ltd.
+ *
+ * SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial
+ * Please see LICENSE files in the repository root for full details.
+ */
+
+package io.element.android.libraries.matrix.impl.spaces
+
+import io.element.android.libraries.matrix.api.spaces.SpaceRoom
+import kotlinx.coroutines.flow.MutableSharedFlow
+import kotlinx.coroutines.flow.first
+import kotlinx.coroutines.sync.Mutex
+import kotlinx.coroutines.sync.withLock
+import org.matrix.rustcomponents.sdk.SpaceListUpdate
+import timber.log.Timber
+
+internal class SpaceListUpdateProcessor(
+ private val spaceRoomsFlow: MutableSharedFlow>,
+ private val mapper: SpaceRoomMapper,
+ private val spaceRoomCache: SpaceRoomCache,
+) {
+ private val mutex = Mutex()
+
+ suspend fun postUpdates(updates: List) {
+ Timber.v("Update space rooms from postUpdates (with ${updates.size} items) on ${Thread.currentThread()}")
+ updateSpaceRooms {
+ updates.forEach { update -> applyUpdate(update) }
+ }
+ }
+
+ private suspend fun updateSpaceRooms(block: MutableList.() -> Unit) =
+ mutex.withLock {
+ val spaceRooms = if (spaceRoomsFlow.replayCache.isNotEmpty()) {
+ spaceRoomsFlow.first().toMutableList()
+ } else {
+ mutableListOf()
+ }
+ block(spaceRooms)
+ spaceRoomCache.update(spaceRooms)
+ spaceRoomsFlow.emit(spaceRooms)
+ }
+
+ private fun MutableList.applyUpdate(update: SpaceListUpdate) {
+ when (update) {
+ is SpaceListUpdate.Append -> {
+ val newSpaces = update.values.map(mapper::map)
+ addAll(newSpaces)
+ }
+ SpaceListUpdate.Clear -> clear()
+ is SpaceListUpdate.Insert -> {
+ val newSpace = mapper.map(update.value)
+ add(update.index.toInt(), newSpace)
+ }
+ SpaceListUpdate.PopBack -> {
+ removeAt(lastIndex)
+ }
+ SpaceListUpdate.PopFront -> {
+ removeAt(0)
+ }
+ is SpaceListUpdate.PushBack -> {
+ val newSpace = mapper.map(update.value)
+ add(newSpace)
+ }
+ is SpaceListUpdate.PushFront -> {
+ val newSpace = mapper.map(update.value)
+ add(0, newSpace)
+ }
+ is SpaceListUpdate.Remove -> {
+ removeAt(update.index.toInt())
+ }
+ is SpaceListUpdate.Reset -> {
+ clear()
+ val newSpaces = update.values.map(mapper::map)
+ addAll(newSpaces)
+ }
+ is SpaceListUpdate.Set -> {
+ val newSpace = mapper.map(update.value)
+ this[update.index.toInt()] = newSpace
+ }
+ is SpaceListUpdate.Truncate -> {
+ subList(update.length.toInt(), size).clear()
+ }
+ }
+ }
+}
diff --git a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/spaces/SpaceRoomCache.kt b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/spaces/SpaceRoomCache.kt
new file mode 100644
index 0000000000..c8f55f1db6
--- /dev/null
+++ b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/spaces/SpaceRoomCache.kt
@@ -0,0 +1,36 @@
+/*
+ * Copyright 2025 New Vector Ltd.
+ *
+ * SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial
+ * Please see LICENSE files in the repository root for full details.
+ */
+
+package io.element.android.libraries.matrix.impl.spaces
+
+import io.element.android.libraries.core.coroutine.mapState
+import io.element.android.libraries.matrix.api.core.RoomId
+import io.element.android.libraries.matrix.api.spaces.SpaceRoom
+import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.coroutines.flow.StateFlow
+import kotlinx.coroutines.flow.update
+import java.util.Optional
+
+/**
+ * An in memory cache of space rooms.
+ * Only caches Rooms with roomType [io.element.android.libraries.matrix.api.room.RoomType.Space].
+ */
+class SpaceRoomCache {
+ private val inMemoryCache = MutableStateFlow
- "%d pleidlais"
- "%d pleidlais"
+ "Yn paratoi…"
"Polisi preifatrwydd"
"Ystafell breifat"
+ "Gofod preifat"
"Ystafell gyhoeddus"
+ "Gofod cyhoeddus"
"Adwaith"
"Adweithiau"
"Rheswm"
"Allwedd adfer"
"Wrthi\'n adnewyddu…"
+
+ - "%1$d atebion"
+ - "%1$d ateb"
+ - "%1$d ateb"
+ - "%1$d ateb"
+ - "%1$d ateb"
+ - "%1$d ateb"
+
"Yn ymateb i %1$s"
"Adrodd ar wall"
"Adrodd am broblem"
@@ -288,6 +312,14 @@ Rheswm: %1$s."
"Ystafell"
"Enw\'r ystafell"
"e.e. enw eich project"
+
+ - "%1$d Ystafelloedd"
+ - "%1$d Ystafell"
+ - "%1$d Ystafell"
+ - "%1$d Ystafell"
+ - "%1$d Ystafell"
+ - "%1$d Ystafell"
+
"Newidiadau wedi\'u cadw"
"Cadw"
"Clo sgrin"
@@ -295,18 +327,30 @@ Rheswm: %1$s."
"Canlyniadau chwilio"
"Diogelwch"
"Wedi\'i weld gan"
+ "Dewis cyfrif"
"Anfon at"
"Yn anfon…"
"Methodd anfon"
"Anfonwyd"
". "
"Nid yw\'r gweinydd yn cael ei gynnal"
+ "Gweinydd yn anghyraeddadwy"
"URL gweinydd"
"Gosodiadau"
+ "Rhannu gofod"
"Lleoliad yn cael ei rannu"
"Allgofnodi"
"Aeth rhywbeth o\'i le"
"Wedi canfod mater. Ceisiwch eto."
+ "Gofod"
+
+ - "%1$d Gofodau"
+ - "%1$d Gofod"
+ - "%1$d Ofod"
+ - "%1$d Gofod"
+ - "%1$d Gofod"
+ - "%1$d Gofod"
+
"Dechrau sgwrs…"
"Sticer"
"Llwyddiant"
@@ -337,6 +381,12 @@ Rheswm: %1$s."
"Gwirio hunaniaeth"
"Gwirio defnyddiwr"
"Fideo"
+ "Ansawdd uchel"
+ "Yr ansawdd gorau ond maint ffeil mwy"
+ "Ansawdd isel"
+ "Y cyflymder llwytho cyflymaf a\'r maint ffeil lleiaf"
+ "Ansawdd safonol"
+ "Cydbwysedd ansawdd a chyflymder llwytho"
"Neges llais"
"Yn aros…"
"Yn aros am y neges hon"
@@ -351,6 +401,10 @@ Rheswm: %1$s."
Ydych chi\'n siŵr eich bod am barhau?"
"Gwnewch yn siŵr fod y ddolen hon yn iawn"
+ "Dewiswch ansawdd rhagosodedig y fideos rydych chi\'n eu llwytho."
+ "Ansawdd llwytho fideo"
+ "Y maint ffeil mwyaf sy\'n cael ei ganiatáu yw:%1$s"
+ "Mae maint y ffeil yn rhy fawr i\'w llwytho"
"Adroddwyd am yr ystafell"
"Adroddwyd a gadael yr ystafell"
"Cadarnhad"
@@ -359,6 +413,11 @@ Ydych chi\'n siŵr eich bod am barhau?"
"Rhybudd"
"Dyw eich newidiadau heb gael eu cadw. Ydych chi\'n siŵr eich bod am fynd nôl?"
"Cadw\'r newidiadau?"
+ "Y maint ffeil mwyaf sy\'n cael ei ganiatáu yw: %1$s"
+ "Dewiswch ansawdd y fideo rydych chi am ei llwytho."
+ "Dewiswch ansawdd llwytho fideo"
+ "Chwilio emojis"
+ "Rydych chi eisoes wedi mewngofnodi ar y ddyfais hon fel %1$s ."
"Mae angen uwchraddio eich gweinydd cartref i gefnogi Gwasanaeth Dilysu Matrix a chreu cyfrif."
"Wedi methu creu\'r ddolen barhaol"
"Methodd %1$s â llwytho\'r map. Ceisiwch eto yn nes ymlaen."
@@ -386,6 +445,10 @@ Ydych chi\'n siŵr eich bod am barhau?"
"Hei, siaradwch â mi ar %1$s: %2$s"
"Android %1$s"
"Rageshake i adrodd gwall"
+ "Bydd hyn hefyd yn eich tynnu o bob ystafell yn y gofod hwn."
+ "Bydd hyn hefyd yn eich tynnu o bob ystafell yn y gofod hwn, gan gynnwys y rhai rydych chi\'n unig weinyddwr ar eu cyfer:"
+ "Gadael %1$s ?"
+ "Llun sgrin"
"%1$s: %2$s"
"Dewisiadau"
"Tynnu %1$s"
@@ -412,6 +475,7 @@ Ydych chi\'n siŵr eich bod am barhau?"
"Dyw eich neges heb ei hanfon oherwydd nid yw %1$s wedi gwirio pob dyfais"
"Mae un neu fwy o\'ch dyfeisiau heb eu gwirio. Gallwch anfon y neges beth bynnag, neu gallwch ei diddymu am y tro a cheisio eto yn nes ymlaen ar ôl i chi ddilysu eich holl ddyfeisiau."
"Nid yw eich neges wedi\'i hanfon oherwydd nad ydych wedi gwirio un neu fwy o\'ch dyfeisiau"
+ "Golygu Gweinyddwyr neu Berchnogion"
"Wedi methu â phrosesu cyfryngau i\'w llwytho, ceisiwch eto."
"Methu â nôl manylion defnyddiwr"
"Neges yn %1$s"
@@ -429,6 +493,9 @@ Ydych chi\'n siŵr eich bod am barhau?"
"Agor yn Google Maps"
"Agor yn OpenStreetMap"
"Rhannu\'r lleoliad hwn"
+ "Gofodau rydych wedi\'u creu neu wedi ymuno â nhw."
+ "%1$s • %2$s"
+ "Gofodau"
"Heb anfon y neges oherwydd bod hunaniaeth wedi \'i ddilysu %1$s wedi\'i ailosod."
"Heb anfon y neges oherwydd nid yw %1$s wedi gwirio pob dyfais."
"Heb anfon y neges oherwydd nad ydych wedi gwirio un neu fwy o\'ch dyfeisiau."
diff --git a/libraries/ui-strings/src/main/res/values-da/translations.xml b/libraries/ui-strings/src/main/res/values-da/translations.xml
index 4116bfa8f1..44f0321315 100644
--- a/libraries/ui-strings/src/main/res/values-da/translations.xml
+++ b/libraries/ui-strings/src/main/res/values-da/translations.xml
@@ -42,7 +42,7 @@
"Fjern reaktion med %1$s"
"Avatar for rummet"
"Send filer"
- "Tidsbegrænset handling påkrævet"
+ "Tidsbegrænset handling påkrævet, du har et minut til at bekræfte"
"Vis adgangskode"
"Start et opkald"
"Deaktiveret rum"
@@ -165,6 +165,8 @@
"Opgradering tilgængelig"
"Om"
"Politik for acceptabel brug"
+ "Tilføj en konto"
+ "Tilføj en anden konto"
"Tilføjelse af billedtekst"
"Avancerede indstillinger"
"et billede"
@@ -185,6 +187,7 @@
"Invitationen blev afvist"
"Mørkt tema"
"Fejl under dekryptering"
+ "Beskrivelse"
"Indstillinger for udviklere"
"Enheds-ID"
"Direkte samtale"
@@ -293,12 +296,14 @@
"Søgeresultater"
"Sikkerhed"
"Set af"
+ "Vælg en konto"
"Send til"
"Sender…"
"Afsendelse mislykkedes"
"Sendt"
". "
"Serveren er ikke understøttet"
+ "Serveren er ikke tilgængelig"
"Server URL"
"Indstillinger"
"Delt placering"
@@ -375,6 +380,8 @@ Er du sikker på, at du vil fortsætte?"
"Den maksimalt tilladte filstørrelse er: %1$s"
"Vælg den kvalitet, du ønsker at uploade videoen i."
"Vælg kvalitet for video-overførsel"
+ "Søg emojis"
+ "Du er allerede logget ind på denne enhed som %1$s."
"Din hjemmeserver skal opgraderes for at understøtte Matrix Authentication Service og kontooprettelse."
"Oprettelse af permalink mislykkedes"
"%1$s kunne ikke indlæse kortet. Prøv igen senere."
diff --git a/libraries/ui-strings/src/main/res/values-de/translations.xml b/libraries/ui-strings/src/main/res/values-de/translations.xml
index 82fe401127..39396928eb 100644
--- a/libraries/ui-strings/src/main/res/values-de/translations.xml
+++ b/libraries/ui-strings/src/main/res/values-de/translations.xml
@@ -105,6 +105,7 @@
"Verlassen"
"Unterhaltung verlassen"
"Verlassen"
+ "Space verlassen"
"Mehr laden…"
"Konto verwalten"
"Geräte verwalten"
@@ -184,9 +185,11 @@
"Chat wird erstellt…"
"Anfrage abgebrochen"
"Hat den Chat verlassen"
+ "Space verlassen"
"Einladung abgelehnt"
"Dunkel"
"Dekodierungsfehler"
+ "Beschreibung"
"Entwickleroptionen"
"Geräte-ID"
"Direktnachricht"
@@ -303,6 +306,7 @@ Grund: %1$s."
"Gesendet"
". "
"Server wird nicht unterstützt"
+ "Server nicht erreichbar"
"Server-URL"
"Einstellungen"
"Geteilter Standort"
@@ -408,6 +412,9 @@ Möchtest du wirklich fortfahren?"
"Hey, sprich mit mir auf %1$s: %2$s"
"%1$s Android"
"Heftiges Schütteln um Fehler zu melden"
+ "Dadurch wirst du auch aus allen Chats in diesem Space entfernt."
+ "Dadurch wirst du auch aus allen Chats in diesem Space entfernt, auch aus denen, für die du der einzige Admin bist:"
+ "%1$s verlassen?"
"Bildschirmfoto"
"%1$s: %2$s"
"Optionen"
diff --git a/libraries/ui-strings/src/main/res/values-eo/translations.xml b/libraries/ui-strings/src/main/res/values-eo/translations.xml
new file mode 100644
index 0000000000..3368f36f08
--- /dev/null
+++ b/libraries/ui-strings/src/main/res/values-eo/translations.xml
@@ -0,0 +1,26 @@
+
+
+ "Manage connected devices"
+ "Start fresh"
+ "Backup password"
+ "Sent from an unconfirmed device"
+ "Sender\'s security verification has changed"
+ "Confirm device"
+ "Verify user"
+ "%1$s\'s security verification has changed. %2$s"
+ "%1$s\'s %2$s security verification has changed. %3$s"
+ "%1$s\'s security verification has changed."
+ "%1$s\'s %2$s security verification has changed. %3$s"
+ "You\'re about to go to your %1$s account to start fresh. Afterwards you\'ll be taken back to the app."
+ "Can\'t confirm? Go to your account to start fresh."
+ "Your message was not sent because %1$s\'s security verification has changed"
+ "%1$s is using one or more unconfirmed devices. You can send the message anyway, or you can cancel for now and try again later after %2$s has confirmed all their devices."
+ "Your message was not sent because %1$s has not confirmed all devices"
+ "One or more of your connected devices are unconfirmed. You can send the message anyway, or you can cancel for now and try again later after you have confirmed all of your connected devices."
+ "Your message was not sent because you have not confirmed one or more of your connected devices"
+ "Message not sent because %1$s\'s security verification has changed."
+ "Message not sent because %1$s has not confirmed all their devices."
+ "Message not sent because you have not confirmed one or more of your connected devices."
+ "You need to confirm this device for access to historical messages"
+ "This message was blocked either because you did not confirm your device or because the sender needs to verify you."
+
diff --git a/libraries/ui-strings/src/main/res/values-et/translations.xml b/libraries/ui-strings/src/main/res/values-et/translations.xml
index cd74b0061e..e02bba3558 100644
--- a/libraries/ui-strings/src/main/res/values-et/translations.xml
+++ b/libraries/ui-strings/src/main/res/values-et/translations.xml
@@ -105,6 +105,7 @@
"Lahku"
"Lahku vestlusest"
"Lahku jututoast"
+ "Lahku kogukonnast"
"Näita veel"
"Halda kasutajakontot"
"Halda seadmeid"
@@ -187,6 +188,7 @@
"Keeldusid kutsest"
"Tume"
"Dekrüptimisviga"
+ "Kirjeldus"
"Arendaja valikud"
"Seadme tunnus"
"Otsevestlus"
@@ -303,6 +305,7 @@ Põhjus: %1$s."
"Saadetud"
". "
"Server pole toetatud"
+ "Server pole leitav"
"Serveri URL"
"Seadistused"
"Jagatud asukoht"
@@ -408,6 +411,9 @@ Kas sa oled kindel, et soovid jätkata?"
"Hei, suhtle minuga %1$s võrgus: %2$s"
"%1$s Android"
"Veast teatamiseks raputa nutiseadet ägedalt"
+ "Sellega eemaldad end ka kõikidest antud kogukonna jututubadest."
+ "Sellega eemaldad end ka kõikidest antud kogukonna jututubadest, sealhulgast järgnevaist, kus oled ainus peakasutaja:"
+ "Kas lahkud %1$s kogukonnast?"
"Ekraanitõmmis"
"%1$s: %2$s"
"Valikud"
diff --git a/libraries/ui-strings/src/main/res/values-fi/translations.xml b/libraries/ui-strings/src/main/res/values-fi/translations.xml
index 4b2fe2682f..326d67c2d9 100644
--- a/libraries/ui-strings/src/main/res/values-fi/translations.xml
+++ b/libraries/ui-strings/src/main/res/values-fi/translations.xml
@@ -2,6 +2,7 @@
"Lisää reaktio: %1$s"
"Avatar"
+ "Pienennä viestin tekstikenttä"
"Poista"
- "%1$d numero syötetty"
@@ -10,6 +11,7 @@
"Muokkaa avataria"
"Täysi osoite tulee olemaan %1$s"
"Salauksen tiedot"
+ "Laajenna viestin tekstikenttä"
"Piilota salasana"
"Liity puheluun"
"Siirry loppuun"
@@ -40,7 +42,7 @@
"Poista reaktio: %1$s"
"Huoneen avatar"
"Lähetä tiedostoja"
- "Aikarajoitettu toimenpide vaaditaan"
+ "Aikarajoitettu toimenpide vaaditaan, sinulla on yksi minuutti aikaa vahvistaa"
"Näytä salasana"
"Aloita puhelu"
"Haudattu huone"
@@ -88,6 +90,7 @@
"Ota käyttöön"
"Lopeta kysely"
"Syötä PIN-koodi"
+ "Valmis"
"Unohditko salasanan?"
"Välitä"
"Takaisin"
@@ -102,6 +105,7 @@
"Poistu"
"Poistu keskustelusta"
"Poistu huoneesta"
+ "Poistu tilasta"
"Lataa lisää"
"Hallitse tiliä"
"Hallitse laitteita"
@@ -162,10 +166,14 @@
"Päivitys saatavilla"
"Tietoa"
"Hyväksyttävän käytön käytäntö"
+ "Lisää tili"
+ "Lisää toinen tili"
"Lisätään kuvatekstiä"
"Edistyneet asetukset"
"kuva"
"Analytiikka"
+ "Poistuit huoneesta"
+ "Sinut kirjattiin ulos istunnosta"
"Ulkoasu"
"Ääni"
"Estetyt käyttäjät"
@@ -177,9 +185,11 @@
"Luodaan huonetta…"
"Pyyntö peruutettu"
"Poistuit huoneesta"
+ "Poistuit tilasta"
"Kutsu hylätty"
"Tumma"
"Salauksen purkuvirhe"
+ "Kuvaus"
"Kehittäjän asetukset"
"Laitteen tunnus"
"Yksityinen keskustelu"
@@ -289,18 +299,22 @@ Syy: %1$s."
"Hakutulokset"
"Turvallisuus"
"Nähneet henkilöt"
+ "Valitse tili"
"Jaa"
"Lähetetään…"
"Lähetys epäonnistui"
"Lähetetty"
". "
"Palvelin ei ole tuettu"
+ "Palvelimeen ei saada yhteyttä"
"Palvelimen osoite"
"Asetukset"
+ "Jaa tila"
"Jaettu sijainti"
"Kirjaudutaan ulos"
"Jokin meni pieleen"
"Kohtasimme ongelman. Yritä uudelleen."
+ "Tila"
- "%1$d Tila"
- "%1$d Tilaa"
@@ -335,6 +349,12 @@ Syy: %1$s."
"Vahvista identiteetti"
"Vahvista käyttäjä"
"Video"
+ "Korkea laatu"
+ "Paras laatu, mutta suurempi tiedostokoko"
+ "Heikko laatu"
+ "Nopein lähetysnopeus ja pienin tiedostokoko"
+ "Normaali laatu"
+ "Tasapainotettu laatu ja lähetysnopeus"
"Ääniviesti"
"Odotetaan…"
"Odotetaan viestiä"
@@ -349,6 +369,10 @@ Syy: %1$s."
Haluatko varmasti jatkaa?"
"Tarkista tämä linkki"
+ "Valitse lähettämäsi videoiden oletuslaatu."
+ "Videoiden lähetyslaatu"
+ "Suurin sallittu tiedostokoko on: %1$s"
+ "Tiedostokoko on liian suuri lähetettäväksi"
"Huone ilmoitettu"
"Ilmoitettu ja poistuttu huoneesta"
"Vahvistus"
@@ -356,7 +380,12 @@ Haluatko varmasti jatkaa?"
"Onnistui"
"Varoitus"
"Muutoksiasi ei ole tallennettu. Haluatko varmasti palata takaisin?"
- "Tallenna muutokset?"
+ "Tallennetaanko muutokset?"
+ "Suurin sallittu tiedostokoko on: %1$s"
+ "Valitse lähetettävän videon laatu."
+ "Valitse videon lähetyslaatu"
+ "Etsi emojeja"
+ "Olet jo kirjautuneena tälle laitteelle käyttäjällä %1$s."
"Kotipalvelimesi on päivitettävä tukemaan Matrix Authentication Serviceä ja tilin luomista."
"Pysyvän linkin luominen epäonnistui"
"%1$s ei pystynyt lataamaan karttaa. Yritä myöhemmin uudelleen."
@@ -384,6 +413,9 @@ Haluatko varmasti jatkaa?"
"Hei, keskustele kanssani %1$s -sovelluksessa: %2$s"
"%1$s Android"
"Raivostunut ravistaminen ilmoittaa virheestä"
+ "Tämä poistaa sinut myös kaikista tämän tilan huoneista."
+ "Tämä poistaa sinut myös kaikista tämän tilan huoneista, mukaan lukien ne, joissa olet ainoa ylläpitäjä:"
+ "Haluatko poistua tilasta %1$s?"
"Näyttökuva"
"%1$s: %2$s"
"Vaihtoehdot"
diff --git a/libraries/ui-strings/src/main/res/values-fr/translations.xml b/libraries/ui-strings/src/main/res/values-fr/translations.xml
index 24cc58f41c..506a0936d9 100644
--- a/libraries/ui-strings/src/main/res/values-fr/translations.xml
+++ b/libraries/ui-strings/src/main/res/values-fr/translations.xml
@@ -187,6 +187,7 @@
"Invitation refusée"
"Sombre"
"Erreur de déchiffrement"
+ "Description"
"Options pour les développeurs"
"Identifiant de session"
"Discussion à deux"
@@ -303,6 +304,7 @@ Raison : %1$s."
"Envoyé"
". "
"Serveur non pris en charge"
+ "Serveur inaccessible"
"URL du serveur"
"Paramètres"
"Position partagée"
diff --git a/libraries/ui-strings/src/main/res/values-nb/translations.xml b/libraries/ui-strings/src/main/res/values-nb/translations.xml
index 1997298944..24594c782e 100644
--- a/libraries/ui-strings/src/main/res/values-nb/translations.xml
+++ b/libraries/ui-strings/src/main/res/values-nb/translations.xml
@@ -257,7 +257,9 @@
"Forbereder…"
"Retningslinjer for personvern"
"Privat rom"
+ "Privat område"
"Offentlig rom"
+ "Offentlig område"
"Reaksjon"
"Reaksjoner"
"Årsak"
@@ -274,6 +276,10 @@
"Rom"
"Romnavn"
"f.eks. prosjektnavnet ditt"
+
+ - "%1$d Rom"
+ - "%1$d Rom"
+
"Lagrede endringer"
"Lagrer"
"Skjermlås"
@@ -292,6 +298,10 @@
"Logger av"
"Noe gikk galt"
"Vi har støtt på et problem. Vennligst prøv igjen."
+
+ - "%1$d Område"
+ - "%1$d Områder"
+
"Starter chat…"
"Klistremerke"
"Suksess"
@@ -411,6 +421,9 @@ Er du sikker på at du vil fortsette?"
"Åpne i Google Maps"
"Åpne i OpenStreetMap"
"Del denne lokasjonen"
+ "Områder du har opprettet eller blitt med i."
+ "%1$s • %2$s"
+ "Områder"
"Meldingen ble ikke sendt fordi %1$ss verifiserte identitet er tilbakestilt."
"Meldingen ble ikke sendt fordi %1$s ikke har verifisert alle enheter."
"Meldingen ble ikke sendt fordi du ikke har verifisert en eller flere av enhetene dine."
diff --git a/libraries/ui-strings/src/main/res/values-pt/translations.xml b/libraries/ui-strings/src/main/res/values-pt/translations.xml
index 592c1f9961..0675f6e86d 100644
--- a/libraries/ui-strings/src/main/res/values-pt/translations.xml
+++ b/libraries/ui-strings/src/main/res/values-pt/translations.xml
@@ -2,6 +2,7 @@
"Adicionar reação: %1$s"
"Avatar"
+ "Minimizar campo de texto da mensagem"
"Eliminar"
- "%1$d dígito inserido"
@@ -10,6 +11,7 @@
"Editar avatar"
"O endereço completo será %1$s"
"Detalhes de cifragem"
+ "Expandir campo de texto da mensagem"
"Ocultar palavra-passe"
"Juntar-se à chamada"
"Saltar para o fundo"
@@ -40,7 +42,7 @@
"Remover reação com %1$s"
"Ícone da sala"
"Enviar ficheiros"
- "Necessária ação em tempo limitado"
+ "Necessária ação em tempo limitado, tens um minuto para verificares"
"Mostrar palavra-passe"
"Iniciar chamada"
"Sala antiga"
@@ -88,6 +90,7 @@
"Ativar"
"Fim da sondagem"
"Inserir PIN"
+ "Concluir"
"Esqueceu-se da palavra-passe?"
"Reencaminhar"
"Voltar"
@@ -162,10 +165,14 @@
"Atualização disponível"
"Sobre"
"Política de utilização aceitável"
+ "Adicionar conta"
+ "Adicionar outra conta"
"A adicionar legenda"
"Configurações avançadas"
"uma imagem"
"Recolha e análise de dados"
+ "Saíste da sala"
+ "A tua sessão foi terminada"
"Aparência"
"Áudio"
"Utilizadores bloqueados"
@@ -180,6 +187,7 @@
"Convite rejeitado"
"Escuro"
"Erro de decifragem"
+ "Descrição"
"Opções de programador"
"ID do dispositivo"
"Conversa direta"
@@ -246,7 +254,7 @@ Razão: %1$s."
"Permissão"
"Afixado"
"Por favor, verifica a tua ligação à internet"
- "Por favor, aguarde…"
+ "Por favor, aguarda…"
"Tens a certeza que queres concluir esta sondagem?"
"Sondagem: %1$s"
"Total de votos: %1$s"
@@ -289,18 +297,21 @@ Razão: %1$s."
"Resultados da pesquisa"
"Segurança"
"Vista por"
+ "Selecionar conta"
"Enviar para"
"A enviar…"
"Falha no envio"
"Enviada"
". "
"Servidor não suportado"
+ "Servidor indisponível"
"URL do servidor"
"Configurações"
"Localização partilhada"
"A terminar sessão"
"Algo correu mal"
"Encontramos um erro. Por favor, tenta novamente."
+ "Espaço"
- "%1$d espaço"
- "%1$d espaços"
@@ -370,6 +381,8 @@ Tens a certeza de que queres continuar?"
"O tamanho máximo de ficheiro permitido é: %1$s"
"Seleciona a qualidade do vídeo que pretendes carregar."
"Seleciona a qualidade de carregamento do vídeo"
+ "Pesquisar emojis"
+ "Já tens sessão iniciada como %1$s neste dispositivo."
"Seu homeserver precisa ser atualizado para suportar o Matrix Authentication Service e a criação de conta."
"Falha ao criar ligação permanente"
"%1$s não foi possível carregar o mapa. Por favor, tente novamente mais tarde."
@@ -385,7 +398,7 @@ Tens a certeza de que queres continuar?"
"Este endereço de sala já existe, tente editar o campo de endereço da sala ou altere o nome da sala"
"Alguns caracteres não são permitidos. Apenas letras, dígitos e os seguintes símbolos são suportados! $ & ‘ ( ) * + / ; = ? @ [ ] - . _"
"Algumas mensagens não foram enviadas"
- "Desculpe, ocorreu um erro"
+ "Pedimos desculpa, ocorreu um erro desconhecido"
"O remetente deste evento não é o dono do dispositivo que o enviou."
"A autenticidade desta mensagem cifrada não pode ser garantida neste dispositivo."
"Criptografado por um usuário verificado anteriormente."
diff --git a/libraries/ui-strings/src/main/res/values-uk/translations.xml b/libraries/ui-strings/src/main/res/values-uk/translations.xml
index dfd5c19053..1afd19dc3a 100644
--- a/libraries/ui-strings/src/main/res/values-uk/translations.xml
+++ b/libraries/ui-strings/src/main/res/values-uk/translations.xml
@@ -2,6 +2,7 @@
"Додати реакцію: %1$s"
"Аватар"
+ "Згорнути поле тексту повідомлення"
"Видалити"
- "Введена %1$d цифра"
@@ -11,6 +12,7 @@
"Редагувати аватар"
"Повна адреса буде %1$s"
"Подробиці шифрування"
+ "Розгорнути текстове поле повідомлення"
"Cховати пароль"
"Приєднатися до виклику"
"Перейти вниз"
@@ -42,7 +44,7 @@
"Прибрати реакцію %1$s"
"Аватар кімнати"
"Надіслати файли"
- "Необхідно виконати дію, обмежену в часі"
+ "Необхідно виконати дію, обмежену в часі, у вас є одна хвилина для верифікації"
"Показати пароль"
"Розпочати виклик"
"Кімната більше не використовується"
@@ -165,10 +167,14 @@
"Доступне оновлення"
"Відомості"
"Політика прийнятного використання"
+ "Додати обліковий запис"
+ "Додати ще один обліковий запис"
"Додавання підпису"
"Додаткові налаштування"
"зображення"
"Аналітика"
+ "Ви вийшли з кімнати"
+ "Ви вийшли з сеансу"
"Тема"
"Аудіо"
"Заблоковані користувачі"
@@ -297,6 +303,7 @@
"Результати пошуку"
"Безпека"
"Переглянули"
+ "Вибрати обліковий запис"
"Надіслати до"
"Надсилання…"
"Не вдалося надіслати"
@@ -380,6 +387,8 @@
"Максимально дозволений розмір файлу: %1$s"
"Виберіть якість відео, яке ви хочете вивантажити."
"Виберіть якість вивантажуваного відео"
+ "Пошук емодзі"
+ "Ви вже ввійшли на цьому пристрої як %1$s."
"Ваш домашній сервер потрібно оновити, щоб він підтримував службу автентифікації Matrix і створення облікових записів."
"Не вдалося створити постійне посилання"
"%1$s не може завантажити мапу. Повторіть спробу пізніше."
diff --git a/libraries/ui-strings/src/main/res/values-uz/translations.xml b/libraries/ui-strings/src/main/res/values-uz/translations.xml
index 80572fd534..4b6bb6a9f5 100644
--- a/libraries/ui-strings/src/main/res/values-uz/translations.xml
+++ b/libraries/ui-strings/src/main/res/values-uz/translations.xml
@@ -331,6 +331,7 @@ Sababi:%1$s."
"Ogohlantirish"
"Oʻzgarishlar saqlanmadi. Haqiqatan ham orqaga qaytmoqchimisiz?"
"O‘zgartirishlarni saqlaysizmi?"
+ "Matrix autentifikatsiya xizmati va hisob yaratish imkoniyatini qo‘llab-quvvatlash uchun uy serveringizni yangilash talab etiladi."
"Doimiy havola yaratilmadi"
"%1$sxaritani yuklay olmadi. Iltimos keyinroq qayta urinib ko\'ring."
"Xabarlar yuklanmadi"
diff --git a/libraries/ui-strings/src/main/res/values-zh-rTW/translations.xml b/libraries/ui-strings/src/main/res/values-zh-rTW/translations.xml
index fd3f6a13e0..93b486e173 100644
--- a/libraries/ui-strings/src/main/res/values-zh-rTW/translations.xml
+++ b/libraries/ui-strings/src/main/res/values-zh-rTW/translations.xml
@@ -2,6 +2,7 @@
"新增反應:%1$s"
"大頭貼"
+ "最小化訊息文字欄位"
"刪除"
- "已輸入 %1$d 個位數"
@@ -9,6 +10,7 @@
"編輯大頭照"
"完整地址為 %1$s"
"加密詳細資訊"
+ "展開訊息文字欄位"
"隱藏密碼"
"加入通話"
"跳至底部"
@@ -38,7 +40,7 @@
"移除反應 %1$s"
"聊天室大頭照"
"傳送檔案"
- "需要限時動作"
+ "需要限時動作,您有一分鐘可以驗證"
"顯示密碼"
"開始通話"
"墓碑聊天室"
@@ -86,6 +88,7 @@
"啟用"
"結束投票"
"輸入 PIN 碼"
+ "結束"
"忘記密碼?"
"轉寄"
"返回"
@@ -100,6 +103,7 @@
"離開"
"離開對話"
"離開聊天室"
+ "離開空間"
"載入更多"
"管理帳號"
"管理裝置"
@@ -160,10 +164,14 @@
"可升級"
"關於"
"可接受使用政策"
+ "新增帳號"
+ "新增其他帳號"
"新增標題"
"進階設定"
"影像"
"分析"
+ "您離開了聊天室"
+ "您已登出工作階段"
"外觀"
"音訊"
"封鎖的使用者"
@@ -175,9 +183,11 @@
"正在建立聊天室…"
"請求已取消"
"已離開聊天室"
+ "離開空間"
"邀請被拒絕"
"深色"
"解密錯誤"
+ "描述"
"開發者選項"
"裝置 ID"
"私訊"
@@ -282,18 +292,21 @@
"搜尋結果"
"安全性"
"已讀"
+ "選取帳號"
"傳送給"
"傳送中…"
"傳送失敗"
"已傳送"
". "
"伺服器不支援"
+ "無法連線至伺服器"
"伺服器 URL"
"設定"
"位置分享"
"正在登出"
"有錯誤發生"
"我們了遇到了問題。請再試一次。"
+ "空間"
- "%1$d 個空間"
@@ -327,6 +340,12 @@
"驗證身份"
"驗證使用者"
"影片"
+ "高品質"
+ "品質最佳但檔案較大"
+ "低品質"
+ "最快的上傳速度且檔案最小"
+ "標準品質"
+ "品質與上傳速度的平衡"
"語音訊息"
"等待中…"
"等待此則訊息"
@@ -341,6 +360,10 @@
您確定您想要繼續嗎?"
"仔細檢查此連結"
+ "選取您上傳的視訊預設品質。"
+ "視訊上傳品質"
+ "允許的最大檔案大小為:%1$s"
+ "檔案太大,無法上傳"
"聊天室已回報"
"回報並離開聊天室"
"確認"
@@ -349,6 +372,11 @@
"警告"
"變更尚未儲存,您確定要返回嗎?"
"是否儲存變更?"
+ "最大允許的檔案大小為:%1$s"
+ "選取您要上傳的視訊的品質。"
+ "選取視訊上傳品質"
+ "搜尋表情符號"
+ "您已在此裝置上以 %1$s 的身份登入。"
"您的家伺服器需要升級才能支援 Matrix Authentication Service 與帳號建立。"
"無法建立永久連結"
"%1$s無法載入地圖。請稍後再試。"
@@ -376,6 +404,9 @@
"嘿,來 %1$s 和我聊天:%2$s"
"%1$s Android"
"憤怒搖晃以回報臭蟲"
+ "這也會將您從此空間中的所有聊天室移除。"
+ "這也會將您從此空間中的所有聊天室移除,包含您是唯一管理員的聊天室:"
+ "離開 %1$s?"
"螢幕截圖"
"%1$s:%2$s"
"選項"
@@ -398,6 +429,7 @@
"未傳送您的訊息,因為 %1$s 尚未驗證所有裝置。"
"您的一個或多個裝置未經驗證。您仍可傳送訊息,也可以取消並在您驗證您的所有裝置後再試一次。"
"因為您尚未驗證一個或多個裝置,因為未傳送您的訊息"
+ "編輯管理員或擁有者"
"無法處理要上傳的媒體,請再試一次。"
"無法擷取使用者詳細資訊"
"%1$s 中的訊息"
diff --git a/libraries/ui-strings/src/main/res/values-zh/translations.xml b/libraries/ui-strings/src/main/res/values-zh/translations.xml
index 3b8fb6ae31..951675ce6d 100644
--- a/libraries/ui-strings/src/main/res/values-zh/translations.xml
+++ b/libraries/ui-strings/src/main/res/values-zh/translations.xml
@@ -40,7 +40,7 @@
"移除表情符号%1$s"
"房间头像"
"发送文件"
- "时限内必须完成的任务"
+ "限时操作,您有一分钟的时间来验证"
"显示密码"
"开始通话"
"墓碑聊天室"
@@ -163,6 +163,8 @@
"有可用升级"
"关于"
"可接受的使用政策"
+ "添加账户"
+ "添加另一个账户"
"添加标题"
"高级设置"
"一张图片"
@@ -183,6 +185,7 @@
"邀请已拒绝"
"深色"
"解密错误"
+ "描述"
"开发者选项"
"设备 ID"
"私聊"
@@ -287,6 +290,7 @@
"搜索结果"
"安全"
"已读"
+ "选择账户"
"发送至"
"正在发送…"
"发送失败"
@@ -368,6 +372,8 @@
"允许的最大文件大小为:%1$s"
"选择您要上传的视频的质量。"
"选择视频上传质量"
+ "搜索表情符号"
+ "您已在此设备以%1$s 身份登录。"
"您的服务器需要升级,以支持 Matrix 鉴权服务和账户创建。"
"创建固定链接失败"
"%1$s 无法加载地图,请稍后再试。"
diff --git a/libraries/ui-strings/src/main/res/values/localazy.xml b/libraries/ui-strings/src/main/res/values/localazy.xml
index c7694387a6..2e678e6c28 100644
--- a/libraries/ui-strings/src/main/res/values/localazy.xml
+++ b/libraries/ui-strings/src/main/res/values/localazy.xml
@@ -105,6 +105,7 @@
"Leave"
"Leave conversation"
"Leave room"
+ "Leave space"
"Load more"
"Manage account"
"Manage devices"
@@ -184,6 +185,7 @@
"Creating room…"
"Request canceled"
"Left room"
+ "Left space"
"Invite declined"
"Dark"
"Decryption error"
@@ -244,6 +246,7 @@ Reason: %1$s."
"%1$s (%2$s)"
"No results"
"No room name"
+ "No space name"
"Not encrypted"
"Offline"
"Open source licenses"
@@ -304,8 +307,10 @@ Reason: %1$s."
"Sent"
". "
"Server not supported"
+ "Server unreachable"
"Server URL"
"Settings"
+ "Share space"
"Shared location"
"Signing out"
"Something went wrong"
@@ -409,6 +414,9 @@ Are you sure you want to continue?"
"Hey, talk to me on %1$s: %2$s"
"%1$s Android"
"Rageshake to report bug"
+ "This will also remove you from all rooms in this space."
+ "This will also remove you from all rooms in this space, including those you’re the only administrator for:"
+ "Leave %1$s?"
"Screenshot"
"%1$s: %2$s"
"Options"
diff --git a/libraries/ui-utils/build.gradle.kts b/libraries/ui-utils/build.gradle.kts
index 62962fbcb4..95ce3d21a1 100644
--- a/libraries/ui-utils/build.gradle.kts
+++ b/libraries/ui-utils/build.gradle.kts
@@ -1,3 +1,5 @@
+import extension.testCommonDependencies
+
/*
* Copyright 2023, 2024 New Vector Ltd.
*
@@ -16,9 +18,6 @@ android {
implementation(projects.libraries.androidutils)
implementation(projects.services.toolbox.impl)
- testImplementation(libs.test.junit)
- testImplementation(libs.test.truth)
- testImplementation(libs.coroutines.test)
- testImplementation(libs.test.truth)
+ testCommonDependencies(libs)
}
}
diff --git a/libraries/usersearch/impl/build.gradle.kts b/libraries/usersearch/impl/build.gradle.kts
index 6498c3a44e..c7378aa07a 100644
--- a/libraries/usersearch/impl/build.gradle.kts
+++ b/libraries/usersearch/impl/build.gradle.kts
@@ -1,4 +1,5 @@
import extension.setupDependencyInjection
+import extension.testCommonDependencies
/*
* Copyright 2023, 2024 New Vector Ltd.
@@ -26,11 +27,7 @@ dependencies {
api(projects.libraries.usersearch.api)
implementation(libs.kotlinx.collections.immutable)
- testImplementation(libs.test.junit)
- testImplementation(libs.coroutines.test)
- testImplementation(libs.molecule.runtime)
- testImplementation(libs.test.truth)
- testImplementation(libs.test.turbine)
+ testCommonDependencies(libs)
testImplementation(projects.libraries.matrix.test)
testImplementation(projects.libraries.usersearch.test)
}
diff --git a/libraries/voiceplayer/impl/build.gradle.kts b/libraries/voiceplayer/impl/build.gradle.kts
index b512608a0d..053914d86b 100644
--- a/libraries/voiceplayer/impl/build.gradle.kts
+++ b/libraries/voiceplayer/impl/build.gradle.kts
@@ -1,4 +1,5 @@
import extension.setupDependencyInjection
+import extension.testCommonDependencies
/*
* Copyright 2024 New Vector Ltd.
@@ -30,15 +31,9 @@ dependencies {
implementation(libs.androidx.annotationjvm)
implementation(libs.coroutines.core)
- testImplementation(libs.molecule.runtime)
- testImplementation(libs.test.junit)
- testImplementation(libs.test.truth)
- testImplementation(libs.test.mockk)
- testImplementation(libs.test.turbine)
+ testCommonDependencies(libs)
testImplementation(libs.coroutines.core)
- testImplementation(libs.coroutines.test)
testImplementation(projects.libraries.matrix.test)
testImplementation(projects.libraries.mediaplayer.test)
testImplementation(projects.services.analytics.test)
- testImplementation(projects.tests.testutils)
}
diff --git a/libraries/voicerecorder/impl/build.gradle.kts b/libraries/voicerecorder/impl/build.gradle.kts
index 7a4ed8c294..a09106a8c3 100644
--- a/libraries/voicerecorder/impl/build.gradle.kts
+++ b/libraries/voicerecorder/impl/build.gradle.kts
@@ -1,4 +1,5 @@
import extension.setupDependencyInjection
+import extension.testCommonDependencies
/*
* Copyright 2023, 2024 New Vector Ltd.
@@ -28,11 +29,6 @@ dependencies {
implementation(libs.androidx.annotationjvm)
implementation(libs.coroutines.core)
- testImplementation(projects.tests.testutils)
- testImplementation(libs.test.junit)
- testImplementation(libs.test.truth)
- testImplementation(libs.test.mockk)
- testImplementation(libs.test.turbine)
+ testCommonDependencies(libs)
testImplementation(libs.coroutines.core)
- testImplementation(libs.coroutines.test)
}
diff --git a/libraries/wellknown/impl/build.gradle.kts b/libraries/wellknown/impl/build.gradle.kts
index 1d7927da57..4de8ecc0fd 100644
--- a/libraries/wellknown/impl/build.gradle.kts
+++ b/libraries/wellknown/impl/build.gradle.kts
@@ -1,4 +1,5 @@
import extension.setupDependencyInjection
+import extension.testCommonDependencies
/*
* Copyright 2025 New Vector Ltd.
@@ -31,12 +32,8 @@ dependencies {
implementation(projects.libraries.matrix.api)
implementation(projects.libraries.network)
- testImplementation(projects.tests.testutils)
- testImplementation(libs.test.junit)
- testImplementation(libs.test.truth)
- testImplementation(libs.test.robolectric)
+ testCommonDependencies(libs)
testImplementation(libs.coroutines.core)
- testImplementation(libs.coroutines.test)
testImplementation(projects.libraries.matrix.test)
testImplementation(projects.services.toolbox.test)
}
diff --git a/plugins/src/main/kotlin/Versions.kt b/plugins/src/main/kotlin/Versions.kt
index f02b468b6e..96a308f93f 100644
--- a/plugins/src/main/kotlin/Versions.kt
+++ b/plugins/src/main/kotlin/Versions.kt
@@ -13,9 +13,9 @@ import org.gradle.jvm.toolchain.JavaLanguageVersion
* Max versionCode allowed by the PlayStore (for information):
* 2_100_000_000
*
- * Also note that the versionCode is multiplied by 10 in app/build.gradle.kts#L168:
+ * Also note that the versionCode is multiplied by 10 in app/build.gradle.kts:
* ```
- * output.versionCode.set((output.versionCode.get() ?: 0) * 10 + abiCode))
+ * output.versionCode.set((output.versionCode.orNull ?: 0) * 10 + abiCode)
* ```
* We are using a CalVer-like approach to version the application. The version code is calculated as follows:
* - 2 digits for the year
@@ -28,27 +28,80 @@ import org.gradle.jvm.toolchain.JavaLanguageVersion
* - the version code: 20250100a (202_501_00a) where `a` stands for the architecture code
*/
+/**
+ * Year of the version on 2 digits.
+ * Do not update this value. it is updated by the release script.
+ */
private const val versionYear = 25
+
+/**
+ * Month of the version on 2 digits. Value must be in [1,12].
+ * Do not update this value. it is updated by the release script.
+ */
private const val versionMonth = 9
-// Note: must be in [0,99]
-private const val versionReleaseNumber = 1
+/**
+ * Release number in the month. Value must be in [0,99].
+ * Do not update this value. it is updated by the release script.
+ */
+private const val versionReleaseNumber = 2
object Versions {
+ /**
+ * Base version code that will be set in the Android Manifest.
+ * The value will be modified at build time to add the ABI code when APK are build.
+ * AAB will have a ABI code of 0.
+ * See comment above for the calculation method.
+ */
const val VERSION_CODE = (2000 + versionYear) * 10_000 + versionMonth * 100 + versionReleaseNumber
val VERSION_NAME = "$versionYear.${versionMonth.toString().padStart(2, '0')}.$versionReleaseNumber"
- // When updating COMPILE_SDK, please do not forget to update the value for `buildToolsVersion`
- // in the file `tools/release/release.sh`
+ /**
+ * Compile SDK version. Must be updated when a new Android version is released.
+ * When updating COMPILE_SDK, please also update BUILD_TOOLS_VERSION.
+ */
const val COMPILE_SDK = 36
+
+ /**
+ * Build tools version. Must be kept in sync with COMPILE_SDK.
+ * The value is used by the release script.
+ */
+ @Suppress("unused")
+ private const val BUILD_TOOLS_VERSION = "36.0.0"
+
+ /**
+ * Target SDK version. Should be kept up to date with COMPILE_SDK.
+ */
const val TARGET_SDK = 36
- // When updating the `minSdk`, make sure to update the value of `minSdkVersion` in the file `tools/release/release.sh`
+ /**
+ * Minimum SDK version for FOSS builds.
+ */
private const val MIN_SDK_FOSS = 24
+
+ /**
+ * Minimum SDK version for Enterprise builds.
+ */
private const val MIN_SDK_ENTERPRISE = 33
+
+ /**
+ * minSdkVersion that will be set in the Android Manifest.
+ */
val minSdk = if (isEnterpriseBuild) MIN_SDK_ENTERPRISE else MIN_SDK_FOSS
+ /**
+ * Java version used for compilation.
+ * Update this value when you want to use a newer Java version.
+ */
private const val JAVA_VERSION = 21
+
val javaVersion: JavaVersion = JavaVersion.toVersion(JAVA_VERSION)
val javaLanguageVersion: JavaLanguageVersion = JavaLanguageVersion.of(JAVA_VERSION)
+
+ // Perform some checks on the values to avoid releasing with bad values
+ init {
+ require(versionMonth in 1..12) { "versionMonth must be in [1,12]" }
+ require(versionReleaseNumber in 0..99) { "versionReleaseNumber must be in [0,99]" }
+ require(BUILD_TOOLS_VERSION.startsWith(COMPILE_SDK.toString())) { "When updating COMPILE_SDK, please also update BUILD_TOOLS_VERSION" }
+ }
}
diff --git a/plugins/src/main/kotlin/extension/DependencyHandleScope.kt b/plugins/src/main/kotlin/extension/DependencyHandleScope.kt
index 440f9d338b..2b6c531eda 100644
--- a/plugins/src/main/kotlin/extension/DependencyHandleScope.kt
+++ b/plugins/src/main/kotlin/extension/DependencyHandleScope.kt
@@ -19,6 +19,8 @@ import org.gradle.kotlin.dsl.closureOf
import org.gradle.kotlin.dsl.project
private fun DependencyHandlerScope.implementation(dependency: Any) = dependencies.add("implementation", dependency)
+private fun DependencyHandlerScope.testImplementation(dependency: Any) = dependencies.add("testImplementation", dependency)
+private fun DependencyHandlerScope.testReleaseImplementation(dependency: Any) = dependencies.add("testReleaseImplementation", dependency)
internal fun DependencyHandler.implementation(dependency: Any) = add("implementation", dependency)
// Implementation + config block
@@ -32,6 +34,30 @@ private fun DependencyHandlerScope.androidTestImplementation(dependency: Any) =
private fun DependencyHandlerScope.debugImplementation(dependency: Any) = dependencies.add("debugImplementation", dependency)
private fun DependencyHandlerScope.releaseImplementation(dependency: Any) = dependencies.add("releaseImplementation", dependency)
+/**
+ * Dependencies used for unit tests.
+ */
+fun DependencyHandlerScope.testCommonDependencies(
+ libs: LibrariesForLibs,
+ includeTestComposeView: Boolean = false,
+) {
+ testImplementation(libs.androidx.test.ext.junit)
+ testImplementation(libs.coroutines.test)
+ testImplementation(libs.molecule.runtime)
+ testImplementation(libs.test.appyx.junit)
+ testImplementation(libs.test.arch.core)
+ testImplementation(libs.test.junit)
+ testImplementation(libs.test.mockk)
+ testImplementation(libs.test.robolectric)
+ testImplementation(libs.test.truth)
+ testImplementation(libs.test.turbine)
+ testImplementation(project(":tests:testutils"))
+ if (includeTestComposeView) {
+ testImplementation(libs.androidx.compose.ui.test.junit)
+ testReleaseImplementation(libs.androidx.compose.ui.test.manifest)
+ }
+}
+
/**
* Dependencies used by all the modules
*/
diff --git a/plugins/src/main/kotlin/extension/locales.kt b/plugins/src/main/kotlin/extension/locales.kt
index 31d59b73b8..93431455a5 100644
--- a/plugins/src/main/kotlin/extension/locales.kt
+++ b/plugins/src/main/kotlin/extension/locales.kt
@@ -12,6 +12,7 @@ val locales = setOf(
"el",
"en",
"en-rUS",
+ "eo",
"es",
"et",
"eu",
diff --git a/screenshots/de/appnav.loggedin_LoggedInView_Day_2_de.png b/screenshots/de/appnav.loggedin_LoggedInView_Day_2_de.png
index 72abca606b..9d5c4e5c4e 100644
--- a/screenshots/de/appnav.loggedin_LoggedInView_Day_2_de.png
+++ b/screenshots/de/appnav.loggedin_LoggedInView_Day_2_de.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:3f8b7d3d94c01ccaf611b5fdb0fb8ea406c5c272d5eb9558cf80648a8f281917
-size 38180
+oid sha256:ec276c2ceeeb57006ff4ad5b45e772efe8240adf461297b92ddc1a70d52e1839
+size 38187
diff --git a/screenshots/de/appnav.root_RootView_Day_2_de.png b/screenshots/de/appnav.root_RootView_Day_2_de.png
index 456fea227e..51212b80c7 100644
--- a/screenshots/de/appnav.root_RootView_Day_2_de.png
+++ b/screenshots/de/appnav.root_RootView_Day_2_de.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:5c6b161fcc127ce493ad38d8e7b54ae7c4c588a2fba7c06cbf9a6b8f6a404921
-size 21806
+oid sha256:5cd2f0f141c1195c450c42d0d0af52db289162442527bb54127bb1b23f0c4333
+size 21781
diff --git a/screenshots/de/features.call.impl.ui_CallScreenView_Day_2_de.png b/screenshots/de/features.call.impl.ui_CallScreenView_Day_2_de.png
index 7cac8ad21d..f63cfd6ee8 100644
--- a/screenshots/de/features.call.impl.ui_CallScreenView_Day_2_de.png
+++ b/screenshots/de/features.call.impl.ui_CallScreenView_Day_2_de.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:3703e9876fcbf94befc13f8f7fc91c266fc0dea558f84288c612623d3a1cf63f
-size 11101
+oid sha256:4c16876ec7bd2b6823d16f23135ccabbcb0c85b860b467bfce0373e1f3db76cf
+size 11095
diff --git a/screenshots/de/features.call.impl.ui_CallScreenView_Day_3_de.png b/screenshots/de/features.call.impl.ui_CallScreenView_Day_3_de.png
index 82ac489296..d9d4d8cc4f 100644
--- a/screenshots/de/features.call.impl.ui_CallScreenView_Day_3_de.png
+++ b/screenshots/de/features.call.impl.ui_CallScreenView_Day_3_de.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:486f72ab9be5c85ec5710f2b463801066b57225dc3e707416d067385ea7bb31d
-size 19033
+oid sha256:ab0c61a6049caddac4880fc8605e169351af36f87cb16dbbeab3c5f7e9575796
+size 19029
diff --git a/screenshots/de/features.call.impl.ui_InvalidAudioDeviceDialog_Day_0_de.png b/screenshots/de/features.call.impl.ui_InvalidAudioDeviceDialog_Day_0_de.png
index def691ef78..616c9b651c 100644
--- a/screenshots/de/features.call.impl.ui_InvalidAudioDeviceDialog_Day_0_de.png
+++ b/screenshots/de/features.call.impl.ui_InvalidAudioDeviceDialog_Day_0_de.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:64dcd14f14ab5ec321f6988c459e6fb7b2675baa26864e6f5eae86b8e89509e2
-size 23452
+oid sha256:e959b0af86942bdf6680e3865f2d093644ce3f9a7b56bb7fe84c30c6e1639b27
+size 23454
diff --git a/screenshots/de/features.changeroommemberroles.impl_ChangeRolesView_Day_10_de.png b/screenshots/de/features.changeroommemberroles.impl_ChangeRolesView_Day_10_de.png
index 5ea694a14c..0e4b5b1562 100644
--- a/screenshots/de/features.changeroommemberroles.impl_ChangeRolesView_Day_10_de.png
+++ b/screenshots/de/features.changeroommemberroles.impl_ChangeRolesView_Day_10_de.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:48daacb9a588911cfde9968b837d9bd0a658b0004a0202b5b8b15a7a2394ce31
-size 53128
+oid sha256:12634dceaef537d5431771d900e476409d7efd4cca1d278c21ef424d609e0596
+size 53107
diff --git a/screenshots/de/features.createroom.impl.addpeople_AddPeopleView_Day_3_de.png b/screenshots/de/features.createroom.impl.addpeople_AddPeopleView_Day_3_de.png
new file mode 100644
index 0000000000..6a97b76076
--- /dev/null
+++ b/screenshots/de/features.createroom.impl.addpeople_AddPeopleView_Day_3_de.png
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:3b105f5a773cfc0d6992a311eeb7edb60faaac10d3747f96d094438e3ce62698
+size 12924
diff --git a/screenshots/de/features.home.impl.spaces_HomeSpaceItemView_Day_0_de.png b/screenshots/de/features.home.impl.spaces_HomeSpaceItemView_Day_0_de.png
deleted file mode 100644
index cf3596c54e..0000000000
--- a/screenshots/de/features.home.impl.spaces_HomeSpaceItemView_Day_0_de.png
+++ /dev/null
@@ -1,3 +0,0 @@
-version https://git-lfs.github.com/spec/v1
-oid sha256:2145d771b6f2634c89877feeefeb0bd2473495e676874186eb492cb163c1a26f
-size 14369
diff --git a/screenshots/de/features.home.impl.spaces_HomeSpaceItemView_Day_1_de.png b/screenshots/de/features.home.impl.spaces_HomeSpaceItemView_Day_1_de.png
deleted file mode 100644
index f83930a492..0000000000
--- a/screenshots/de/features.home.impl.spaces_HomeSpaceItemView_Day_1_de.png
+++ /dev/null
@@ -1,3 +0,0 @@
-version https://git-lfs.github.com/spec/v1
-oid sha256:d070f9a87e3ad6262e1cc8e8010f3af7a7f311710518f1247ca70737f1b86f19
-size 11628
diff --git a/screenshots/de/features.home.impl.spaces_HomeSpaceItemView_Day_2_de.png b/screenshots/de/features.home.impl.spaces_HomeSpaceItemView_Day_2_de.png
deleted file mode 100644
index d155bcfe5c..0000000000
--- a/screenshots/de/features.home.impl.spaces_HomeSpaceItemView_Day_2_de.png
+++ /dev/null
@@ -1,3 +0,0 @@
-version https://git-lfs.github.com/spec/v1
-oid sha256:6d09a459eb74ecda35bebbc01d22325056fca70b68b223d06c13ed817183e33a
-size 11720
diff --git a/screenshots/de/features.home.impl.spaces_HomeSpaceItemView_Day_3_de.png b/screenshots/de/features.home.impl.spaces_HomeSpaceItemView_Day_3_de.png
deleted file mode 100644
index 07864fae22..0000000000
--- a/screenshots/de/features.home.impl.spaces_HomeSpaceItemView_Day_3_de.png
+++ /dev/null
@@ -1,3 +0,0 @@
-version https://git-lfs.github.com/spec/v1
-oid sha256:669f10bedf9be832c40021e7b06d319433e63ac6d9ae9f635fd83ea57d3cb122
-size 20680
diff --git a/screenshots/de/features.home.impl.spaces_HomeSpaceItemView_Day_4_de.png b/screenshots/de/features.home.impl.spaces_HomeSpaceItemView_Day_4_de.png
deleted file mode 100644
index 6a9beadfb3..0000000000
--- a/screenshots/de/features.home.impl.spaces_HomeSpaceItemView_Day_4_de.png
+++ /dev/null
@@ -1,3 +0,0 @@
-version https://git-lfs.github.com/spec/v1
-oid sha256:9965b39e2477477d57c9692acaed40cb4574bbf39882ec58046e3e291a5d409b
-size 20584
diff --git a/screenshots/de/features.home.impl.spaces_HomeSpacesView_Day_0_de.png b/screenshots/de/features.home.impl.spaces_HomeSpacesView_Day_0_de.png
index 4b3eeca8e1..0f5f4cf56a 100644
--- a/screenshots/de/features.home.impl.spaces_HomeSpacesView_Day_0_de.png
+++ b/screenshots/de/features.home.impl.spaces_HomeSpacesView_Day_0_de.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:cba5963ddcd07cc4c68550dc046be6d528003b38086763a4dae07a8ea8cc08e9
-size 126188
+oid sha256:b13217ac65a45328a20c1bbb9ee6acb8f9a64ee85b8101118ae8d5a958a0104f
+size 109579
diff --git a/screenshots/de/features.invite.impl.acceptdecline_AcceptDeclineInviteView_Day_2_de.png b/screenshots/de/features.invite.impl.acceptdecline_AcceptDeclineInviteView_Day_2_de.png
index 7120d50aba..ecd9db7dbf 100644
--- a/screenshots/de/features.invite.impl.acceptdecline_AcceptDeclineInviteView_Day_2_de.png
+++ b/screenshots/de/features.invite.impl.acceptdecline_AcceptDeclineInviteView_Day_2_de.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:027df6bffe7bed2239c06b9225dd1facd4a66191e179c781d40581e3e8240fd2
-size 31657
+oid sha256:c139e49e6fb3c7aa0f94f2e391cf82160b0dec0609a899af1910522d972ed39f
+size 31633
diff --git a/screenshots/de/features.invite.impl.declineandblock_DeclineAndBlockView_Day_4_de.png b/screenshots/de/features.invite.impl.declineandblock_DeclineAndBlockView_Day_4_de.png
index 8ae544f54d..06c106589a 100644
--- a/screenshots/de/features.invite.impl.declineandblock_DeclineAndBlockView_Day_4_de.png
+++ b/screenshots/de/features.invite.impl.declineandblock_DeclineAndBlockView_Day_4_de.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:3351d9df8402ceab8898541e03a56a368e7acef293e718f5688725bf433323e5
-size 38646
+oid sha256:47ea6d76991c1a9d4dcd017186fc226150fe7f6fb0c3f772d9fe81c655f671fd
+size 38622
diff --git a/screenshots/de/features.invitepeople.impl_InvitePeopleView_Day_9_de.png b/screenshots/de/features.invitepeople.impl_InvitePeopleView_Day_9_de.png
new file mode 100644
index 0000000000..15bfd49357
--- /dev/null
+++ b/screenshots/de/features.invitepeople.impl_InvitePeopleView_Day_9_de.png
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:8590b5fd61453580add2dc93262f621b1dbefcff45ed9ef1004d0c5606c35dad
+size 21730
diff --git a/screenshots/de/features.joinroom.impl_JoinRoomView_Day_8_de.png b/screenshots/de/features.joinroom.impl_JoinRoomView_Day_8_de.png
index 1a93a3e94a..1e052632fd 100644
--- a/screenshots/de/features.joinroom.impl_JoinRoomView_Day_8_de.png
+++ b/screenshots/de/features.joinroom.impl_JoinRoomView_Day_8_de.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:3887ef896847361799a885eca9999f81bbbff641694d1647ffd6cb01f9bccd43
-size 33980
+oid sha256:c964465b659870b6ce5b32eab2ba8c19d0b078b06660c3f14faf6e54c029763d
+size 34001
diff --git a/screenshots/de/features.knockrequests.impl.list_KnockRequestsListView_Day_5_de.png b/screenshots/de/features.knockrequests.impl.list_KnockRequestsListView_Day_5_de.png
index 78a7c0c1bb..f739c629e1 100644
--- a/screenshots/de/features.knockrequests.impl.list_KnockRequestsListView_Day_5_de.png
+++ b/screenshots/de/features.knockrequests.impl.list_KnockRequestsListView_Day_5_de.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:e1bfab0ac55ce67f42d53c2e5b6d8a5d49fc0d047651546a1691886c5c421533
-size 48524
+oid sha256:cb4b0c5968cf1859485f0a88e836017ce640e9e7ecc5a8db31df0cd51012da99
+size 48479
diff --git a/screenshots/de/features.knockrequests.impl.list_KnockRequestsListView_Day_7_de.png b/screenshots/de/features.knockrequests.impl.list_KnockRequestsListView_Day_7_de.png
index 282335b1cb..60d8909107 100644
--- a/screenshots/de/features.knockrequests.impl.list_KnockRequestsListView_Day_7_de.png
+++ b/screenshots/de/features.knockrequests.impl.list_KnockRequestsListView_Day_7_de.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:394f8b666cb31923f088b6d101de754d613ff3d9cfef28066178af007333357e
-size 44373
+oid sha256:a7f9908bb1a05de0c4e97e830f9ee543deb29d8664cad5ae5a29a5a6cb5284d1
+size 44367
diff --git a/screenshots/de/features.leaveroom.impl_LeaveRoomView_Day_5_de.png b/screenshots/de/features.leaveroom.impl_LeaveRoomView_Day_5_de.png
index 2ea6aa11ca..6be223de8c 100644
--- a/screenshots/de/features.leaveroom.impl_LeaveRoomView_Day_5_de.png
+++ b/screenshots/de/features.leaveroom.impl_LeaveRoomView_Day_5_de.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:ccb6c4a8689c8c9c309ba64fef507ce14805392ec3aee5220d6ecd1e754994fc
-size 37579
+oid sha256:a66922765b357a16336992692aa74ff3d1e58868ab272008032332a66823a2ae
+size 37550
diff --git a/screenshots/de/features.lockscreen.impl.setup.pin_SetupPinView_Day_3_de.png b/screenshots/de/features.lockscreen.impl.setup.pin_SetupPinView_Day_3_de.png
index 022700f776..e67751b3c7 100644
--- a/screenshots/de/features.lockscreen.impl.setup.pin_SetupPinView_Day_3_de.png
+++ b/screenshots/de/features.lockscreen.impl.setup.pin_SetupPinView_Day_3_de.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:26e818df9c99d20c71acddb0a5697ffab3eebfa896e4ed24f79fbafd36bb9d5d
-size 27780
+oid sha256:339e4dc13f6074ca938d6752878b54752f6c9002c92ebf291136079579f85bd5
+size 27776
diff --git a/screenshots/de/features.lockscreen.impl.setup.pin_SetupPinView_Day_4_de.png b/screenshots/de/features.lockscreen.impl.setup.pin_SetupPinView_Day_4_de.png
index faf578f961..a7a98fafb1 100644
--- a/screenshots/de/features.lockscreen.impl.setup.pin_SetupPinView_Day_4_de.png
+++ b/screenshots/de/features.lockscreen.impl.setup.pin_SetupPinView_Day_4_de.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:e3c7051ef748dca1730dd0e5348709228e6950b3c2fa0e5a47a2609fbbb0c3bf
-size 32696
+oid sha256:fa5cf8e3bbd7116f1c8c27ac29d956929ed6a52e7b2b9a0cc425709ed83c3c1f
+size 32583
diff --git a/screenshots/de/features.lockscreen.impl.unlock_PinUnlockViewInApp_Day_7_de.png b/screenshots/de/features.lockscreen.impl.unlock_PinUnlockViewInApp_Day_7_de.png
index 2e632bab83..9e2974f594 100644
--- a/screenshots/de/features.lockscreen.impl.unlock_PinUnlockViewInApp_Day_7_de.png
+++ b/screenshots/de/features.lockscreen.impl.unlock_PinUnlockViewInApp_Day_7_de.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:d7ee6437ca7d096d5a2ba7171a4749015da77032b3a154d3fa5124870e6392fa
-size 25062
+oid sha256:02cbbc16f07b45feeb638195be476483d68dd652462f8b069a6e1492f66d0089
+size 25068
diff --git a/screenshots/de/features.lockscreen.impl.unlock_PinUnlockView_Day_7_de.png b/screenshots/de/features.lockscreen.impl.unlock_PinUnlockView_Day_7_de.png
index 93f749bbc9..9f22132175 100644
--- a/screenshots/de/features.lockscreen.impl.unlock_PinUnlockView_Day_7_de.png
+++ b/screenshots/de/features.lockscreen.impl.unlock_PinUnlockView_Day_7_de.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:a6ea7ae5ada8408bfae483241aa553a95cf3e4a5afe7a313942f07eabe2f32f3
+oid sha256:88c5747df737c777ca3e1fb039e6507489d2db418d46d970f25b7380ff0dfb40
size 32282
diff --git a/screenshots/de/features.login.impl.changeserver_ChangeServerView_Day_1_de.png b/screenshots/de/features.login.impl.changeserver_ChangeServerView_Day_1_de.png
index b23fe05d44..c856f0e358 100644
--- a/screenshots/de/features.login.impl.changeserver_ChangeServerView_Day_1_de.png
+++ b/screenshots/de/features.login.impl.changeserver_ChangeServerView_Day_1_de.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:628cc87a2c18dd8416ddfca2a7bde83f9254e79031bbfdbbb41663f3ebc6d0b4
-size 14401
+oid sha256:506f037d7cce42ac09efc89bff5d74475a723321af4713ed54a7caf85bfcb297
+size 14382
diff --git a/screenshots/de/features.login.impl.changeserver_ChangeServerView_Day_2_de.png b/screenshots/de/features.login.impl.changeserver_ChangeServerView_Day_2_de.png
index ac9a633cf2..52cb399536 100644
--- a/screenshots/de/features.login.impl.changeserver_ChangeServerView_Day_2_de.png
+++ b/screenshots/de/features.login.impl.changeserver_ChangeServerView_Day_2_de.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:f8bf0480dbcf1edd824649000e0c01d84047c85fa3e6f7d73a43d495ee78549f
-size 32391
+oid sha256:38bd30d45c29b9655f0e07e76c22d46b0e0ab5e3cce718bcdb135141a098332d
+size 32396
diff --git a/screenshots/de/features.login.impl.changeserver_ChangeServerView_Day_3_de.png b/screenshots/de/features.login.impl.changeserver_ChangeServerView_Day_3_de.png
index 3f09465793..a99f7380f6 100644
--- a/screenshots/de/features.login.impl.changeserver_ChangeServerView_Day_3_de.png
+++ b/screenshots/de/features.login.impl.changeserver_ChangeServerView_Day_3_de.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:9b5104c3f7bcb024b7ae93fa0da6c4f310ed791805fe276cf140028d84843bab
-size 16339
+oid sha256:16da7f89ea01252b4805da19a577c17be69890c45a5fd59f0d9cdadaed24be04
+size 16317
diff --git a/screenshots/de/features.login.impl.dialogs_SlidingSyncNotSupportedDialog_Day_0_de.png b/screenshots/de/features.login.impl.dialogs_SlidingSyncNotSupportedDialog_Day_0_de.png
index ac9a633cf2..52cb399536 100644
--- a/screenshots/de/features.login.impl.dialogs_SlidingSyncNotSupportedDialog_Day_0_de.png
+++ b/screenshots/de/features.login.impl.dialogs_SlidingSyncNotSupportedDialog_Day_0_de.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:f8bf0480dbcf1edd824649000e0c01d84047c85fa3e6f7d73a43d495ee78549f
-size 32391
+oid sha256:38bd30d45c29b9655f0e07e76c22d46b0e0ab5e3cce718bcdb135141a098332d
+size 32396
diff --git a/screenshots/de/features.login.impl.login_LoginModeView_Day_0_de.png b/screenshots/de/features.login.impl.login_LoginModeView_Day_0_de.png
index f7934c34d4..298de207db 100644
--- a/screenshots/de/features.login.impl.login_LoginModeView_Day_0_de.png
+++ b/screenshots/de/features.login.impl.login_LoginModeView_Day_0_de.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:89054d2e35f11086c392d5de2dd299a76803b07b7236e403bb41c18ae991e046
-size 37021
+oid sha256:01bb49eb69c81c2d00318aed7463436f500e7a69679c05003e468459b3563c94
+size 37005
diff --git a/screenshots/de/features.login.impl.login_LoginModeView_Day_1_de.png b/screenshots/de/features.login.impl.login_LoginModeView_Day_1_de.png
index 09833de090..97263af58c 100644
--- a/screenshots/de/features.login.impl.login_LoginModeView_Day_1_de.png
+++ b/screenshots/de/features.login.impl.login_LoginModeView_Day_1_de.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:c7ab2dc5a541481eb5e348772064a23668a481073ae7b97fb069df9b11f9597e
-size 10937
+oid sha256:cd7144624be51c4bc8a4d6d59c898fc50e8607f819c4c6c0bfe75100b9cc4c2d
+size 10932
diff --git a/screenshots/de/features.login.impl.login_LoginModeView_Day_3_de.png b/screenshots/de/features.login.impl.login_LoginModeView_Day_3_de.png
index 7617196945..683bef00b4 100644
--- a/screenshots/de/features.login.impl.login_LoginModeView_Day_3_de.png
+++ b/screenshots/de/features.login.impl.login_LoginModeView_Day_3_de.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:21dbf7e2c3c9fef115de119b26ac00872336d402e0680ba951f89f8b0555e2ef
-size 15807
+oid sha256:ab6bd357aaa6bfb530e596693f1c1454274784d53363525c5e8b89efd4599481
+size 15786
diff --git a/screenshots/de/features.login.impl.login_LoginModeView_Day_4_de.png b/screenshots/de/features.login.impl.login_LoginModeView_Day_4_de.png
index ac9a633cf2..52cb399536 100644
--- a/screenshots/de/features.login.impl.login_LoginModeView_Day_4_de.png
+++ b/screenshots/de/features.login.impl.login_LoginModeView_Day_4_de.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:f8bf0480dbcf1edd824649000e0c01d84047c85fa3e6f7d73a43d495ee78549f
-size 32391
+oid sha256:38bd30d45c29b9655f0e07e76c22d46b0e0ab5e3cce718bcdb135141a098332d
+size 32396
diff --git a/screenshots/de/features.login.impl.screens.confirmaccountprovider_ConfirmAccountProviderView_Day_2_de.png b/screenshots/de/features.login.impl.screens.confirmaccountprovider_ConfirmAccountProviderView_Day_2_de.png
index 32cb3a1eb2..49eb1c3e50 100644
--- a/screenshots/de/features.login.impl.screens.confirmaccountprovider_ConfirmAccountProviderView_Day_2_de.png
+++ b/screenshots/de/features.login.impl.screens.confirmaccountprovider_ConfirmAccountProviderView_Day_2_de.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:7a77db58d9c877002568d3554a43bae126c55249910c60f772d70c00eb64924e
-size 41262
+oid sha256:61d0f8e341e76fee533117b9724aec1e299519e7cff827d43b0977e7d6845ab9
+size 41284
diff --git a/screenshots/de/features.login.impl.screens.createaccount_CreateAccountView_Day_3_de.png b/screenshots/de/features.login.impl.screens.createaccount_CreateAccountView_Day_3_de.png
index e8d43eb741..61d358271f 100644
--- a/screenshots/de/features.login.impl.screens.createaccount_CreateAccountView_Day_3_de.png
+++ b/screenshots/de/features.login.impl.screens.createaccount_CreateAccountView_Day_3_de.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:bfbe1b69a417a3a08dd9864e1bc4f150538b36906bd06e0c571575f64fc7a058
-size 15585
+oid sha256:f55612c2279875c0d128d124097f6ed36378e16bf4d0a2ce27126e3f76b57147
+size 15587
diff --git a/screenshots/de/features.login.impl.screens.loginpassword_LoginPasswordView_Day_2_de.png b/screenshots/de/features.login.impl.screens.loginpassword_LoginPasswordView_Day_2_de.png
index b6252c50e3..8c48a80d25 100644
--- a/screenshots/de/features.login.impl.screens.loginpassword_LoginPasswordView_Day_2_de.png
+++ b/screenshots/de/features.login.impl.screens.loginpassword_LoginPasswordView_Day_2_de.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:c437e3747748e9421644cf1ff1988f27f685515ab2cf1c6913166b3455e03a10
-size 30421
+oid sha256:e73952f62b9f4addbf6c66e6929da91539a451660a6617ac53f995534726f52d
+size 30406
diff --git a/screenshots/de/features.logout.impl.direct_DefaultDirectLogoutView_Day_3_de.png b/screenshots/de/features.logout.impl.direct_DefaultDirectLogoutView_Day_3_de.png
index 460eb8cad4..251b8a0496 100644
--- a/screenshots/de/features.logout.impl.direct_DefaultDirectLogoutView_Day_3_de.png
+++ b/screenshots/de/features.logout.impl.direct_DefaultDirectLogoutView_Day_3_de.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:0f87747043f62847839dc9eb80a4011d555d230a1310edeaa2c8bf6395213313
-size 20660
+oid sha256:33601bf38dab409508b12c6f864d5529fdb24d17bd54caf50502abdfe4e04ea5
+size 20636
diff --git a/screenshots/de/features.logout.impl_AccountDeactivationView_Day_2_de.png b/screenshots/de/features.logout.impl_AccountDeactivationView_Day_2_de.png
index e74f9bd19a..52bed8eca4 100644
--- a/screenshots/de/features.logout.impl_AccountDeactivationView_Day_2_de.png
+++ b/screenshots/de/features.logout.impl_AccountDeactivationView_Day_2_de.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:9f3ec4d1f9787b011113b41f9868c0276784b3a9d7ce7a72d487950aa158d5b7
-size 79784
+oid sha256:1a9978fc6a551e92d64880cebac69380fa57cd793e790529db023111ea1f407c
+size 79754
diff --git a/screenshots/de/features.logout.impl_AccountDeactivationView_Day_4_de.png b/screenshots/de/features.logout.impl_AccountDeactivationView_Day_4_de.png
index b73d5d55f2..f53bb77866 100644
--- a/screenshots/de/features.logout.impl_AccountDeactivationView_Day_4_de.png
+++ b/screenshots/de/features.logout.impl_AccountDeactivationView_Day_4_de.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:6bbf2df2dda72fc32211778f075d00edfd47109e0fa87f5d694378a138e4c8ae
-size 61833
+oid sha256:df52787c1b88af53738293ee058b67ddd08f78c857c2e3af3f006d12626cd250
+size 61807
diff --git a/screenshots/de/features.logout.impl_LogoutView_Day_6_de.png b/screenshots/de/features.logout.impl_LogoutView_Day_6_de.png
index a63166bdd8..d97f248616 100644
--- a/screenshots/de/features.logout.impl_LogoutView_Day_6_de.png
+++ b/screenshots/de/features.logout.impl_LogoutView_Day_6_de.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:befa9251f01f28dd09063171f7c3dad4a3f1ed58026d5c1dbe718e39edf6982c
-size 27434
+oid sha256:dbb085f18507ad5448a6614bf2823879e7e6497a52eb9feb4265a3e717030b8f
+size 27420
diff --git a/screenshots/de/features.messages.impl.attachments.preview_AttachmentsView_5_de.png b/screenshots/de/features.messages.impl.attachments.preview_AttachmentsView_5_de.png
index 3cf9e4fb19..f2979cc741 100644
--- a/screenshots/de/features.messages.impl.attachments.preview_AttachmentsView_5_de.png
+++ b/screenshots/de/features.messages.impl.attachments.preview_AttachmentsView_5_de.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:c9be86c06161d58cf4204791eac435bad01c166edadf07f61ea5d9019f1a5dfb
-size 68306
+oid sha256:c06481e9cc1787ac90268137a145790eab9929690e162ef22e7e0b1d4796d368
+size 68291
diff --git a/screenshots/de/features.messages.impl.attachments.preview_AttachmentsView_6_de.png b/screenshots/de/features.messages.impl.attachments.preview_AttachmentsView_6_de.png
index 4e2bceba69..6d0ad528db 100644
--- a/screenshots/de/features.messages.impl.attachments.preview_AttachmentsView_6_de.png
+++ b/screenshots/de/features.messages.impl.attachments.preview_AttachmentsView_6_de.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:969b78ec1d869b7f06c4dec25176fe4bfcf9e6ae0522af6cb921df0d86c0240c
-size 72014
+oid sha256:5a1c8211e71e899ee932c6016e1d44eceb340a55727b72f5055a7a57ade3e6e5
+size 72017
diff --git a/screenshots/de/features.messages.impl.attachments.preview_AttachmentsView_8_de.png b/screenshots/de/features.messages.impl.attachments.preview_AttachmentsView_8_de.png
index 7f21f5ba9d..0366e56484 100644
--- a/screenshots/de/features.messages.impl.attachments.preview_AttachmentsView_8_de.png
+++ b/screenshots/de/features.messages.impl.attachments.preview_AttachmentsView_8_de.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:0dd36282dba9dadef788807726d9ee12d4d61e23c61dc0139ea812f20d96b696
-size 89662
+oid sha256:c356dd8df9ef8b414c68458828b20a709d55c3ffcd9010482c07e5e0ad501461
+size 89714
diff --git a/screenshots/de/features.messages.impl.attachments.preview_VideoQualitySelectorDialog_Day_0_de.png b/screenshots/de/features.messages.impl.attachments.preview_VideoQualitySelectorDialog_Day_0_de.png
index 8037f2e7fc..f614e6eac7 100644
--- a/screenshots/de/features.messages.impl.attachments.preview_VideoQualitySelectorDialog_Day_0_de.png
+++ b/screenshots/de/features.messages.impl.attachments.preview_VideoQualitySelectorDialog_Day_0_de.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:1c83af220914a1c29336486ef27e37581e663c8b7424f793ea4226f49b8c1114
-size 71882
+oid sha256:c71d15c6788611ecc0be5f75d64696d7bf68673f9c75c91d692358fedf219ba6
+size 71872
diff --git a/screenshots/de/features.messages.impl.forward_ForwardMessagesView_Day_3_de.png b/screenshots/de/features.messages.impl.forward_ForwardMessagesView_Day_3_de.png
index 415bf08603..9f006b50ca 100644
--- a/screenshots/de/features.messages.impl.forward_ForwardMessagesView_Day_3_de.png
+++ b/screenshots/de/features.messages.impl.forward_ForwardMessagesView_Day_3_de.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:a8077b421a93fb66d11503d75b558acda35947f5886c0f11d6b81dcf1c5e7653
+oid sha256:384eb7f0964c98a0f9f78085e7523086818f76c1d56e6750424cff515971e357
size 8681
diff --git a/screenshots/de/features.messages.impl.link_LinkView_Day_1_de.png b/screenshots/de/features.messages.impl.link_LinkView_Day_1_de.png
index cecc9c370f..659485fa9c 100644
--- a/screenshots/de/features.messages.impl.link_LinkView_Day_1_de.png
+++ b/screenshots/de/features.messages.impl.link_LinkView_Day_1_de.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:466a88dd4bcc7aa5666e248c0acf02e36d9a726754014c4c2353f4860a529ad0
-size 32255
+oid sha256:3acf4964ad6d685b5cef831d2397d46beb7f3de7cb1b062b07b513cf4bdf08a2
+size 32269
diff --git a/screenshots/de/features.messages.impl.pinned.list_PinnedMessagesListView_Day_0_de.png b/screenshots/de/features.messages.impl.pinned.list_PinnedMessagesListView_Day_0_de.png
index 859a4b74f3..358c0dff18 100644
--- a/screenshots/de/features.messages.impl.pinned.list_PinnedMessagesListView_Day_0_de.png
+++ b/screenshots/de/features.messages.impl.pinned.list_PinnedMessagesListView_Day_0_de.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:8cb6fbaa752a13e34a7d049b9cfd1048fa499d35cb99dca78ec3ea25f01a4251
-size 25033
+oid sha256:dd115b1d8b6b3d5c302d45110947cee2f9e5b1df9c6c6c7f24f750e1850e04af
+size 24976
diff --git a/screenshots/de/features.messages.impl.report_ReportMessageView_Day_4_de.png b/screenshots/de/features.messages.impl.report_ReportMessageView_Day_4_de.png
index 7906c74564..636abf3e9e 100644
--- a/screenshots/de/features.messages.impl.report_ReportMessageView_Day_4_de.png
+++ b/screenshots/de/features.messages.impl.report_ReportMessageView_Day_4_de.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:7ae11374f316fc309e9fb909a06d09c2a5781bf7f223acb0dcb33fdf1d9cfb3c
-size 28952
+oid sha256:4ff29d01ede74dd4bb73eaaf95969867ff27d25fc9123c81aa7746b4c660694c
+size 28941
diff --git a/screenshots/de/features.messages.impl.timeline.focus_FocusRequestStateView_Day_1_de.png b/screenshots/de/features.messages.impl.timeline.focus_FocusRequestStateView_Day_1_de.png
index 1cb1173b12..c53dd3597d 100644
--- a/screenshots/de/features.messages.impl.timeline.focus_FocusRequestStateView_Day_1_de.png
+++ b/screenshots/de/features.messages.impl.timeline.focus_FocusRequestStateView_Day_1_de.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:a83be835af4ba5220bc17d56e430b53b363df5a53e7f4a05fb34cb0e7e9487ff
-size 11513
+oid sha256:a0a43b9a921e9e6e3524f3830a4a6d8a0ac0a8185f60427146e0a683c1f68e5e
+size 11516
diff --git a/screenshots/de/features.messages.impl.timeline.focus_FocusRequestStateView_Day_2_de.png b/screenshots/de/features.messages.impl.timeline.focus_FocusRequestStateView_Day_2_de.png
index 1cb1173b12..c53dd3597d 100644
--- a/screenshots/de/features.messages.impl.timeline.focus_FocusRequestStateView_Day_2_de.png
+++ b/screenshots/de/features.messages.impl.timeline.focus_FocusRequestStateView_Day_2_de.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:a83be835af4ba5220bc17d56e430b53b363df5a53e7f4a05fb34cb0e7e9487ff
-size 11513
+oid sha256:a0a43b9a921e9e6e3524f3830a4a6d8a0ac0a8185f60427146e0a683c1f68e5e
+size 11516
diff --git a/screenshots/de/features.messages.impl.timeline.focus_FocusRequestStateView_Day_3_de.png b/screenshots/de/features.messages.impl.timeline.focus_FocusRequestStateView_Day_3_de.png
index b23fe05d44..c856f0e358 100644
--- a/screenshots/de/features.messages.impl.timeline.focus_FocusRequestStateView_Day_3_de.png
+++ b/screenshots/de/features.messages.impl.timeline.focus_FocusRequestStateView_Day_3_de.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:628cc87a2c18dd8416ddfca2a7bde83f9254e79031bbfdbbb41663f3ebc6d0b4
-size 14401
+oid sha256:506f037d7cce42ac09efc89bff5d74475a723321af4713ed54a7caf85bfcb297
+size 14382
diff --git a/screenshots/de/features.messages.impl_MessagesView_Day_9_de.png b/screenshots/de/features.messages.impl_MessagesView_Day_9_de.png
index 66f1d91843..93a2e19fca 100644
--- a/screenshots/de/features.messages.impl_MessagesView_Day_9_de.png
+++ b/screenshots/de/features.messages.impl_MessagesView_Day_9_de.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:d22db7b845a7fe310bcc6d8c57e95f32b1edfb9841f9785fd9f3dc261ad7f48c
-size 49579
+oid sha256:ceff1004db2bbe6cbdf2c6d62e4521b89a9c63823b6cd1c709037e3bae306302
+size 49568
diff --git a/screenshots/de/features.poll.impl.create_CreatePollView_Day_7_de.png b/screenshots/de/features.poll.impl.create_CreatePollView_Day_7_de.png
index e9dc52b6e5..48641b50c0 100644
--- a/screenshots/de/features.poll.impl.create_CreatePollView_Day_7_de.png
+++ b/screenshots/de/features.poll.impl.create_CreatePollView_Day_7_de.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:fab6aaceb328430d33609f68f43b6133fe532e700d43235e35cbe93f403aa9e0
-size 40841
+oid sha256:1fcf6e7dc35e868539efe503ed937d978ed75c5f3f46e4f19ab52dc3bec71303
+size 40813
diff --git a/screenshots/de/features.preferences.impl.advanced_VideoQualitySelectorDialog_Day_0_de.png b/screenshots/de/features.preferences.impl.advanced_VideoQualitySelectorDialog_Day_0_de.png
index f4ab27d051..b8ced31a50 100644
--- a/screenshots/de/features.preferences.impl.advanced_VideoQualitySelectorDialog_Day_0_de.png
+++ b/screenshots/de/features.preferences.impl.advanced_VideoQualitySelectorDialog_Day_0_de.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:da9077d093d852068db6a0c20aebf8e76ecdb64114b64b3f2db6020e8a9602f1
-size 62455
+oid sha256:8e9642babd75110581efedcf740f42d800dd8b93ff63707cf54ec273a23e6ce5
+size 62459
diff --git a/screenshots/de/features.preferences.impl.notifications.edit_EditDefaultNotificationSettingView_Day_3_de.png b/screenshots/de/features.preferences.impl.notifications.edit_EditDefaultNotificationSettingView_Day_3_de.png
index c91f3101bc..b447e6eb76 100644
--- a/screenshots/de/features.preferences.impl.notifications.edit_EditDefaultNotificationSettingView_Day_3_de.png
+++ b/screenshots/de/features.preferences.impl.notifications.edit_EditDefaultNotificationSettingView_Day_3_de.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:a856144e5645d4624b888be7b7a0b2d7be3f40b86e01893347f700dc0e1f0acb
-size 41411
+oid sha256:d5130de6e57ac0b4ada7b7a7de549cb08c1a1b48ac64cc05ab39f8d2efb41680
+size 41413
diff --git a/screenshots/de/features.preferences.impl.notifications_NotificationSettingsView_Day_11_de.png b/screenshots/de/features.preferences.impl.notifications_NotificationSettingsView_Day_11_de.png
index ae4eae6136..5837583cf1 100644
--- a/screenshots/de/features.preferences.impl.notifications_NotificationSettingsView_Day_11_de.png
+++ b/screenshots/de/features.preferences.impl.notifications_NotificationSettingsView_Day_11_de.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:33e046c38a374200a1cd8143d2d8ecb9b28fab08d58a9207df5f48d26bc6a61c
-size 42847
+oid sha256:bc683b3b8b0b3ffa9da10e505559f98b2faef0dd85523d2bf21faa32956d9483
+size 42832
diff --git a/screenshots/de/features.preferences.impl.notifications_NotificationSettingsView_Day_3_de.png b/screenshots/de/features.preferences.impl.notifications_NotificationSettingsView_Day_3_de.png
index caeba08e69..589bdcabc5 100644
--- a/screenshots/de/features.preferences.impl.notifications_NotificationSettingsView_Day_3_de.png
+++ b/screenshots/de/features.preferences.impl.notifications_NotificationSettingsView_Day_3_de.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:bab5d7148aa93d93279ba04125814702664ffc272d29e5c7288661a2fe45d4b7
-size 50021
+oid sha256:3b8df24928cda90d3e29186034cf088ebbe37a75b99e7ac8132f515e339a6bc2
+size 50019
diff --git a/screenshots/de/features.preferences.impl.notifications_NotificationSettingsView_Day_4_de.png b/screenshots/de/features.preferences.impl.notifications_NotificationSettingsView_Day_4_de.png
index caeba08e69..589bdcabc5 100644
--- a/screenshots/de/features.preferences.impl.notifications_NotificationSettingsView_Day_4_de.png
+++ b/screenshots/de/features.preferences.impl.notifications_NotificationSettingsView_Day_4_de.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:bab5d7148aa93d93279ba04125814702664ffc272d29e5c7288661a2fe45d4b7
-size 50021
+oid sha256:3b8df24928cda90d3e29186034cf088ebbe37a75b99e7ac8132f515e339a6bc2
+size 50019
diff --git a/screenshots/de/features.preferences.impl.notifications_NotificationSettingsView_Day_6_de.png b/screenshots/de/features.preferences.impl.notifications_NotificationSettingsView_Day_6_de.png
index f695529b11..0fc4259316 100644
--- a/screenshots/de/features.preferences.impl.notifications_NotificationSettingsView_Day_6_de.png
+++ b/screenshots/de/features.preferences.impl.notifications_NotificationSettingsView_Day_6_de.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:8a62180a7f7ac07a75fbb73bb31a085c22c621b1d14db125ebaaa163f457d172
-size 47160
+oid sha256:b83ce1b120f5eca77007f7f7d957bdd3c45135f5f3e454ec68c50564924373f3
+size 47163
diff --git a/screenshots/de/features.preferences.impl.notifications_NotificationSettingsView_Day_7_de.png b/screenshots/de/features.preferences.impl.notifications_NotificationSettingsView_Day_7_de.png
index afa048c458..663000bae6 100644
--- a/screenshots/de/features.preferences.impl.notifications_NotificationSettingsView_Day_7_de.png
+++ b/screenshots/de/features.preferences.impl.notifications_NotificationSettingsView_Day_7_de.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:4932d9acbe99d45c9b1886817eae52cbc4c4d978476020d4c229d5d5d2893980
-size 52303
+oid sha256:633b2df37189860357e7a98285f57c098e580d61cb82fdf274055e7559865a9b
+size 52264
diff --git a/screenshots/de/features.rageshake.impl.bugreport_BugReportView_Day_4_de.png b/screenshots/de/features.rageshake.impl.bugreport_BugReportView_Day_4_de.png
index cdcf00cf53..66088d0cd9 100644
--- a/screenshots/de/features.rageshake.impl.bugreport_BugReportView_Day_4_de.png
+++ b/screenshots/de/features.rageshake.impl.bugreport_BugReportView_Day_4_de.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:7def84e736b71aa50b6da5ebe2a959e54c4bef83e5d13477e1e1143e7cc3aa1c
-size 57643
+oid sha256:bce0a946397aa0223be195fc0090b6bf009ed02a914879840bc445b271a37a32
+size 57646
diff --git a/screenshots/de/features.reportroom.impl_ReportRoomView_Day_4_de.png b/screenshots/de/features.reportroom.impl_ReportRoomView_Day_4_de.png
index efb5e3c53f..dc2fd86233 100644
--- a/screenshots/de/features.reportroom.impl_ReportRoomView_Day_4_de.png
+++ b/screenshots/de/features.reportroom.impl_ReportRoomView_Day_4_de.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:4141c28d59cbc731c96f9625a0fed478d3ee18a3b0498a69f50f952b66f4053e
-size 32018
+oid sha256:43c3083501e9fa128a2eab0896829f1a37ac673111d2ac7cbc3886ee1a02f884
+size 32001
diff --git a/screenshots/de/features.roomaliasresolver.impl_RoomAliasResolverView_Day_1_de.png b/screenshots/de/features.roomaliasresolver.impl_RoomAliasResolverView_Day_1_de.png
index 1a93a3e94a..1e052632fd 100644
--- a/screenshots/de/features.roomaliasresolver.impl_RoomAliasResolverView_Day_1_de.png
+++ b/screenshots/de/features.roomaliasresolver.impl_RoomAliasResolverView_Day_1_de.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:3887ef896847361799a885eca9999f81bbbff641694d1647ffd6cb01f9bccd43
-size 33980
+oid sha256:c964465b659870b6ce5b32eab2ba8c19d0b078b06660c3f14faf6e54c029763d
+size 34001
diff --git a/screenshots/de/features.roomaliasresolver.impl_RoomAliasResolverView_Day_2_de.png b/screenshots/de/features.roomaliasresolver.impl_RoomAliasResolverView_Day_2_de.png
index a61ad50520..17ecc2d044 100644
--- a/screenshots/de/features.roomaliasresolver.impl_RoomAliasResolverView_Day_2_de.png
+++ b/screenshots/de/features.roomaliasresolver.impl_RoomAliasResolverView_Day_2_de.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:c18619e7ba34ada5b6bef1ef552c522fa1c031f148cbf36649206a1df0eba5bd
-size 25568
+oid sha256:7010c3f8fcd3863d07a97ea8e07be0ce65f9a9d232b46c99888bade57462e9a6
+size 25589
diff --git a/screenshots/de/features.roomdetails.impl.edit_RoomDetailsEditView_Day_7_de.png b/screenshots/de/features.roomdetails.impl.edit_RoomDetailsEditView_Day_7_de.png
index f7618097ad..87677b8e2d 100644
--- a/screenshots/de/features.roomdetails.impl.edit_RoomDetailsEditView_Day_7_de.png
+++ b/screenshots/de/features.roomdetails.impl.edit_RoomDetailsEditView_Day_7_de.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:c0df2d9b9be192f42a172633cd07cd4686a699f12609aef93afb5d1e8a6d86cc
-size 29762
+oid sha256:445db5ce8ac1d90129d2e53be3074f0c8d4518374355833c0ce3579fa9ff3394
+size 29761
diff --git a/screenshots/de/features.roomdetails.impl.invite_RoomInviteMembersView_Day_3_de.png b/screenshots/de/features.roomdetails.impl.invite_RoomInviteMembersView_Day_3_de.png
new file mode 100644
index 0000000000..949ec34d43
--- /dev/null
+++ b/screenshots/de/features.roomdetails.impl.invite_RoomInviteMembersView_Day_3_de.png
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:b580adefe5d563c71caaaf17639b84b7e6c8f5eda5c3d154cce9a5176ed7825e
+size 24822
diff --git a/screenshots/de/features.roomdetails.impl.notificationsettings_RoomNotificationSettingsView_Day_3_de.png b/screenshots/de/features.roomdetails.impl.notificationsettings_RoomNotificationSettingsView_Day_3_de.png
index e0dd7601dd..8a3190e8a6 100644
--- a/screenshots/de/features.roomdetails.impl.notificationsettings_RoomNotificationSettingsView_Day_3_de.png
+++ b/screenshots/de/features.roomdetails.impl.notificationsettings_RoomNotificationSettingsView_Day_3_de.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:6182b842f646b7eda109f9e411a9a8f2a1dd8e7b807bf4239acf608426f1fa0f
-size 42647
+oid sha256:bb7aae1df2a4cbfbda74c6c8812198140e54f12b7798af9a1a90500616b05595
+size 42653
diff --git a/screenshots/de/features.roomdetails.impl.notificationsettings_RoomNotificationSettingsView_Day_5_de.png b/screenshots/de/features.roomdetails.impl.notificationsettings_RoomNotificationSettingsView_Day_5_de.png
index e0dd7601dd..8a3190e8a6 100644
--- a/screenshots/de/features.roomdetails.impl.notificationsettings_RoomNotificationSettingsView_Day_5_de.png
+++ b/screenshots/de/features.roomdetails.impl.notificationsettings_RoomNotificationSettingsView_Day_5_de.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:6182b842f646b7eda109f9e411a9a8f2a1dd8e7b807bf4239acf608426f1fa0f
-size 42647
+oid sha256:bb7aae1df2a4cbfbda74c6c8812198140e54f12b7798af9a1a90500616b05595
+size 42653
diff --git a/screenshots/de/features.roomdetails.impl.rolesandpermissions.permissions_ChangeRoomPermissionsView_Day_5_de.png b/screenshots/de/features.roomdetails.impl.rolesandpermissions.permissions_ChangeRoomPermissionsView_Day_5_de.png
index d7b6fca2bc..68d5d0381f 100644
--- a/screenshots/de/features.roomdetails.impl.rolesandpermissions.permissions_ChangeRoomPermissionsView_Day_5_de.png
+++ b/screenshots/de/features.roomdetails.impl.rolesandpermissions.permissions_ChangeRoomPermissionsView_Day_5_de.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:a527d0177803a96bc7ae717caa9c2ca4e96f35e1da0fec42e0e6bb825132e80c
-size 38849
+oid sha256:f6b9b30eecec15ac0adf1ba18dc578553770e228c944d928dc87bb308ad66a95
+size 38846
diff --git a/screenshots/de/features.roomdetails.impl.rolesandpermissions_RolesAndPermissionsView_Day_4_de.png b/screenshots/de/features.roomdetails.impl.rolesandpermissions_RolesAndPermissionsView_Day_4_de.png
index bf8522617d..2540918855 100644
--- a/screenshots/de/features.roomdetails.impl.rolesandpermissions_RolesAndPermissionsView_Day_4_de.png
+++ b/screenshots/de/features.roomdetails.impl.rolesandpermissions_RolesAndPermissionsView_Day_4_de.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:8766a94b51ec53c8330ce901394d3fe4a92f7f736ffa617ff63e1c4511197f43
-size 43946
+oid sha256:638d958fa225877f475feb357c0d839fef8a05b876238522c9750a8b90b23358
+size 43922
diff --git a/screenshots/de/features.roomdetails.impl.rolesandpermissions_RolesAndPermissionsView_Day_5_de.png b/screenshots/de/features.roomdetails.impl.rolesandpermissions_RolesAndPermissionsView_Day_5_de.png
index 96b8936d53..a61d4381bc 100644
--- a/screenshots/de/features.roomdetails.impl.rolesandpermissions_RolesAndPermissionsView_Day_5_de.png
+++ b/screenshots/de/features.roomdetails.impl.rolesandpermissions_RolesAndPermissionsView_Day_5_de.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:ce62f7f62d097fdfc85ef2c409e6abbcce0f320aa1fa458f0622b039b3e03bfe
-size 56504
+oid sha256:89d4726d9deb408e2a7fac1a71ad487b154faa9735131bd1fcbd64d0587746bc
+size 56525
diff --git a/screenshots/de/features.roomdetails.impl.rolesandpermissions_RolesAndPermissionsView_Day_7_de.png b/screenshots/de/features.roomdetails.impl.rolesandpermissions_RolesAndPermissionsView_Day_7_de.png
index b47952d037..23571dc46c 100644
--- a/screenshots/de/features.roomdetails.impl.rolesandpermissions_RolesAndPermissionsView_Day_7_de.png
+++ b/screenshots/de/features.roomdetails.impl.rolesandpermissions_RolesAndPermissionsView_Day_7_de.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:22d8c6b59b409a01ebdaa24b65cd3516d411e118d40fbb9576064e9d6a06d730
+oid sha256:c60eaa6e529c230303960d0fa3ca03eec6c010bef06bb6a46db2d1241472a312
size 43377
diff --git a/screenshots/de/features.roomdetails.impl.securityandprivacy_SecurityAndPrivacyViewDark_7_de.png b/screenshots/de/features.roomdetails.impl.securityandprivacy_SecurityAndPrivacyViewDark_7_de.png
index 56a7a11055..c8d111b76e 100644
--- a/screenshots/de/features.roomdetails.impl.securityandprivacy_SecurityAndPrivacyViewDark_7_de.png
+++ b/screenshots/de/features.roomdetails.impl.securityandprivacy_SecurityAndPrivacyViewDark_7_de.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:421174f28f650d589613e7bbad4f46541e88cd67c9e4aed789f136b900fc61ad
-size 50030
+oid sha256:d685380e4b4ec9634ceab25bb989dda305000bbc63d388d308584ce9be41e900
+size 50034
diff --git a/screenshots/de/features.roomdetails.impl.securityandprivacy_SecurityAndPrivacyViewLight_7_de.png b/screenshots/de/features.roomdetails.impl.securityandprivacy_SecurityAndPrivacyViewLight_7_de.png
index 43ed134364..63c9d2f2ec 100644
--- a/screenshots/de/features.roomdetails.impl.securityandprivacy_SecurityAndPrivacyViewLight_7_de.png
+++ b/screenshots/de/features.roomdetails.impl.securityandprivacy_SecurityAndPrivacyViewLight_7_de.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:25d8ecbc9477f4baa755cf01530bb3f5ad95832a6c14cd49beb3a41ee5f9f5f7
-size 52366
+oid sha256:9322e1e84b86d8deeb0ff07ce296847c54d620901fa072fbe5321c1197fac16e
+size 52370
diff --git a/screenshots/de/features.roommembermoderation.impl_RoomMemberModerationView_Day_4_de.png b/screenshots/de/features.roommembermoderation.impl_RoomMemberModerationView_Day_4_de.png
index fd881fdd55..f11c344ae6 100644
--- a/screenshots/de/features.roommembermoderation.impl_RoomMemberModerationView_Day_4_de.png
+++ b/screenshots/de/features.roommembermoderation.impl_RoomMemberModerationView_Day_4_de.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:f1f142e1a18779649d19d7c031b8de83f359c36a4e1a6225e13edccf773102c5
-size 31609
+oid sha256:6dd52f4b17d3ff94b4d61db544fddfb8b449da49673ecb45a02fa297966b52f6
+size 31604
diff --git a/screenshots/de/features.roommembermoderation.impl_RoomMemberModerationView_Day_6_de.png b/screenshots/de/features.roommembermoderation.impl_RoomMemberModerationView_Day_6_de.png
index 5e7a0b3ee0..9a626deaab 100644
--- a/screenshots/de/features.roommembermoderation.impl_RoomMemberModerationView_Day_6_de.png
+++ b/screenshots/de/features.roommembermoderation.impl_RoomMemberModerationView_Day_6_de.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:3cfc2b6376f8d8f1a20befd2b7817e5eab0a9612f3fce05290ddc5cccdade39f
-size 32124
+oid sha256:5037873ed63f558691c06a63f93eca0d22dd2ec1f70aec2dcbf9481e73d16412
+size 32099
diff --git a/screenshots/de/features.securebackup.impl.disable_SecureBackupDisableView_Day_3_de.png b/screenshots/de/features.securebackup.impl.disable_SecureBackupDisableView_Day_3_de.png
index f327c1d5d0..ff25ff9a77 100644
--- a/screenshots/de/features.securebackup.impl.disable_SecureBackupDisableView_Day_3_de.png
+++ b/screenshots/de/features.securebackup.impl.disable_SecureBackupDisableView_Day_3_de.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:6837012d8b4863b5bbcdca3e2e7a038a0df2723767d54bbb3394f010e66751e3
-size 46045
+oid sha256:e3f99c41bdd09088037a6fc0e7436f71867e679e2d4f829156cf774cf5c06ec8
+size 46051
diff --git a/screenshots/de/features.securebackup.impl.enter_SecureBackupEnterRecoveryKeyView_Day_3_de.png b/screenshots/de/features.securebackup.impl.enter_SecureBackupEnterRecoveryKeyView_Day_3_de.png
index 23d60c8cb6..c2cfc1532c 100644
--- a/screenshots/de/features.securebackup.impl.enter_SecureBackupEnterRecoveryKeyView_Day_3_de.png
+++ b/screenshots/de/features.securebackup.impl.enter_SecureBackupEnterRecoveryKeyView_Day_3_de.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:4b100deda7d2a421e3d57183b17d0d5d07f4a5c791774e7f57edfc02d8d00d99
-size 51026
+oid sha256:05096ace3fae4368464a78816164680ebecf5a65b03eb9bc6fc6eb06a0a43d81
+size 50930
diff --git a/screenshots/de/features.securebackup.impl.reset.root_ResetIdentityRootView_Day_1_de.png b/screenshots/de/features.securebackup.impl.reset.root_ResetIdentityRootView_Day_1_de.png
index be93620283..45e32ffc99 100644
--- a/screenshots/de/features.securebackup.impl.reset.root_ResetIdentityRootView_Day_1_de.png
+++ b/screenshots/de/features.securebackup.impl.reset.root_ResetIdentityRootView_Day_1_de.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:aa1e4b41b792ffd847e06bfa66cf4c6aa1e0f74af84562ba2943b7ccd7b92831
-size 50160
+oid sha256:a1468fd52b8e3448bd1f8e0f3791c574565adddeda13ea8a13b2332e132522d6
+size 50128
diff --git a/screenshots/de/features.securebackup.impl.root_SecureBackupRootView_Day_6_de.png b/screenshots/de/features.securebackup.impl.root_SecureBackupRootView_Day_6_de.png
index 755c6f633b..f36902ec07 100644
--- a/screenshots/de/features.securebackup.impl.root_SecureBackupRootView_Day_6_de.png
+++ b/screenshots/de/features.securebackup.impl.root_SecureBackupRootView_Day_6_de.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:b3a4d53926428ea875ba03831aaa63e499235ecfc420e3f0232653e7262221c8
-size 42153
+oid sha256:818f5f1d73b601d026f513387d76e67628142609412c0afa055d530be94db263
+size 42157
diff --git a/screenshots/de/features.securebackup.impl.setup_SecureBackupSetupViewChange_Day_4_de.png b/screenshots/de/features.securebackup.impl.setup_SecureBackupSetupViewChange_Day_4_de.png
index 1499406151..d58496d0b3 100644
--- a/screenshots/de/features.securebackup.impl.setup_SecureBackupSetupViewChange_Day_4_de.png
+++ b/screenshots/de/features.securebackup.impl.setup_SecureBackupSetupViewChange_Day_4_de.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:4236d65528a408e142bee3d102fa697ec46f2279da0a3faab60b8601bfd85368
-size 51489
+oid sha256:edc3adcd73285dbaf217485d9e296a1af1ef592d65baca1fcf6ed75700d17eb3
+size 51568
diff --git a/screenshots/de/features.securebackup.impl.setup_SecureBackupSetupView_Day_4_de.png b/screenshots/de/features.securebackup.impl.setup_SecureBackupSetupView_Day_4_de.png
index 1499406151..d58496d0b3 100644
--- a/screenshots/de/features.securebackup.impl.setup_SecureBackupSetupView_Day_4_de.png
+++ b/screenshots/de/features.securebackup.impl.setup_SecureBackupSetupView_Day_4_de.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:4236d65528a408e142bee3d102fa697ec46f2279da0a3faab60b8601bfd85368
-size 51489
+oid sha256:edc3adcd73285dbaf217485d9e296a1af1ef592d65baca1fcf6ed75700d17eb3
+size 51568
diff --git a/screenshots/de/features.share.impl_ShareView_Day_3_de.png b/screenshots/de/features.share.impl_ShareView_Day_3_de.png
index 415bf08603..9f006b50ca 100644
--- a/screenshots/de/features.share.impl_ShareView_Day_3_de.png
+++ b/screenshots/de/features.share.impl_ShareView_Day_3_de.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:a8077b421a93fb66d11503d75b558acda35947f5886c0f11d6b81dcf1c5e7653
+oid sha256:384eb7f0964c98a0f9f78085e7523086818f76c1d56e6750424cff515971e357
size 8681
diff --git a/screenshots/de/features.space.impl_SpaceView_Day_2_de.png b/screenshots/de/features.space.impl_SpaceView_Day_2_de.png
new file mode 100644
index 0000000000..dfbfac62d4
--- /dev/null
+++ b/screenshots/de/features.space.impl_SpaceView_Day_2_de.png
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:c300acd3609d5f5c2b9b641d84dff196c3d44973a270b89f12919dced5b1ff91
+size 47339
diff --git a/screenshots/de/features.space.impl_SpaceView_Day_3_de.png b/screenshots/de/features.space.impl_SpaceView_Day_3_de.png
new file mode 100644
index 0000000000..2823c4d3e3
--- /dev/null
+++ b/screenshots/de/features.space.impl_SpaceView_Day_3_de.png
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:c471588072bc12721ae792976ddbbb756206aacd1e2bdfb91f58e79b3f458b1f
+size 46103
diff --git a/screenshots/de/features.startchat.impl.root_StartChatView_Day_2_de.png b/screenshots/de/features.startchat.impl.root_StartChatView_Day_2_de.png
index cb7209b068..60aa2ae9c2 100644
--- a/screenshots/de/features.startchat.impl.root_StartChatView_Day_2_de.png
+++ b/screenshots/de/features.startchat.impl.root_StartChatView_Day_2_de.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:8b070f5671759396846a0796cb94307a429724318a74277a388839e79cb5c5e4
-size 31873
+oid sha256:dbda304432217316c4cc028d98e6394619c9279a261a004466bd5ddf640f994f
+size 31853
diff --git a/screenshots/de/libraries.designsystem.components.async_AsyncActionView_Day_3_de.png b/screenshots/de/libraries.designsystem.components.async_AsyncActionView_Day_3_de.png
index 40bb8c6698..ce4f4013b5 100644
--- a/screenshots/de/libraries.designsystem.components.async_AsyncActionView_Day_3_de.png
+++ b/screenshots/de/libraries.designsystem.components.async_AsyncActionView_Day_3_de.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:0e7f87cbe57ac1f64685dff9df668d30311898b045596b3f2c928c3606ea129c
+oid sha256:1b891e2217b77873c9f33f8377a0a1643a9e461e5ec4e67b817494194f4ec60c
size 10478
diff --git a/screenshots/de/libraries.designsystem.components.dialogs_ErrorDialogContent_Dialogs_de.png b/screenshots/de/libraries.designsystem.components.dialogs_ErrorDialogContent_Dialogs_de.png
index fa50461695..80fce53231 100644
--- a/screenshots/de/libraries.designsystem.components.dialogs_ErrorDialogContent_Dialogs_de.png
+++ b/screenshots/de/libraries.designsystem.components.dialogs_ErrorDialogContent_Dialogs_de.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:674db98a0ff8dd9628b19583bf671b8eb7eefa13f3475525e14c8a61a5e05591
-size 14286
+oid sha256:490e87db0101dcf91fe86568322cacae54b657bd66de955e0dbbff2f5402396e
+size 14285
diff --git a/screenshots/de/libraries.designsystem.components.dialogs_ErrorDialogWithDoNotShowAgain_Day_0_de.png b/screenshots/de/libraries.designsystem.components.dialogs_ErrorDialogWithDoNotShowAgain_Day_0_de.png
index 1b305a5b9d..a43d60ba7c 100644
--- a/screenshots/de/libraries.designsystem.components.dialogs_ErrorDialogWithDoNotShowAgain_Day_0_de.png
+++ b/screenshots/de/libraries.designsystem.components.dialogs_ErrorDialogWithDoNotShowAgain_Day_0_de.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:1e601b48a4db352012a7ce171f1ea6cf1e2241224dbec2944e9367e617348a86
-size 12864
+oid sha256:c1b59d7d1c8541af79bd99b45d5c4e7f0d17179c2f5a8f1c2feb694f92225c37
+size 12855
diff --git a/screenshots/de/libraries.designsystem.components.dialogs_ErrorDialog_Day_0_de.png b/screenshots/de/libraries.designsystem.components.dialogs_ErrorDialog_Day_0_de.png
index bb113d1f29..61c16505c5 100644
--- a/screenshots/de/libraries.designsystem.components.dialogs_ErrorDialog_Day_0_de.png
+++ b/screenshots/de/libraries.designsystem.components.dialogs_ErrorDialog_Day_0_de.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:5bc1577f7e5d3125cd432cbc346803c81e9c4f24813241f90bc0542a0b2e5aa6
-size 9278
+oid sha256:16421610dab7afeaa01e67e1b48d5cff9e516d4bead702381fd00d3dfe75cd90
+size 9280
diff --git a/screenshots/de/libraries.designsystem.components.dialogs_RetryDialogContent_Dialogs_de.png b/screenshots/de/libraries.designsystem.components.dialogs_RetryDialogContent_Dialogs_de.png
index 2958d50ac6..448999910f 100644
--- a/screenshots/de/libraries.designsystem.components.dialogs_RetryDialogContent_Dialogs_de.png
+++ b/screenshots/de/libraries.designsystem.components.dialogs_RetryDialogContent_Dialogs_de.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:f9494488876263418a4c86505482910776062277385924f69e1dcb468d474991
-size 25944
+oid sha256:09ea44484d7dbedf8c37888360df25910f6cf03eb80924f5018500ade17c53c6
+size 25978
diff --git a/screenshots/de/libraries.designsystem.components.dialogs_RetryDialog_Day_0_de.png b/screenshots/de/libraries.designsystem.components.dialogs_RetryDialog_Day_0_de.png
index ae23a0e725..78a751b5c4 100644
--- a/screenshots/de/libraries.designsystem.components.dialogs_RetryDialog_Day_0_de.png
+++ b/screenshots/de/libraries.designsystem.components.dialogs_RetryDialog_Day_0_de.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:46767b660cc867c2a3a264c35ff8d1b91593ee0b888dcf4a40c67361c36b5a74
-size 15358
+oid sha256:dd9c051d47ffb1b91684e919796363b8d206fd2f2ab715a95ebb0e8e7e6000ca
+size 15348
diff --git a/screenshots/de/libraries.designsystem.components_ProgressDialogWithContent_Day_0_de.png b/screenshots/de/libraries.designsystem.components_ProgressDialogWithContent_Day_0_de.png
new file mode 100644
index 0000000000..72dc113ce5
--- /dev/null
+++ b/screenshots/de/libraries.designsystem.components_ProgressDialogWithContent_Day_0_de.png
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:8b110f2913fbdf487b46e92fec76ed372d7f89cab582d1ea9abb3fbaa2cd041f
+size 12317
diff --git a/screenshots/de/libraries.mediaviewer.impl.viewer_MediaViewerView_2_de.png b/screenshots/de/libraries.mediaviewer.impl.viewer_MediaViewerView_2_de.png
index 4b6d14cdb7..39dedcbc2a 100644
--- a/screenshots/de/libraries.mediaviewer.impl.viewer_MediaViewerView_2_de.png
+++ b/screenshots/de/libraries.mediaviewer.impl.viewer_MediaViewerView_2_de.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:7c88b10eeb0b787624d12e653d4b7037cdc42b90a91c40ea23ab7b661af03625
-size 45999
+oid sha256:3d6bc0b609f19136a6bdf9752d399047aac63f26e88bea363d823b5273f1657d
+size 45992
diff --git a/screenshots/de/libraries.permissions.api_PermissionsView_Day_0_de.png b/screenshots/de/libraries.permissions.api_PermissionsView_Day_0_de.png
index 0da1cc8f31..60c2b48abf 100644
--- a/screenshots/de/libraries.permissions.api_PermissionsView_Day_0_de.png
+++ b/screenshots/de/libraries.permissions.api_PermissionsView_Day_0_de.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:ae922c3c9d531b7efc833804397263c0ab182288cd1f712a34cb6bb99f63d6c6
-size 30865
+oid sha256:206efed2c6d28aab43b1588113335574e671a388e948d8de9a0ae63c0372c06a
+size 30922
diff --git a/screenshots/de/libraries.permissions.api_PermissionsView_Day_1_de.png b/screenshots/de/libraries.permissions.api_PermissionsView_Day_1_de.png
index 53296f56b0..e874e82876 100644
--- a/screenshots/de/libraries.permissions.api_PermissionsView_Day_1_de.png
+++ b/screenshots/de/libraries.permissions.api_PermissionsView_Day_1_de.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:3aedcb2b94763b33f5b360655276af85913636850ce1afa43b22037b43475258
-size 30795
+oid sha256:284912820f3cc73c1067d45580f7bc07c743f2a21ab96842609f4b57ccc14fc6
+size 30861
diff --git a/screenshots/de/libraries.permissions.api_PermissionsView_Day_2_de.png b/screenshots/de/libraries.permissions.api_PermissionsView_Day_2_de.png
index a6acef7c27..28037f69cb 100644
--- a/screenshots/de/libraries.permissions.api_PermissionsView_Day_2_de.png
+++ b/screenshots/de/libraries.permissions.api_PermissionsView_Day_2_de.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:ca3b5c81ccb5a13945fe584f98746313d3050468aa9bf46f7bbdb44266996374
-size 29623
+oid sha256:7d977bd436da02de2a76a0037e0704ba9878919b53dc502d963d6b6b8c9a9237
+size 29671
diff --git a/screenshots/de/libraries.permissions.api_PermissionsView_Day_3_de.png b/screenshots/de/libraries.permissions.api_PermissionsView_Day_3_de.png
index b3041ab22d..63e70d9fe8 100644
--- a/screenshots/de/libraries.permissions.api_PermissionsView_Day_3_de.png
+++ b/screenshots/de/libraries.permissions.api_PermissionsView_Day_3_de.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:a31fbffb7529b127443b4a52651cae6b0a525b2ec2ded82eb19c390eae4953cf
-size 24256
+oid sha256:f7390a48f7e11f4e907c89beedb1250c43312c63cc9ad54b2f9983e5f3fcb675
+size 24176
diff --git a/screenshots/de/services.apperror.impl_AppErrorView_Day_0_de.png b/screenshots/de/services.apperror.impl_AppErrorView_Day_0_de.png
index 9116a57f72..f446c5ac38 100644
--- a/screenshots/de/services.apperror.impl_AppErrorView_Day_0_de.png
+++ b/screenshots/de/services.apperror.impl_AppErrorView_Day_0_de.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:26388ccf8c8d78a991bd46f39983536be27a1093d354436cfd3df466a414496b
-size 19558
+oid sha256:43272bd940257366c0ac035787b1603fa5bd3903e67760a262c289a4e8ffb4e3
+size 19531
diff --git a/screenshots/html/data.js b/screenshots/html/data.js
index 9592a58fae..d4e0ce58b9 100644
--- a/screenshots/html/data.js
+++ b/screenshots/html/data.js
@@ -1,76 +1,77 @@
// Generated file, do not edit
export const screenshots = [
["en","en-dark","de",],
-["features.preferences.impl.about_AboutView_Day_0_en","features.preferences.impl.about_AboutView_Night_0_en",20336,],
+["features.preferences.impl.about_AboutView_Day_0_en","features.preferences.impl.about_AboutView_Night_0_en",20350,],
["features.invite.impl.acceptdecline_AcceptDeclineInviteView_Day_0_en","features.invite.impl.acceptdecline_AcceptDeclineInviteView_Night_0_en",0,],
-["features.invite.impl.acceptdecline_AcceptDeclineInviteView_Day_1_en","features.invite.impl.acceptdecline_AcceptDeclineInviteView_Night_1_en",20336,],
-["features.invite.impl.acceptdecline_AcceptDeclineInviteView_Day_2_en","features.invite.impl.acceptdecline_AcceptDeclineInviteView_Night_2_en",20336,],
-["features.invite.impl.acceptdecline_AcceptDeclineInviteView_Day_3_en","features.invite.impl.acceptdecline_AcceptDeclineInviteView_Night_3_en",20336,],
-["features.invite.impl.acceptdecline_AcceptDeclineInviteView_Day_4_en","features.invite.impl.acceptdecline_AcceptDeclineInviteView_Night_4_en",20336,],
-["features.invite.impl.acceptdecline_AcceptDeclineInviteView_Day_5_en","features.invite.impl.acceptdecline_AcceptDeclineInviteView_Night_5_en",20336,],
-["features.logout.impl_AccountDeactivationView_Day_0_en","features.logout.impl_AccountDeactivationView_Night_0_en",20336,],
-["features.logout.impl_AccountDeactivationView_Day_1_en","features.logout.impl_AccountDeactivationView_Night_1_en",20336,],
-["features.logout.impl_AccountDeactivationView_Day_2_en","features.logout.impl_AccountDeactivationView_Night_2_en",20336,],
-["features.logout.impl_AccountDeactivationView_Day_3_en","features.logout.impl_AccountDeactivationView_Night_3_en",20336,],
-["features.logout.impl_AccountDeactivationView_Day_4_en","features.logout.impl_AccountDeactivationView_Night_4_en",20336,],
-["features.login.impl.accountprovider_AccountProviderOtherView_Day_0_en","features.login.impl.accountprovider_AccountProviderOtherView_Night_0_en",20336,],
+["features.invite.impl.acceptdecline_AcceptDeclineInviteView_Day_1_en","features.invite.impl.acceptdecline_AcceptDeclineInviteView_Night_1_en",20350,],
+["features.invite.impl.acceptdecline_AcceptDeclineInviteView_Day_2_en","features.invite.impl.acceptdecline_AcceptDeclineInviteView_Night_2_en",20350,],
+["features.invite.impl.acceptdecline_AcceptDeclineInviteView_Day_3_en","features.invite.impl.acceptdecline_AcceptDeclineInviteView_Night_3_en",20350,],
+["features.invite.impl.acceptdecline_AcceptDeclineInviteView_Day_4_en","features.invite.impl.acceptdecline_AcceptDeclineInviteView_Night_4_en",20350,],
+["features.invite.impl.acceptdecline_AcceptDeclineInviteView_Day_5_en","features.invite.impl.acceptdecline_AcceptDeclineInviteView_Night_5_en",20350,],
+["features.logout.impl_AccountDeactivationView_Day_0_en","features.logout.impl_AccountDeactivationView_Night_0_en",20350,],
+["features.logout.impl_AccountDeactivationView_Day_1_en","features.logout.impl_AccountDeactivationView_Night_1_en",20350,],
+["features.logout.impl_AccountDeactivationView_Day_2_en","features.logout.impl_AccountDeactivationView_Night_2_en",20350,],
+["features.logout.impl_AccountDeactivationView_Day_3_en","features.logout.impl_AccountDeactivationView_Night_3_en",20350,],
+["features.logout.impl_AccountDeactivationView_Day_4_en","features.logout.impl_AccountDeactivationView_Night_4_en",20350,],
+["features.login.impl.accountprovider_AccountProviderOtherView_Day_0_en","features.login.impl.accountprovider_AccountProviderOtherView_Night_0_en",20350,],
["features.login.impl.accountprovider_AccountProviderView_Day_0_en","features.login.impl.accountprovider_AccountProviderView_Night_0_en",0,],
["features.login.impl.accountprovider_AccountProviderView_Day_1_en","features.login.impl.accountprovider_AccountProviderView_Night_1_en",0,],
["features.login.impl.accountprovider_AccountProviderView_Day_2_en","features.login.impl.accountprovider_AccountProviderView_Night_2_en",0,],
["features.login.impl.accountprovider_AccountProviderView_Day_3_en","features.login.impl.accountprovider_AccountProviderView_Night_3_en",0,],
["features.messages.impl.actionlist_ActionListViewContent_Day_0_en","features.messages.impl.actionlist_ActionListViewContent_Night_0_en",0,],
-["features.messages.impl.actionlist_ActionListViewContent_Day_10_en","features.messages.impl.actionlist_ActionListViewContent_Night_10_en",20336,],
-["features.messages.impl.actionlist_ActionListViewContent_Day_11_en","features.messages.impl.actionlist_ActionListViewContent_Night_11_en",20336,],
-["features.messages.impl.actionlist_ActionListViewContent_Day_12_en","features.messages.impl.actionlist_ActionListViewContent_Night_12_en",20336,],
+["features.messages.impl.actionlist_ActionListViewContent_Day_10_en","features.messages.impl.actionlist_ActionListViewContent_Night_10_en",20350,],
+["features.messages.impl.actionlist_ActionListViewContent_Day_11_en","features.messages.impl.actionlist_ActionListViewContent_Night_11_en",20350,],
+["features.messages.impl.actionlist_ActionListViewContent_Day_12_en","features.messages.impl.actionlist_ActionListViewContent_Night_12_en",20350,],
["features.messages.impl.actionlist_ActionListViewContent_Day_1_en","features.messages.impl.actionlist_ActionListViewContent_Night_1_en",0,],
-["features.messages.impl.actionlist_ActionListViewContent_Day_2_en","features.messages.impl.actionlist_ActionListViewContent_Night_2_en",20336,],
-["features.messages.impl.actionlist_ActionListViewContent_Day_3_en","features.messages.impl.actionlist_ActionListViewContent_Night_3_en",20336,],
-["features.messages.impl.actionlist_ActionListViewContent_Day_4_en","features.messages.impl.actionlist_ActionListViewContent_Night_4_en",20336,],
-["features.messages.impl.actionlist_ActionListViewContent_Day_5_en","features.messages.impl.actionlist_ActionListViewContent_Night_5_en",20336,],
-["features.messages.impl.actionlist_ActionListViewContent_Day_6_en","features.messages.impl.actionlist_ActionListViewContent_Night_6_en",20336,],
-["features.messages.impl.actionlist_ActionListViewContent_Day_7_en","features.messages.impl.actionlist_ActionListViewContent_Night_7_en",20336,],
-["features.messages.impl.actionlist_ActionListViewContent_Day_8_en","features.messages.impl.actionlist_ActionListViewContent_Night_8_en",20336,],
-["features.messages.impl.actionlist_ActionListViewContent_Day_9_en","features.messages.impl.actionlist_ActionListViewContent_Night_9_en",20336,],
-["features.createroom.impl.addpeople_AddPeopleView_Day_0_en","features.createroom.impl.addpeople_AddPeopleView_Night_0_en",20336,],
-["features.createroom.impl.addpeople_AddPeopleView_Day_1_en","features.createroom.impl.addpeople_AddPeopleView_Night_1_en",20336,],
-["features.createroom.impl.addpeople_AddPeopleView_Day_2_en","features.createroom.impl.addpeople_AddPeopleView_Night_2_en",20336,],
-["features.preferences.impl.advanced_AdvancedSettingsViewDark_0_en","",20336,],
-["features.preferences.impl.advanced_AdvancedSettingsViewDark_1_en","",20336,],
-["features.preferences.impl.advanced_AdvancedSettingsViewDark_2_en","",20336,],
-["features.preferences.impl.advanced_AdvancedSettingsViewDark_3_en","",20336,],
-["features.preferences.impl.advanced_AdvancedSettingsViewDark_4_en","",20336,],
-["features.preferences.impl.advanced_AdvancedSettingsViewDark_5_en","",20336,],
-["features.preferences.impl.advanced_AdvancedSettingsViewDark_6_en","",20336,],
-["features.preferences.impl.advanced_AdvancedSettingsViewDark_7_en","",20336,],
-["features.preferences.impl.advanced_AdvancedSettingsViewDark_8_en","",20336,],
-["features.preferences.impl.advanced_AdvancedSettingsViewLight_0_en","",20336,],
-["features.preferences.impl.advanced_AdvancedSettingsViewLight_1_en","",20336,],
-["features.preferences.impl.advanced_AdvancedSettingsViewLight_2_en","",20336,],
-["features.preferences.impl.advanced_AdvancedSettingsViewLight_3_en","",20336,],
-["features.preferences.impl.advanced_AdvancedSettingsViewLight_4_en","",20336,],
-["features.preferences.impl.advanced_AdvancedSettingsViewLight_5_en","",20336,],
-["features.preferences.impl.advanced_AdvancedSettingsViewLight_6_en","",20336,],
-["features.preferences.impl.advanced_AdvancedSettingsViewLight_7_en","",20336,],
-["features.preferences.impl.advanced_AdvancedSettingsViewLight_8_en","",20336,],
-["libraries.designsystem.components.dialogs_AlertDialogContent_Dialogs_en","",20336,],
-["libraries.designsystem.components.dialogs_AlertDialog_Day_0_en","libraries.designsystem.components.dialogs_AlertDialog_Night_0_en",20336,],
-["features.analytics.impl_AnalyticsOptInView_Day_0_en","features.analytics.impl_AnalyticsOptInView_Night_0_en",20336,],
-["features.analytics.impl_AnalyticsOptInView_Day_1_en","features.analytics.impl_AnalyticsOptInView_Night_1_en",20336,],
-["features.analytics.api.preferences_AnalyticsPreferencesView_Day_0_en","features.analytics.api.preferences_AnalyticsPreferencesView_Night_0_en",20336,],
-["features.analytics.api.preferences_AnalyticsPreferencesView_Day_1_en","features.analytics.api.preferences_AnalyticsPreferencesView_Night_1_en",20336,],
-["features.preferences.impl.analytics_AnalyticsSettingsView_Day_0_en","features.preferences.impl.analytics_AnalyticsSettingsView_Night_0_en",20336,],
+["features.messages.impl.actionlist_ActionListViewContent_Day_2_en","features.messages.impl.actionlist_ActionListViewContent_Night_2_en",20350,],
+["features.messages.impl.actionlist_ActionListViewContent_Day_3_en","features.messages.impl.actionlist_ActionListViewContent_Night_3_en",20350,],
+["features.messages.impl.actionlist_ActionListViewContent_Day_4_en","features.messages.impl.actionlist_ActionListViewContent_Night_4_en",20350,],
+["features.messages.impl.actionlist_ActionListViewContent_Day_5_en","features.messages.impl.actionlist_ActionListViewContent_Night_5_en",20350,],
+["features.messages.impl.actionlist_ActionListViewContent_Day_6_en","features.messages.impl.actionlist_ActionListViewContent_Night_6_en",20350,],
+["features.messages.impl.actionlist_ActionListViewContent_Day_7_en","features.messages.impl.actionlist_ActionListViewContent_Night_7_en",20350,],
+["features.messages.impl.actionlist_ActionListViewContent_Day_8_en","features.messages.impl.actionlist_ActionListViewContent_Night_8_en",20350,],
+["features.messages.impl.actionlist_ActionListViewContent_Day_9_en","features.messages.impl.actionlist_ActionListViewContent_Night_9_en",20350,],
+["features.createroom.impl.addpeople_AddPeopleView_Day_0_en","features.createroom.impl.addpeople_AddPeopleView_Night_0_en",20350,],
+["features.createroom.impl.addpeople_AddPeopleView_Day_1_en","features.createroom.impl.addpeople_AddPeopleView_Night_1_en",20350,],
+["features.createroom.impl.addpeople_AddPeopleView_Day_2_en","features.createroom.impl.addpeople_AddPeopleView_Night_2_en",20350,],
+["features.createroom.impl.addpeople_AddPeopleView_Day_3_en","features.createroom.impl.addpeople_AddPeopleView_Night_3_en",20350,],
+["features.preferences.impl.advanced_AdvancedSettingsViewDark_0_en","",20350,],
+["features.preferences.impl.advanced_AdvancedSettingsViewDark_1_en","",20350,],
+["features.preferences.impl.advanced_AdvancedSettingsViewDark_2_en","",20350,],
+["features.preferences.impl.advanced_AdvancedSettingsViewDark_3_en","",20350,],
+["features.preferences.impl.advanced_AdvancedSettingsViewDark_4_en","",20350,],
+["features.preferences.impl.advanced_AdvancedSettingsViewDark_5_en","",20350,],
+["features.preferences.impl.advanced_AdvancedSettingsViewDark_6_en","",20350,],
+["features.preferences.impl.advanced_AdvancedSettingsViewDark_7_en","",20350,],
+["features.preferences.impl.advanced_AdvancedSettingsViewDark_8_en","",20350,],
+["features.preferences.impl.advanced_AdvancedSettingsViewLight_0_en","",20350,],
+["features.preferences.impl.advanced_AdvancedSettingsViewLight_1_en","",20350,],
+["features.preferences.impl.advanced_AdvancedSettingsViewLight_2_en","",20350,],
+["features.preferences.impl.advanced_AdvancedSettingsViewLight_3_en","",20350,],
+["features.preferences.impl.advanced_AdvancedSettingsViewLight_4_en","",20350,],
+["features.preferences.impl.advanced_AdvancedSettingsViewLight_5_en","",20350,],
+["features.preferences.impl.advanced_AdvancedSettingsViewLight_6_en","",20350,],
+["features.preferences.impl.advanced_AdvancedSettingsViewLight_7_en","",20350,],
+["features.preferences.impl.advanced_AdvancedSettingsViewLight_8_en","",20350,],
+["libraries.designsystem.components.dialogs_AlertDialogContent_Dialogs_en","",20350,],
+["libraries.designsystem.components.dialogs_AlertDialog_Day_0_en","libraries.designsystem.components.dialogs_AlertDialog_Night_0_en",20350,],
+["features.analytics.impl_AnalyticsOptInView_Day_0_en","features.analytics.impl_AnalyticsOptInView_Night_0_en",20350,],
+["features.analytics.impl_AnalyticsOptInView_Day_1_en","features.analytics.impl_AnalyticsOptInView_Night_1_en",20350,],
+["features.analytics.api.preferences_AnalyticsPreferencesView_Day_0_en","features.analytics.api.preferences_AnalyticsPreferencesView_Night_0_en",20350,],
+["features.analytics.api.preferences_AnalyticsPreferencesView_Day_1_en","features.analytics.api.preferences_AnalyticsPreferencesView_Night_1_en",20350,],
+["features.preferences.impl.analytics_AnalyticsSettingsView_Day_0_en","features.preferences.impl.analytics_AnalyticsSettingsView_Night_0_en",20350,],
["libraries.designsystem.components_Announcement_Day_0_en","libraries.designsystem.components_Announcement_Night_0_en",0,],
-["services.apperror.impl_AppErrorView_Day_0_en","services.apperror.impl_AppErrorView_Night_0_en",20336,],
+["services.apperror.impl_AppErrorView_Day_0_en","services.apperror.impl_AppErrorView_Night_0_en",20350,],
["libraries.designsystem.components.async_AsyncActionView_Day_0_en","libraries.designsystem.components.async_AsyncActionView_Night_0_en",0,],
-["libraries.designsystem.components.async_AsyncActionView_Day_1_en","libraries.designsystem.components.async_AsyncActionView_Night_1_en",20336,],
+["libraries.designsystem.components.async_AsyncActionView_Day_1_en","libraries.designsystem.components.async_AsyncActionView_Night_1_en",20350,],
["libraries.designsystem.components.async_AsyncActionView_Day_2_en","libraries.designsystem.components.async_AsyncActionView_Night_2_en",0,],
-["libraries.designsystem.components.async_AsyncActionView_Day_3_en","libraries.designsystem.components.async_AsyncActionView_Night_3_en",20336,],
+["libraries.designsystem.components.async_AsyncActionView_Day_3_en","libraries.designsystem.components.async_AsyncActionView_Night_3_en",20350,],
["libraries.designsystem.components.async_AsyncActionView_Day_4_en","libraries.designsystem.components.async_AsyncActionView_Night_4_en",0,],
-["libraries.designsystem.components.async_AsyncFailure_Day_0_en","libraries.designsystem.components.async_AsyncFailure_Night_0_en",20336,],
+["libraries.designsystem.components.async_AsyncFailure_Day_0_en","libraries.designsystem.components.async_AsyncFailure_Night_0_en",20350,],
["libraries.designsystem.components.async_AsyncIndicatorFailure_Day_0_en","libraries.designsystem.components.async_AsyncIndicatorFailure_Night_0_en",0,],
["libraries.designsystem.components.async_AsyncIndicatorLoading_Day_0_en","libraries.designsystem.components.async_AsyncIndicatorLoading_Night_0_en",0,],
["libraries.designsystem.components.async_AsyncLoading_Day_0_en","libraries.designsystem.components.async_AsyncLoading_Night_0_en",0,],
-["features.messages.impl.messagecomposer_AttachmentSourcePickerMenu_Day_0_en","features.messages.impl.messagecomposer_AttachmentSourcePickerMenu_Night_0_en",20336,],
+["features.messages.impl.messagecomposer_AttachmentSourcePickerMenu_Day_0_en","features.messages.impl.messagecomposer_AttachmentSourcePickerMenu_Night_0_en",20350,],
["libraries.matrix.ui.components_AttachmentThumbnail_Day_0_en","libraries.matrix.ui.components_AttachmentThumbnail_Night_0_en",0,],
["libraries.matrix.ui.components_AttachmentThumbnail_Day_1_en","libraries.matrix.ui.components_AttachmentThumbnail_Night_1_en",0,],
["libraries.matrix.ui.components_AttachmentThumbnail_Day_2_en","libraries.matrix.ui.components_AttachmentThumbnail_Night_2_en",0,],
@@ -80,19 +81,19 @@ export const screenshots = [
["libraries.matrix.ui.components_AttachmentThumbnail_Day_6_en","libraries.matrix.ui.components_AttachmentThumbnail_Night_6_en",0,],
["libraries.matrix.ui.components_AttachmentThumbnail_Day_7_en","libraries.matrix.ui.components_AttachmentThumbnail_Night_7_en",0,],
["libraries.matrix.ui.components_AttachmentThumbnail_Day_8_en","libraries.matrix.ui.components_AttachmentThumbnail_Night_8_en",0,],
-["features.messages.impl.attachments.preview_AttachmentsView_0_en","",20336,],
-["features.messages.impl.attachments.preview_AttachmentsView_1_en","",20336,],
-["features.messages.impl.attachments.preview_AttachmentsView_2_en","",20336,],
-["features.messages.impl.attachments.preview_AttachmentsView_3_en","",20336,],
-["features.messages.impl.attachments.preview_AttachmentsView_4_en","",20336,],
-["features.messages.impl.attachments.preview_AttachmentsView_5_en","",20336,],
-["features.messages.impl.attachments.preview_AttachmentsView_6_en","",20336,],
-["features.messages.impl.attachments.preview_AttachmentsView_7_en","",20336,],
-["features.messages.impl.attachments.preview_AttachmentsView_8_en","",20336,],
+["features.messages.impl.attachments.preview_AttachmentsView_0_en","",20350,],
+["features.messages.impl.attachments.preview_AttachmentsView_1_en","",20350,],
+["features.messages.impl.attachments.preview_AttachmentsView_2_en","",20350,],
+["features.messages.impl.attachments.preview_AttachmentsView_3_en","",20350,],
+["features.messages.impl.attachments.preview_AttachmentsView_4_en","",20350,],
+["features.messages.impl.attachments.preview_AttachmentsView_5_en","",20350,],
+["features.messages.impl.attachments.preview_AttachmentsView_6_en","",20350,],
+["features.messages.impl.attachments.preview_AttachmentsView_7_en","",20350,],
+["features.messages.impl.attachments.preview_AttachmentsView_8_en","",20350,],
["libraries.mediaviewer.impl.gallery.ui_AudioItemView_Day_0_en","libraries.mediaviewer.impl.gallery.ui_AudioItemView_Night_0_en",0,],
["libraries.mediaviewer.impl.gallery.ui_AudioItemView_Day_1_en","libraries.mediaviewer.impl.gallery.ui_AudioItemView_Night_1_en",0,],
["libraries.mediaviewer.impl.gallery.ui_AudioItemView_Day_2_en","libraries.mediaviewer.impl.gallery.ui_AudioItemView_Night_2_en",0,],
-["libraries.matrix.ui.components_AvatarActionBottomSheet_Day_0_en","libraries.matrix.ui.components_AvatarActionBottomSheet_Night_0_en",20336,],
+["libraries.matrix.ui.components_AvatarActionBottomSheet_Day_0_en","libraries.matrix.ui.components_AvatarActionBottomSheet_Night_0_en",20350,],
["libraries.designsystem.components.avatar.internal_AvatarCluster_Avatars_en","",0,],
["libraries.designsystem.components.avatar_AvatarRowLastOnTopRtl_Day_0_en","libraries.designsystem.components.avatar_AvatarRowLastOnTopRtl_Night_0_en",0,],
["libraries.designsystem.components.avatar_AvatarRowLastOnTopRtl_Day_1_en","libraries.designsystem.components.avatar_AvatarRowLastOnTopRtl_Night_1_en",0,],
@@ -224,150 +225,152 @@ export const screenshots = [
["libraries.designsystem.modifiers_BackgroundVerticalGradientEnterprise_Day_0_en","libraries.designsystem.modifiers_BackgroundVerticalGradientEnterprise_Night_0_en",0,],
["libraries.designsystem.modifiers_BackgroundVerticalGradient_Day_0_en","libraries.designsystem.modifiers_BackgroundVerticalGradient_Night_0_en",0,],
["libraries.designsystem.components_Badge_Day_0_en","libraries.designsystem.components_Badge_Night_0_en",0,],
-["features.home.impl.components_BatteryOptimizationBanner_Day_0_en","features.home.impl.components_BatteryOptimizationBanner_Night_0_en",20336,],
+["features.home.impl.components_BatteryOptimizationBanner_Day_0_en","features.home.impl.components_BatteryOptimizationBanner_Night_0_en",20350,],
["libraries.designsystem.components_BigIcon_Day_0_en","libraries.designsystem.components_BigIcon_Night_0_en",0,],
-["features.preferences.impl.blockedusers_BlockedUsersView_Day_0_en","features.preferences.impl.blockedusers_BlockedUsersView_Night_0_en",20336,],
-["features.preferences.impl.blockedusers_BlockedUsersView_Day_1_en","features.preferences.impl.blockedusers_BlockedUsersView_Night_1_en",20336,],
-["features.preferences.impl.blockedusers_BlockedUsersView_Day_2_en","features.preferences.impl.blockedusers_BlockedUsersView_Night_2_en",20336,],
-["features.preferences.impl.blockedusers_BlockedUsersView_Day_3_en","features.preferences.impl.blockedusers_BlockedUsersView_Night_3_en",20336,],
-["features.preferences.impl.blockedusers_BlockedUsersView_Day_4_en","features.preferences.impl.blockedusers_BlockedUsersView_Night_4_en",20336,],
-["features.preferences.impl.blockedusers_BlockedUsersView_Day_5_en","features.preferences.impl.blockedusers_BlockedUsersView_Night_5_en",20336,],
-["features.preferences.impl.blockedusers_BlockedUsersView_Day_6_en","features.preferences.impl.blockedusers_BlockedUsersView_Night_6_en",20336,],
+["features.preferences.impl.blockedusers_BlockedUsersView_Day_0_en","features.preferences.impl.blockedusers_BlockedUsersView_Night_0_en",20350,],
+["features.preferences.impl.blockedusers_BlockedUsersView_Day_1_en","features.preferences.impl.blockedusers_BlockedUsersView_Night_1_en",20350,],
+["features.preferences.impl.blockedusers_BlockedUsersView_Day_2_en","features.preferences.impl.blockedusers_BlockedUsersView_Night_2_en",20350,],
+["features.preferences.impl.blockedusers_BlockedUsersView_Day_3_en","features.preferences.impl.blockedusers_BlockedUsersView_Night_3_en",20350,],
+["features.preferences.impl.blockedusers_BlockedUsersView_Day_4_en","features.preferences.impl.blockedusers_BlockedUsersView_Night_4_en",20350,],
+["features.preferences.impl.blockedusers_BlockedUsersView_Day_5_en","features.preferences.impl.blockedusers_BlockedUsersView_Night_5_en",20350,],
+["features.preferences.impl.blockedusers_BlockedUsersView_Day_6_en","features.preferences.impl.blockedusers_BlockedUsersView_Night_6_en",20350,],
["libraries.designsystem.theme.components_BottomSheetDragHandle_Day_0_en","libraries.designsystem.theme.components_BottomSheetDragHandle_Night_0_en",0,],
-["features.rageshake.impl.bugreport_BugReportView_Day_0_en","features.rageshake.impl.bugreport_BugReportView_Night_0_en",20336,],
-["features.rageshake.impl.bugreport_BugReportView_Day_1_en","features.rageshake.impl.bugreport_BugReportView_Night_1_en",20336,],
-["features.rageshake.impl.bugreport_BugReportView_Day_2_en","features.rageshake.impl.bugreport_BugReportView_Night_2_en",20336,],
-["features.rageshake.impl.bugreport_BugReportView_Day_3_en","features.rageshake.impl.bugreport_BugReportView_Night_3_en",20336,],
-["features.rageshake.impl.bugreport_BugReportView_Day_4_en","features.rageshake.impl.bugreport_BugReportView_Night_4_en",20336,],
+["features.rageshake.impl.bugreport_BugReportView_Day_0_en","features.rageshake.impl.bugreport_BugReportView_Night_0_en",20350,],
+["features.rageshake.impl.bugreport_BugReportView_Day_1_en","features.rageshake.impl.bugreport_BugReportView_Night_1_en",20350,],
+["features.rageshake.impl.bugreport_BugReportView_Day_2_en","features.rageshake.impl.bugreport_BugReportView_Night_2_en",20350,],
+["features.rageshake.impl.bugreport_BugReportView_Day_3_en","features.rageshake.impl.bugreport_BugReportView_Night_3_en",20350,],
+["features.rageshake.impl.bugreport_BugReportView_Day_4_en","features.rageshake.impl.bugreport_BugReportView_Night_4_en",20350,],
["libraries.designsystem.atomic.molecules_ButtonColumnMolecule_Day_0_en","libraries.designsystem.atomic.molecules_ButtonColumnMolecule_Night_0_en",0,],
["libraries.designsystem.atomic.molecules_ButtonRowMolecule_Day_0_en","libraries.designsystem.atomic.molecules_ButtonRowMolecule_Night_0_en",0,],
["features.messages.impl.timeline.components_CallMenuItem_Day_0_en","features.messages.impl.timeline.components_CallMenuItem_Night_0_en",0,],
["features.messages.impl.timeline.components_CallMenuItem_Day_1_en","features.messages.impl.timeline.components_CallMenuItem_Night_1_en",0,],
-["features.messages.impl.timeline.components_CallMenuItem_Day_2_en","features.messages.impl.timeline.components_CallMenuItem_Night_2_en",20336,],
-["features.messages.impl.timeline.components_CallMenuItem_Day_3_en","features.messages.impl.timeline.components_CallMenuItem_Night_3_en",20336,],
+["features.messages.impl.timeline.components_CallMenuItem_Day_2_en","features.messages.impl.timeline.components_CallMenuItem_Night_2_en",20350,],
+["features.messages.impl.timeline.components_CallMenuItem_Day_3_en","features.messages.impl.timeline.components_CallMenuItem_Night_3_en",20350,],
["features.messages.impl.timeline.components_CallMenuItem_Day_4_en","features.messages.impl.timeline.components_CallMenuItem_Night_4_en",0,],
["features.messages.impl.timeline.components_CallMenuItem_Day_5_en","features.messages.impl.timeline.components_CallMenuItem_Night_5_en",0,],
["features.call.impl.ui_CallScreenView_Day_0_en","features.call.impl.ui_CallScreenView_Night_0_en",0,],
-["features.call.impl.ui_CallScreenView_Day_1_en","features.call.impl.ui_CallScreenView_Night_1_en",20336,],
-["features.call.impl.ui_CallScreenView_Day_2_en","features.call.impl.ui_CallScreenView_Night_2_en",20336,],
-["features.call.impl.ui_CallScreenView_Day_3_en","features.call.impl.ui_CallScreenView_Night_3_en",20336,],
-["libraries.textcomposer_CaptionWarningBottomSheet_Day_0_en","libraries.textcomposer_CaptionWarningBottomSheet_Night_0_en",20336,],
-["features.login.impl.screens.changeaccountprovider_ChangeAccountProviderView_Day_0_en","features.login.impl.screens.changeaccountprovider_ChangeAccountProviderView_Night_0_en",20336,],
-["features.login.impl.screens.changeaccountprovider_ChangeAccountProviderView_Day_1_en","features.login.impl.screens.changeaccountprovider_ChangeAccountProviderView_Night_1_en",20336,],
-["features.changeroommemberroles.impl_ChangeRolesView_Day_0_en","features.changeroommemberroles.impl_ChangeRolesView_Night_0_en",20336,],
-["features.changeroommemberroles.impl_ChangeRolesView_Day_10_en","features.changeroommemberroles.impl_ChangeRolesView_Night_10_en",20336,],
-["features.changeroommemberroles.impl_ChangeRolesView_Day_11_en","features.changeroommemberroles.impl_ChangeRolesView_Night_11_en",20336,],
-["features.changeroommemberroles.impl_ChangeRolesView_Day_12_en","features.changeroommemberroles.impl_ChangeRolesView_Night_12_en",20336,],
-["features.changeroommemberroles.impl_ChangeRolesView_Day_1_en","features.changeroommemberroles.impl_ChangeRolesView_Night_1_en",20336,],
-["features.changeroommemberroles.impl_ChangeRolesView_Day_2_en","features.changeroommemberroles.impl_ChangeRolesView_Night_2_en",20336,],
-["features.changeroommemberroles.impl_ChangeRolesView_Day_3_en","features.changeroommemberroles.impl_ChangeRolesView_Night_3_en",20336,],
-["features.changeroommemberroles.impl_ChangeRolesView_Day_4_en","features.changeroommemberroles.impl_ChangeRolesView_Night_4_en",20336,],
+["features.call.impl.ui_CallScreenView_Day_1_en","features.call.impl.ui_CallScreenView_Night_1_en",20350,],
+["features.call.impl.ui_CallScreenView_Day_2_en","features.call.impl.ui_CallScreenView_Night_2_en",20350,],
+["features.call.impl.ui_CallScreenView_Day_3_en","features.call.impl.ui_CallScreenView_Night_3_en",20350,],
+["libraries.textcomposer_CaptionWarningBottomSheet_Day_0_en","libraries.textcomposer_CaptionWarningBottomSheet_Night_0_en",20350,],
+["features.login.impl.screens.changeaccountprovider_ChangeAccountProviderView_Day_0_en","features.login.impl.screens.changeaccountprovider_ChangeAccountProviderView_Night_0_en",20350,],
+["features.login.impl.screens.changeaccountprovider_ChangeAccountProviderView_Day_1_en","features.login.impl.screens.changeaccountprovider_ChangeAccountProviderView_Night_1_en",20350,],
+["features.changeroommemberroles.impl_ChangeRolesView_Day_0_en","features.changeroommemberroles.impl_ChangeRolesView_Night_0_en",20350,],
+["features.changeroommemberroles.impl_ChangeRolesView_Day_10_en","features.changeroommemberroles.impl_ChangeRolesView_Night_10_en",20350,],
+["features.changeroommemberroles.impl_ChangeRolesView_Day_11_en","features.changeroommemberroles.impl_ChangeRolesView_Night_11_en",20350,],
+["features.changeroommemberroles.impl_ChangeRolesView_Day_12_en","features.changeroommemberroles.impl_ChangeRolesView_Night_12_en",20350,],
+["features.changeroommemberroles.impl_ChangeRolesView_Day_1_en","features.changeroommemberroles.impl_ChangeRolesView_Night_1_en",20350,],
+["features.changeroommemberroles.impl_ChangeRolesView_Day_2_en","features.changeroommemberroles.impl_ChangeRolesView_Night_2_en",20350,],
+["features.changeroommemberroles.impl_ChangeRolesView_Day_3_en","features.changeroommemberroles.impl_ChangeRolesView_Night_3_en",20350,],
+["features.changeroommemberroles.impl_ChangeRolesView_Day_4_en","features.changeroommemberroles.impl_ChangeRolesView_Night_4_en",20350,],
["features.changeroommemberroles.impl_ChangeRolesView_Day_5_en","features.changeroommemberroles.impl_ChangeRolesView_Night_5_en",0,],
-["features.changeroommemberroles.impl_ChangeRolesView_Day_6_en","features.changeroommemberroles.impl_ChangeRolesView_Night_6_en",20336,],
-["features.changeroommemberroles.impl_ChangeRolesView_Day_7_en","features.changeroommemberroles.impl_ChangeRolesView_Night_7_en",20336,],
-["features.changeroommemberroles.impl_ChangeRolesView_Day_8_en","features.changeroommemberroles.impl_ChangeRolesView_Night_8_en",20336,],
-["features.changeroommemberroles.impl_ChangeRolesView_Day_9_en","features.changeroommemberroles.impl_ChangeRolesView_Night_9_en",20336,],
-["features.roomdetails.impl.rolesandpermissions.permissions_ChangeRoomPermissionsView_Day_0_en","features.roomdetails.impl.rolesandpermissions.permissions_ChangeRoomPermissionsView_Night_0_en",20336,],
-["features.roomdetails.impl.rolesandpermissions.permissions_ChangeRoomPermissionsView_Day_1_en","features.roomdetails.impl.rolesandpermissions.permissions_ChangeRoomPermissionsView_Night_1_en",20336,],
-["features.roomdetails.impl.rolesandpermissions.permissions_ChangeRoomPermissionsView_Day_2_en","features.roomdetails.impl.rolesandpermissions.permissions_ChangeRoomPermissionsView_Night_2_en",20336,],
-["features.roomdetails.impl.rolesandpermissions.permissions_ChangeRoomPermissionsView_Day_3_en","features.roomdetails.impl.rolesandpermissions.permissions_ChangeRoomPermissionsView_Night_3_en",20336,],
-["features.roomdetails.impl.rolesandpermissions.permissions_ChangeRoomPermissionsView_Day_4_en","features.roomdetails.impl.rolesandpermissions.permissions_ChangeRoomPermissionsView_Night_4_en",20336,],
-["features.roomdetails.impl.rolesandpermissions.permissions_ChangeRoomPermissionsView_Day_5_en","features.roomdetails.impl.rolesandpermissions.permissions_ChangeRoomPermissionsView_Night_5_en",20336,],
-["features.roomdetails.impl.rolesandpermissions.permissions_ChangeRoomPermissionsView_Day_6_en","features.roomdetails.impl.rolesandpermissions.permissions_ChangeRoomPermissionsView_Night_6_en",20336,],
+["features.changeroommemberroles.impl_ChangeRolesView_Day_6_en","features.changeroommemberroles.impl_ChangeRolesView_Night_6_en",20350,],
+["features.changeroommemberroles.impl_ChangeRolesView_Day_7_en","features.changeroommemberroles.impl_ChangeRolesView_Night_7_en",20350,],
+["features.changeroommemberroles.impl_ChangeRolesView_Day_8_en","features.changeroommemberroles.impl_ChangeRolesView_Night_8_en",20350,],
+["features.changeroommemberroles.impl_ChangeRolesView_Day_9_en","features.changeroommemberroles.impl_ChangeRolesView_Night_9_en",20350,],
+["features.roomdetails.impl.rolesandpermissions.permissions_ChangeRoomPermissionsView_Day_0_en","features.roomdetails.impl.rolesandpermissions.permissions_ChangeRoomPermissionsView_Night_0_en",20350,],
+["features.roomdetails.impl.rolesandpermissions.permissions_ChangeRoomPermissionsView_Day_1_en","features.roomdetails.impl.rolesandpermissions.permissions_ChangeRoomPermissionsView_Night_1_en",20350,],
+["features.roomdetails.impl.rolesandpermissions.permissions_ChangeRoomPermissionsView_Day_2_en","features.roomdetails.impl.rolesandpermissions.permissions_ChangeRoomPermissionsView_Night_2_en",20350,],
+["features.roomdetails.impl.rolesandpermissions.permissions_ChangeRoomPermissionsView_Day_3_en","features.roomdetails.impl.rolesandpermissions.permissions_ChangeRoomPermissionsView_Night_3_en",20350,],
+["features.roomdetails.impl.rolesandpermissions.permissions_ChangeRoomPermissionsView_Day_4_en","features.roomdetails.impl.rolesandpermissions.permissions_ChangeRoomPermissionsView_Night_4_en",20350,],
+["features.roomdetails.impl.rolesandpermissions.permissions_ChangeRoomPermissionsView_Day_5_en","features.roomdetails.impl.rolesandpermissions.permissions_ChangeRoomPermissionsView_Night_5_en",20350,],
+["features.roomdetails.impl.rolesandpermissions.permissions_ChangeRoomPermissionsView_Day_6_en","features.roomdetails.impl.rolesandpermissions.permissions_ChangeRoomPermissionsView_Night_6_en",20350,],
["features.login.impl.changeserver_ChangeServerView_Day_0_en","features.login.impl.changeserver_ChangeServerView_Night_0_en",0,],
-["features.login.impl.changeserver_ChangeServerView_Day_1_en","features.login.impl.changeserver_ChangeServerView_Night_1_en",20336,],
-["features.login.impl.changeserver_ChangeServerView_Day_2_en","features.login.impl.changeserver_ChangeServerView_Night_2_en",20336,],
-["features.login.impl.changeserver_ChangeServerView_Day_3_en","features.login.impl.changeserver_ChangeServerView_Night_3_en",20336,],
-["features.login.impl.changeserver_ChangeServerView_Day_4_en","features.login.impl.changeserver_ChangeServerView_Night_4_en",20336,],
+["features.login.impl.changeserver_ChangeServerView_Day_1_en","features.login.impl.changeserver_ChangeServerView_Night_1_en",20350,],
+["features.login.impl.changeserver_ChangeServerView_Day_2_en","features.login.impl.changeserver_ChangeServerView_Night_2_en",20350,],
+["features.login.impl.changeserver_ChangeServerView_Day_3_en","features.login.impl.changeserver_ChangeServerView_Night_3_en",20350,],
+["features.login.impl.changeserver_ChangeServerView_Day_4_en","features.login.impl.changeserver_ChangeServerView_Night_4_en",20350,],
["libraries.matrix.ui.components_CheckableResolvedUserRow_en","",0,],
-["libraries.matrix.ui.components_CheckableUnresolvedUserRow_en","",20336,],
+["libraries.matrix.ui.components_CheckableUnresolvedUserRow_en","",20350,],
["libraries.designsystem.theme.components_Checkboxes_Toggles_en","",0,],
-["features.login.impl.screens.chooseaccountprovider_ChooseAccountProviderView_Day_0_en","features.login.impl.screens.chooseaccountprovider_ChooseAccountProviderView_Night_0_en",20336,],
-["features.login.impl.screens.chooseaccountprovider_ChooseAccountProviderView_Day_1_en","features.login.impl.screens.chooseaccountprovider_ChooseAccountProviderView_Night_1_en",20336,],
-["features.login.impl.screens.chooseaccountprovider_ChooseAccountProviderView_Day_2_en","features.login.impl.screens.chooseaccountprovider_ChooseAccountProviderView_Night_2_en",20336,],
-["features.ftue.impl.sessionverification.choosemode_ChooseSelfVerificationModeView_Day_0_en","features.ftue.impl.sessionverification.choosemode_ChooseSelfVerificationModeView_Night_0_en",20336,],
-["features.ftue.impl.sessionverification.choosemode_ChooseSelfVerificationModeView_Day_1_en","features.ftue.impl.sessionverification.choosemode_ChooseSelfVerificationModeView_Night_1_en",20336,],
-["features.ftue.impl.sessionverification.choosemode_ChooseSelfVerificationModeView_Day_2_en","features.ftue.impl.sessionverification.choosemode_ChooseSelfVerificationModeView_Night_2_en",20336,],
-["features.ftue.impl.sessionverification.choosemode_ChooseSelfVerificationModeView_Day_3_en","features.ftue.impl.sessionverification.choosemode_ChooseSelfVerificationModeView_Night_3_en",20336,],
+["features.login.impl.screens.chooseaccountprovider_ChooseAccountProviderView_Day_0_en","features.login.impl.screens.chooseaccountprovider_ChooseAccountProviderView_Night_0_en",20350,],
+["features.login.impl.screens.chooseaccountprovider_ChooseAccountProviderView_Day_1_en","features.login.impl.screens.chooseaccountprovider_ChooseAccountProviderView_Night_1_en",20350,],
+["features.login.impl.screens.chooseaccountprovider_ChooseAccountProviderView_Day_2_en","features.login.impl.screens.chooseaccountprovider_ChooseAccountProviderView_Night_2_en",20350,],
+["features.ftue.impl.sessionverification.choosemode_ChooseSelfVerificationModeView_Day_0_en","features.ftue.impl.sessionverification.choosemode_ChooseSelfVerificationModeView_Night_0_en",20350,],
+["features.ftue.impl.sessionverification.choosemode_ChooseSelfVerificationModeView_Day_1_en","features.ftue.impl.sessionverification.choosemode_ChooseSelfVerificationModeView_Night_1_en",20350,],
+["features.ftue.impl.sessionverification.choosemode_ChooseSelfVerificationModeView_Day_2_en","features.ftue.impl.sessionverification.choosemode_ChooseSelfVerificationModeView_Night_2_en",20350,],
+["features.ftue.impl.sessionverification.choosemode_ChooseSelfVerificationModeView_Day_3_en","features.ftue.impl.sessionverification.choosemode_ChooseSelfVerificationModeView_Night_3_en",20350,],
["libraries.designsystem.theme.components_CircularProgressIndicator_Progress_Indicators_en","",0,],
["libraries.designsystem.components_ClickableLinkText_Text_en","",0,],
["libraries.designsystem.theme_ColorAliases_Day_0_en","libraries.designsystem.theme_ColorAliases_Night_0_en",0,],
-["libraries.designsystem.atomic.molecules_ComposerAlertMolecule_Day_0_en","libraries.designsystem.atomic.molecules_ComposerAlertMolecule_Night_0_en",20336,],
-["libraries.designsystem.atomic.molecules_ComposerAlertMolecule_Day_1_en","libraries.designsystem.atomic.molecules_ComposerAlertMolecule_Night_1_en",20336,],
-["libraries.textcomposer_ComposerModeView_Day_0_en","libraries.textcomposer_ComposerModeView_Night_0_en",20336,],
+["libraries.designsystem.atomic.molecules_ComposerAlertMolecule_Day_0_en","libraries.designsystem.atomic.molecules_ComposerAlertMolecule_Night_0_en",20350,],
+["libraries.designsystem.atomic.molecules_ComposerAlertMolecule_Day_1_en","libraries.designsystem.atomic.molecules_ComposerAlertMolecule_Night_1_en",20350,],
+["libraries.textcomposer_ComposerModeView_Day_0_en","libraries.textcomposer_ComposerModeView_Night_0_en",20350,],
["libraries.textcomposer_ComposerModeView_Day_1_en","libraries.textcomposer_ComposerModeView_Night_1_en",0,],
["libraries.textcomposer_ComposerModeView_Day_2_en","libraries.textcomposer_ComposerModeView_Night_2_en",0,],
["libraries.textcomposer_ComposerModeView_Day_3_en","libraries.textcomposer_ComposerModeView_Night_3_en",0,],
-["features.createroom.impl.configureroom_ConfigureRoomViewDark_0_en","",20336,],
-["features.createroom.impl.configureroom_ConfigureRoomViewDark_1_en","",20336,],
-["features.createroom.impl.configureroom_ConfigureRoomViewDark_2_en","",20336,],
-["features.createroom.impl.configureroom_ConfigureRoomViewDark_3_en","",20336,],
-["features.createroom.impl.configureroom_ConfigureRoomViewDark_4_en","",20336,],
-["features.createroom.impl.configureroom_ConfigureRoomViewDark_5_en","",20336,],
-["features.createroom.impl.configureroom_ConfigureRoomViewLight_0_en","",20336,],
-["features.createroom.impl.configureroom_ConfigureRoomViewLight_1_en","",20336,],
-["features.createroom.impl.configureroom_ConfigureRoomViewLight_2_en","",20336,],
-["features.createroom.impl.configureroom_ConfigureRoomViewLight_3_en","",20336,],
-["features.createroom.impl.configureroom_ConfigureRoomViewLight_4_en","",20336,],
-["features.createroom.impl.configureroom_ConfigureRoomViewLight_5_en","",20336,],
-["features.login.impl.screens.confirmaccountprovider_ConfirmAccountProviderView_Day_0_en","features.login.impl.screens.confirmaccountprovider_ConfirmAccountProviderView_Night_0_en",20336,],
-["features.login.impl.screens.confirmaccountprovider_ConfirmAccountProviderView_Day_1_en","features.login.impl.screens.confirmaccountprovider_ConfirmAccountProviderView_Night_1_en",20336,],
-["features.login.impl.screens.confirmaccountprovider_ConfirmAccountProviderView_Day_2_en","features.login.impl.screens.confirmaccountprovider_ConfirmAccountProviderView_Night_2_en",20336,],
-["features.home.impl.components_ConfirmRecoveryKeyBanner_Day_0_en","features.home.impl.components_ConfirmRecoveryKeyBanner_Night_0_en",20336,],
+["features.createroom.impl.configureroom_ConfigureRoomViewDark_0_en","",20350,],
+["features.createroom.impl.configureroom_ConfigureRoomViewDark_1_en","",20350,],
+["features.createroom.impl.configureroom_ConfigureRoomViewDark_2_en","",20350,],
+["features.createroom.impl.configureroom_ConfigureRoomViewDark_3_en","",20350,],
+["features.createroom.impl.configureroom_ConfigureRoomViewDark_4_en","",20350,],
+["features.createroom.impl.configureroom_ConfigureRoomViewDark_5_en","",20350,],
+["features.createroom.impl.configureroom_ConfigureRoomViewLight_0_en","",20350,],
+["features.createroom.impl.configureroom_ConfigureRoomViewLight_1_en","",20350,],
+["features.createroom.impl.configureroom_ConfigureRoomViewLight_2_en","",20350,],
+["features.createroom.impl.configureroom_ConfigureRoomViewLight_3_en","",20350,],
+["features.createroom.impl.configureroom_ConfigureRoomViewLight_4_en","",20350,],
+["features.createroom.impl.configureroom_ConfigureRoomViewLight_5_en","",20350,],
+["features.login.impl.screens.confirmaccountprovider_ConfirmAccountProviderView_Day_0_en","features.login.impl.screens.confirmaccountprovider_ConfirmAccountProviderView_Night_0_en",20350,],
+["features.login.impl.screens.confirmaccountprovider_ConfirmAccountProviderView_Day_1_en","features.login.impl.screens.confirmaccountprovider_ConfirmAccountProviderView_Night_1_en",20350,],
+["features.login.impl.screens.confirmaccountprovider_ConfirmAccountProviderView_Day_2_en","features.login.impl.screens.confirmaccountprovider_ConfirmAccountProviderView_Night_2_en",20350,],
+["features.home.impl.components_ConfirmRecoveryKeyBanner_Day_0_en","features.home.impl.components_ConfirmRecoveryKeyBanner_Night_0_en",20350,],
["libraries.designsystem.components.dialogs_ConfirmationDialogContent_Dialogs_en","",0,],
["libraries.designsystem.components.dialogs_ConfirmationDialog_Day_0_en","libraries.designsystem.components.dialogs_ConfirmationDialog_Night_0_en",0,],
["features.networkmonitor.api.ui_ConnectivityIndicatorView_Day_0_en","features.networkmonitor.api.ui_ConnectivityIndicatorView_Night_0_en",0,],
["libraries.designsystem.atomic.atoms_CounterAtom_Day_0_en","libraries.designsystem.atomic.atoms_CounterAtom_Night_0_en",0,],
-["features.rageshake.api.crash_CrashDetectionView_Day_0_en","features.rageshake.api.crash_CrashDetectionView_Night_0_en",20336,],
-["features.login.impl.screens.createaccount_CreateAccountView_Day_0_en","features.login.impl.screens.createaccount_CreateAccountView_Night_0_en",20336,],
-["features.login.impl.screens.createaccount_CreateAccountView_Day_1_en","features.login.impl.screens.createaccount_CreateAccountView_Night_1_en",20336,],
-["features.login.impl.screens.createaccount_CreateAccountView_Day_2_en","features.login.impl.screens.createaccount_CreateAccountView_Night_2_en",20336,],
-["features.login.impl.screens.createaccount_CreateAccountView_Day_3_en","features.login.impl.screens.createaccount_CreateAccountView_Night_3_en",20336,],
-["libraries.matrix.ui.components_CreateDmConfirmationBottomSheet_Day_0_en","libraries.matrix.ui.components_CreateDmConfirmationBottomSheet_Night_0_en",20336,],
-["libraries.matrix.ui.components_CreateDmConfirmationBottomSheet_Day_1_en","libraries.matrix.ui.components_CreateDmConfirmationBottomSheet_Night_1_en",20336,],
-["features.poll.impl.create_CreatePollView_Day_0_en","features.poll.impl.create_CreatePollView_Night_0_en",20336,],
-["features.poll.impl.create_CreatePollView_Day_1_en","features.poll.impl.create_CreatePollView_Night_1_en",20336,],
-["features.poll.impl.create_CreatePollView_Day_2_en","features.poll.impl.create_CreatePollView_Night_2_en",20336,],
-["features.poll.impl.create_CreatePollView_Day_3_en","features.poll.impl.create_CreatePollView_Night_3_en",20336,],
-["features.poll.impl.create_CreatePollView_Day_4_en","features.poll.impl.create_CreatePollView_Night_4_en",20336,],
-["features.poll.impl.create_CreatePollView_Day_5_en","features.poll.impl.create_CreatePollView_Night_5_en",20336,],
-["features.poll.impl.create_CreatePollView_Day_6_en","features.poll.impl.create_CreatePollView_Night_6_en",20336,],
-["features.poll.impl.create_CreatePollView_Day_7_en","features.poll.impl.create_CreatePollView_Night_7_en",20336,],
-["libraries.dateformatter.impl.previews_DateFormatterModeView_0_en","",20336,],
-["libraries.dateformatter.impl.previews_DateFormatterModeView_1_en","",20336,],
-["libraries.dateformatter.impl.previews_DateFormatterModeView_2_en","",20336,],
-["libraries.dateformatter.impl.previews_DateFormatterModeView_3_en","",20336,],
-["libraries.dateformatter.impl.previews_DateFormatterModeView_4_en","",20336,],
+["features.rageshake.api.crash_CrashDetectionView_Day_0_en","features.rageshake.api.crash_CrashDetectionView_Night_0_en",20350,],
+["features.login.impl.screens.createaccount_CreateAccountView_Day_0_en","features.login.impl.screens.createaccount_CreateAccountView_Night_0_en",20350,],
+["features.login.impl.screens.createaccount_CreateAccountView_Day_1_en","features.login.impl.screens.createaccount_CreateAccountView_Night_1_en",20350,],
+["features.login.impl.screens.createaccount_CreateAccountView_Day_2_en","features.login.impl.screens.createaccount_CreateAccountView_Night_2_en",20350,],
+["features.login.impl.screens.createaccount_CreateAccountView_Day_3_en","features.login.impl.screens.createaccount_CreateAccountView_Night_3_en",20350,],
+["libraries.matrix.ui.components_CreateDmConfirmationBottomSheet_Day_0_en","libraries.matrix.ui.components_CreateDmConfirmationBottomSheet_Night_0_en",20350,],
+["libraries.matrix.ui.components_CreateDmConfirmationBottomSheet_Day_1_en","libraries.matrix.ui.components_CreateDmConfirmationBottomSheet_Night_1_en",20350,],
+["features.poll.impl.create_CreatePollView_Day_0_en","features.poll.impl.create_CreatePollView_Night_0_en",20350,],
+["features.poll.impl.create_CreatePollView_Day_1_en","features.poll.impl.create_CreatePollView_Night_1_en",20350,],
+["features.poll.impl.create_CreatePollView_Day_2_en","features.poll.impl.create_CreatePollView_Night_2_en",20350,],
+["features.poll.impl.create_CreatePollView_Day_3_en","features.poll.impl.create_CreatePollView_Night_3_en",20350,],
+["features.poll.impl.create_CreatePollView_Day_4_en","features.poll.impl.create_CreatePollView_Night_4_en",20350,],
+["features.poll.impl.create_CreatePollView_Day_5_en","features.poll.impl.create_CreatePollView_Night_5_en",20350,],
+["features.poll.impl.create_CreatePollView_Day_6_en","features.poll.impl.create_CreatePollView_Night_6_en",20350,],
+["features.poll.impl.create_CreatePollView_Day_7_en","features.poll.impl.create_CreatePollView_Night_7_en",20350,],
+["libraries.dateformatter.impl.previews_DateFormatterModeView_0_en","",20350,],
+["libraries.dateformatter.impl.previews_DateFormatterModeView_1_en","",20350,],
+["libraries.dateformatter.impl.previews_DateFormatterModeView_2_en","",20350,],
+["libraries.dateformatter.impl.previews_DateFormatterModeView_3_en","",20350,],
+["libraries.dateformatter.impl.previews_DateFormatterModeView_4_en","",20350,],
["libraries.mediaviewer.impl.gallery.ui_DateItemView_Day_0_en","libraries.mediaviewer.impl.gallery.ui_DateItemView_Night_0_en",0,],
["libraries.mediaviewer.impl.gallery.ui_DateItemView_Day_1_en","libraries.mediaviewer.impl.gallery.ui_DateItemView_Night_1_en",0,],
-["libraries.designsystem.theme.components.previews_DatePickerDark_DateTime_pickers_en","",20336,],
-["libraries.designsystem.theme.components.previews_DatePickerLight_DateTime_pickers_en","",20336,],
-["features.invite.impl.declineandblock_DeclineAndBlockView_Day_0_en","features.invite.impl.declineandblock_DeclineAndBlockView_Night_0_en",20336,],
-["features.invite.impl.declineandblock_DeclineAndBlockView_Day_1_en","features.invite.impl.declineandblock_DeclineAndBlockView_Night_1_en",20336,],
-["features.invite.impl.declineandblock_DeclineAndBlockView_Day_2_en","features.invite.impl.declineandblock_DeclineAndBlockView_Night_2_en",20336,],
-["features.invite.impl.declineandblock_DeclineAndBlockView_Day_3_en","features.invite.impl.declineandblock_DeclineAndBlockView_Night_3_en",20336,],
-["features.invite.impl.declineandblock_DeclineAndBlockView_Day_4_en","features.invite.impl.declineandblock_DeclineAndBlockView_Night_4_en",20336,],
+["libraries.designsystem.theme.components.previews_DatePickerDark_DateTime_pickers_en","",20350,],
+["libraries.designsystem.theme.components.previews_DatePickerLight_DateTime_pickers_en","",20350,],
+["features.invite.impl.declineandblock_DeclineAndBlockView_Day_0_en","features.invite.impl.declineandblock_DeclineAndBlockView_Night_0_en",20350,],
+["features.invite.impl.declineandblock_DeclineAndBlockView_Day_1_en","features.invite.impl.declineandblock_DeclineAndBlockView_Night_1_en",20350,],
+["features.invite.impl.declineandblock_DeclineAndBlockView_Day_2_en","features.invite.impl.declineandblock_DeclineAndBlockView_Night_2_en",20350,],
+["features.invite.impl.declineandblock_DeclineAndBlockView_Day_3_en","features.invite.impl.declineandblock_DeclineAndBlockView_Night_3_en",20350,],
+["features.invite.impl.declineandblock_DeclineAndBlockView_Day_4_en","features.invite.impl.declineandblock_DeclineAndBlockView_Night_4_en",20350,],
["features.logout.impl.direct_DefaultDirectLogoutView_Day_0_en","features.logout.impl.direct_DefaultDirectLogoutView_Night_0_en",0,],
-["features.logout.impl.direct_DefaultDirectLogoutView_Day_1_en","features.logout.impl.direct_DefaultDirectLogoutView_Night_1_en",20336,],
-["features.logout.impl.direct_DefaultDirectLogoutView_Day_2_en","features.logout.impl.direct_DefaultDirectLogoutView_Night_2_en",20336,],
-["features.logout.impl.direct_DefaultDirectLogoutView_Day_3_en","features.logout.impl.direct_DefaultDirectLogoutView_Night_3_en",20336,],
+["features.logout.impl.direct_DefaultDirectLogoutView_Day_1_en","features.logout.impl.direct_DefaultDirectLogoutView_Night_1_en",20350,],
+["features.logout.impl.direct_DefaultDirectLogoutView_Day_2_en","features.logout.impl.direct_DefaultDirectLogoutView_Night_2_en",20350,],
+["features.logout.impl.direct_DefaultDirectLogoutView_Day_3_en","features.logout.impl.direct_DefaultDirectLogoutView_Night_3_en",20350,],
["features.logout.impl.direct_DefaultDirectLogoutView_Day_4_en","features.logout.impl.direct_DefaultDirectLogoutView_Night_4_en",0,],
-["features.preferences.impl.notifications.edit_DefaultNotificationSettingOption_Day_0_en","features.preferences.impl.notifications.edit_DefaultNotificationSettingOption_Night_0_en",20336,],
-["features.home.impl.components_DefaultRoomListTopBarWithIndicator_Day_0_en","features.home.impl.components_DefaultRoomListTopBarWithIndicator_Night_0_en",20336,],
-["features.home.impl.components_DefaultRoomListTopBar_Day_0_en","features.home.impl.components_DefaultRoomListTopBar_Night_0_en",20336,],
+["features.preferences.impl.notifications.edit_DefaultNotificationSettingOption_Day_0_en","features.preferences.impl.notifications.edit_DefaultNotificationSettingOption_Night_0_en",20350,],
+["features.home.impl.components_DefaultRoomListTopBarWithIndicator_Day_0_en","features.home.impl.components_DefaultRoomListTopBarWithIndicator_Night_0_en",20350,],
+["features.home.impl.components_DefaultRoomListTopBar_Day_0_en","features.home.impl.components_DefaultRoomListTopBar_Night_0_en",20350,],
["features.licenses.impl.details_DependenciesDetailsView_Day_0_en","features.licenses.impl.details_DependenciesDetailsView_Night_0_en",0,],
-["features.licenses.impl.list_DependencyLicensesListView_Day_0_en","features.licenses.impl.list_DependencyLicensesListView_Night_0_en",20336,],
-["features.licenses.impl.list_DependencyLicensesListView_Day_1_en","features.licenses.impl.list_DependencyLicensesListView_Night_1_en",20336,],
-["features.licenses.impl.list_DependencyLicensesListView_Day_2_en","features.licenses.impl.list_DependencyLicensesListView_Night_2_en",20336,],
-["features.licenses.impl.list_DependencyLicensesListView_Day_3_en","features.licenses.impl.list_DependencyLicensesListView_Night_3_en",20336,],
-["features.preferences.impl.developer_DeveloperSettingsView_Day_0_en","features.preferences.impl.developer_DeveloperSettingsView_Night_0_en",20336,],
-["features.preferences.impl.developer_DeveloperSettingsView_Day_1_en","features.preferences.impl.developer_DeveloperSettingsView_Night_1_en",20336,],
-["features.preferences.impl.developer_DeveloperSettingsView_Day_2_en","features.preferences.impl.developer_DeveloperSettingsView_Night_2_en",20336,],
+["features.licenses.impl.list_DependencyLicensesListView_Day_0_en","features.licenses.impl.list_DependencyLicensesListView_Night_0_en",20350,],
+["features.licenses.impl.list_DependencyLicensesListView_Day_1_en","features.licenses.impl.list_DependencyLicensesListView_Night_1_en",20350,],
+["features.licenses.impl.list_DependencyLicensesListView_Day_2_en","features.licenses.impl.list_DependencyLicensesListView_Night_2_en",20350,],
+["features.licenses.impl.list_DependencyLicensesListView_Day_3_en","features.licenses.impl.list_DependencyLicensesListView_Night_3_en",20350,],
+["features.preferences.impl.developer_DeveloperSettingsView_Day_0_en","features.preferences.impl.developer_DeveloperSettingsView_Night_0_en",20350,],
+["features.preferences.impl.developer_DeveloperSettingsView_Day_1_en","features.preferences.impl.developer_DeveloperSettingsView_Night_1_en",20350,],
+["features.preferences.impl.developer_DeveloperSettingsView_Day_2_en","features.preferences.impl.developer_DeveloperSettingsView_Night_2_en",20350,],
["libraries.designsystem.theme.components_DialogWithDestructiveButton_Dialog_with_destructive_button_Dialogs_en","",0,],
["libraries.designsystem.theme.components_DialogWithOnlyMessageAndOkButton_Dialog_with_only_message_and_ok_button_Dialogs_en","",0,],
["libraries.designsystem.theme.components_DialogWithThirdButton_Dialog_with_third_button_Dialogs_en","",0,],
["libraries.designsystem.theme.components_DialogWithTitleAndOkButton_Dialog_with_title_and_ok_button_Dialogs_en","",0,],
["libraries.designsystem.theme.components_DialogWithTitleIconAndOkButton_Dialog_with_title,_icon_and_ok_button_Dialogs_en","",0,],
+["libraries.designsystem.theme.components_DialogWithVeryLongTitleAndIcon_Dialog_with_a_very_long_title_and_icon_Dialogs_en","",0,],
+["libraries.designsystem.theme.components_DialogWithVeryLongTitle_Dialog_with_a_very_long_title_Dialogs_en","",0,],
["features.messages.impl.messagecomposer_DisabledComposerView_Day_0_en","features.messages.impl.messagecomposer_DisabledComposerView_Night_0_en",0,],
["libraries.designsystem.components.avatar_DmAvatarsRtl_Avatars_en","",0,],
["libraries.designsystem.components.avatar_DmAvatars_Avatars_en","",0,],
@@ -375,18 +378,18 @@ export const screenshots = [
["libraries.designsystem.text_DpScale_1_0f__en","",0,],
["libraries.designsystem.text_DpScale_1_5f__en","",0,],
["libraries.designsystem.theme.components_DropdownMenuItem_Menus_en","",0,],
-["features.preferences.impl.notifications.edit_EditDefaultNotificationSettingView_Day_0_en","features.preferences.impl.notifications.edit_EditDefaultNotificationSettingView_Night_0_en",20336,],
-["features.preferences.impl.notifications.edit_EditDefaultNotificationSettingView_Day_1_en","features.preferences.impl.notifications.edit_EditDefaultNotificationSettingView_Night_1_en",20336,],
-["features.preferences.impl.notifications.edit_EditDefaultNotificationSettingView_Day_2_en","features.preferences.impl.notifications.edit_EditDefaultNotificationSettingView_Night_2_en",20336,],
-["features.preferences.impl.notifications.edit_EditDefaultNotificationSettingView_Day_3_en","features.preferences.impl.notifications.edit_EditDefaultNotificationSettingView_Night_3_en",20336,],
-["features.preferences.impl.notifications.edit_EditDefaultNotificationSettingView_Day_4_en","features.preferences.impl.notifications.edit_EditDefaultNotificationSettingView_Night_4_en",20336,],
-["features.roomdetails.impl.securityandprivacy.editroomaddress_EditRoomAddressView_Day_0_en","features.roomdetails.impl.securityandprivacy.editroomaddress_EditRoomAddressView_Night_0_en",20336,],
-["features.roomdetails.impl.securityandprivacy.editroomaddress_EditRoomAddressView_Day_1_en","features.roomdetails.impl.securityandprivacy.editroomaddress_EditRoomAddressView_Night_1_en",20336,],
-["features.roomdetails.impl.securityandprivacy.editroomaddress_EditRoomAddressView_Day_2_en","features.roomdetails.impl.securityandprivacy.editroomaddress_EditRoomAddressView_Night_2_en",20336,],
-["features.roomdetails.impl.securityandprivacy.editroomaddress_EditRoomAddressView_Day_3_en","features.roomdetails.impl.securityandprivacy.editroomaddress_EditRoomAddressView_Night_3_en",20336,],
-["features.roomdetails.impl.securityandprivacy.editroomaddress_EditRoomAddressView_Day_4_en","features.roomdetails.impl.securityandprivacy.editroomaddress_EditRoomAddressView_Night_4_en",20336,],
-["features.preferences.impl.user.editprofile_EditUserProfileView_Day_0_en","features.preferences.impl.user.editprofile_EditUserProfileView_Night_0_en",20336,],
-["features.preferences.impl.user.editprofile_EditUserProfileView_Day_1_en","features.preferences.impl.user.editprofile_EditUserProfileView_Night_1_en",20336,],
+["features.preferences.impl.notifications.edit_EditDefaultNotificationSettingView_Day_0_en","features.preferences.impl.notifications.edit_EditDefaultNotificationSettingView_Night_0_en",20350,],
+["features.preferences.impl.notifications.edit_EditDefaultNotificationSettingView_Day_1_en","features.preferences.impl.notifications.edit_EditDefaultNotificationSettingView_Night_1_en",20350,],
+["features.preferences.impl.notifications.edit_EditDefaultNotificationSettingView_Day_2_en","features.preferences.impl.notifications.edit_EditDefaultNotificationSettingView_Night_2_en",20350,],
+["features.preferences.impl.notifications.edit_EditDefaultNotificationSettingView_Day_3_en","features.preferences.impl.notifications.edit_EditDefaultNotificationSettingView_Night_3_en",20350,],
+["features.preferences.impl.notifications.edit_EditDefaultNotificationSettingView_Day_4_en","features.preferences.impl.notifications.edit_EditDefaultNotificationSettingView_Night_4_en",20350,],
+["features.roomdetails.impl.securityandprivacy.editroomaddress_EditRoomAddressView_Day_0_en","features.roomdetails.impl.securityandprivacy.editroomaddress_EditRoomAddressView_Night_0_en",20350,],
+["features.roomdetails.impl.securityandprivacy.editroomaddress_EditRoomAddressView_Day_1_en","features.roomdetails.impl.securityandprivacy.editroomaddress_EditRoomAddressView_Night_1_en",20350,],
+["features.roomdetails.impl.securityandprivacy.editroomaddress_EditRoomAddressView_Day_2_en","features.roomdetails.impl.securityandprivacy.editroomaddress_EditRoomAddressView_Night_2_en",20350,],
+["features.roomdetails.impl.securityandprivacy.editroomaddress_EditRoomAddressView_Day_3_en","features.roomdetails.impl.securityandprivacy.editroomaddress_EditRoomAddressView_Night_3_en",20350,],
+["features.roomdetails.impl.securityandprivacy.editroomaddress_EditRoomAddressView_Day_4_en","features.roomdetails.impl.securityandprivacy.editroomaddress_EditRoomAddressView_Night_4_en",20350,],
+["features.preferences.impl.user.editprofile_EditUserProfileView_Day_0_en","features.preferences.impl.user.editprofile_EditUserProfileView_Night_0_en",20350,],
+["features.preferences.impl.user.editprofile_EditUserProfileView_Day_1_en","features.preferences.impl.user.editprofile_EditUserProfileView_Night_1_en",20350,],
["libraries.matrix.ui.components_EditableAvatarView_Day_0_en","libraries.matrix.ui.components_EditableAvatarView_Night_0_en",0,],
["libraries.matrix.ui.components_EditableAvatarView_Day_1_en","libraries.matrix.ui.components_EditableAvatarView_Night_1_en",0,],
["libraries.matrix.ui.components_EditableAvatarView_Day_2_en","libraries.matrix.ui.components_EditableAvatarView_Night_2_en",0,],
@@ -397,13 +400,13 @@ export const screenshots = [
["libraries.designsystem.atomic.atoms_ElementLogoAtomMediumNoBlurShadow_Day_0_en","libraries.designsystem.atomic.atoms_ElementLogoAtomMediumNoBlurShadow_Night_0_en",0,],
["libraries.designsystem.atomic.atoms_ElementLogoAtomMedium_Day_0_en","libraries.designsystem.atomic.atoms_ElementLogoAtomMedium_Night_0_en",0,],
["features.messages.impl.timeline.components.customreaction_EmojiItem_Day_0_en","features.messages.impl.timeline.components.customreaction_EmojiItem_Night_0_en",0,],
-["features.messages.impl.timeline.components.customreaction.picker_EmojiPicker_Day_0_en","features.messages.impl.timeline.components.customreaction.picker_EmojiPicker_Night_0_en",20339,],
-["features.messages.impl.timeline.components.customreaction.picker_EmojiPicker_Day_1_en","features.messages.impl.timeline.components.customreaction.picker_EmojiPicker_Night_1_en",20339,],
+["features.messages.impl.timeline.components.customreaction.picker_EmojiPicker_Day_0_en","features.messages.impl.timeline.components.customreaction.picker_EmojiPicker_Night_0_en",20350,],
+["features.messages.impl.timeline.components.customreaction.picker_EmojiPicker_Day_1_en","features.messages.impl.timeline.components.customreaction.picker_EmojiPicker_Night_1_en",20350,],
["features.messages.impl.timeline.components.customreaction.picker_EmojiPicker_Day_2_en","features.messages.impl.timeline.components.customreaction.picker_EmojiPicker_Night_2_en",0,],
["features.messages.impl.timeline.components.customreaction.picker_EmojiPicker_Day_3_en","features.messages.impl.timeline.components.customreaction.picker_EmojiPicker_Night_3_en",0,],
-["libraries.designsystem.components.dialogs_ErrorDialogContent_Dialogs_en","",20336,],
-["libraries.designsystem.components.dialogs_ErrorDialogWithDoNotShowAgain_Day_0_en","libraries.designsystem.components.dialogs_ErrorDialogWithDoNotShowAgain_Night_0_en",20336,],
-["libraries.designsystem.components.dialogs_ErrorDialog_Day_0_en","libraries.designsystem.components.dialogs_ErrorDialog_Night_0_en",20336,],
+["libraries.designsystem.components.dialogs_ErrorDialogContent_Dialogs_en","",20350,],
+["libraries.designsystem.components.dialogs_ErrorDialogWithDoNotShowAgain_Day_0_en","libraries.designsystem.components.dialogs_ErrorDialogWithDoNotShowAgain_Night_0_en",20350,],
+["libraries.designsystem.components.dialogs_ErrorDialog_Day_0_en","libraries.designsystem.components.dialogs_ErrorDialog_Night_0_en",20350,],
["features.messages.impl.timeline.debug_EventDebugInfoView_Day_0_en","features.messages.impl.timeline.debug_EventDebugInfoView_Night_0_en",0,],
["libraries.designsystem.components_ExpandableBottomSheetLayout_en","",0,],
["libraries.featureflag.ui_FeatureListView_Day_0_en","libraries.featureflag.ui_FeatureListView_Night_0_en",0,],
@@ -422,46 +425,41 @@ export const screenshots = [
["libraries.designsystem.theme.components_FloatingActionButton_Floating_Action_Buttons_en","",0,],
["libraries.designsystem.atomic.pages_FlowStepPage_Day_0_en","libraries.designsystem.atomic.pages_FlowStepPage_Night_0_en",0,],
["features.messages.impl.timeline.focus_FocusRequestStateView_Day_0_en","features.messages.impl.timeline.focus_FocusRequestStateView_Night_0_en",0,],
-["features.messages.impl.timeline.focus_FocusRequestStateView_Day_1_en","features.messages.impl.timeline.focus_FocusRequestStateView_Night_1_en",20336,],
-["features.messages.impl.timeline.focus_FocusRequestStateView_Day_2_en","features.messages.impl.timeline.focus_FocusRequestStateView_Night_2_en",20336,],
-["features.messages.impl.timeline.focus_FocusRequestStateView_Day_3_en","features.messages.impl.timeline.focus_FocusRequestStateView_Night_3_en",20336,],
+["features.messages.impl.timeline.focus_FocusRequestStateView_Day_1_en","features.messages.impl.timeline.focus_FocusRequestStateView_Night_1_en",20350,],
+["features.messages.impl.timeline.focus_FocusRequestStateView_Day_2_en","features.messages.impl.timeline.focus_FocusRequestStateView_Night_2_en",20350,],
+["features.messages.impl.timeline.focus_FocusRequestStateView_Day_3_en","features.messages.impl.timeline.focus_FocusRequestStateView_Night_3_en",20350,],
["features.messages.impl.timeline.components_FocusedEventEnterprise_Day_0_en","features.messages.impl.timeline.components_FocusedEventEnterprise_Night_0_en",0,],
["features.messages.impl.timeline.components_FocusedEvent_Day_0_en","features.messages.impl.timeline.components_FocusedEvent_Night_0_en",0,],
["libraries.textcomposer.components_FormattingOption_Day_0_en","libraries.textcomposer.components_FormattingOption_Night_0_en",0,],
["features.messages.impl.forward_ForwardMessagesView_Day_0_en","features.messages.impl.forward_ForwardMessagesView_Night_0_en",0,],
["features.messages.impl.forward_ForwardMessagesView_Day_1_en","features.messages.impl.forward_ForwardMessagesView_Night_1_en",0,],
["features.messages.impl.forward_ForwardMessagesView_Day_2_en","features.messages.impl.forward_ForwardMessagesView_Night_2_en",0,],
-["features.messages.impl.forward_ForwardMessagesView_Day_3_en","features.messages.impl.forward_ForwardMessagesView_Night_3_en",20336,],
-["features.home.impl.components_FullScreenIntentPermissionBanner_Day_0_en","features.home.impl.components_FullScreenIntentPermissionBanner_Night_0_en",20336,],
+["features.messages.impl.forward_ForwardMessagesView_Day_3_en","features.messages.impl.forward_ForwardMessagesView_Night_3_en",20350,],
+["features.home.impl.components_FullScreenIntentPermissionBanner_Day_0_en","features.home.impl.components_FullScreenIntentPermissionBanner_Night_0_en",20350,],
["libraries.designsystem.components.button_GradientFloatingActionButtonCircleShape_Day_0_en","libraries.designsystem.components.button_GradientFloatingActionButtonCircleShape_Night_0_en",0,],
["libraries.designsystem.components.button_GradientFloatingActionButton_Day_0_en","libraries.designsystem.components.button_GradientFloatingActionButton_Night_0_en",0,],
["features.messages.impl.timeline.components.group_GroupHeaderView_Day_0_en","features.messages.impl.timeline.components.group_GroupHeaderView_Night_0_en",0,],
["libraries.designsystem.atomic.pages_HeaderFooterPageScrollable_Day_0_en","libraries.designsystem.atomic.pages_HeaderFooterPageScrollable_Night_0_en",0,],
["libraries.designsystem.atomic.pages_HeaderFooterPage_Day_0_en","libraries.designsystem.atomic.pages_HeaderFooterPage_Night_0_en",0,],
-["features.home.impl.spaces_HomeSpaceItemView_Day_0_en","features.home.impl.spaces_HomeSpaceItemView_Night_0_en",20339,],
-["features.home.impl.spaces_HomeSpaceItemView_Day_1_en","features.home.impl.spaces_HomeSpaceItemView_Night_1_en",20339,],
-["features.home.impl.spaces_HomeSpaceItemView_Day_2_en","features.home.impl.spaces_HomeSpaceItemView_Night_2_en",20339,],
-["features.home.impl.spaces_HomeSpaceItemView_Day_3_en","features.home.impl.spaces_HomeSpaceItemView_Night_3_en",20339,],
-["features.home.impl.spaces_HomeSpaceItemView_Day_4_en","features.home.impl.spaces_HomeSpaceItemView_Night_4_en",20339,],
-["features.home.impl.spaces_HomeSpacesView_Day_0_en","features.home.impl.spaces_HomeSpacesView_Night_0_en",20339,],
-["features.home.impl.spaces_HomeSpacesView_Day_1_en","features.home.impl.spaces_HomeSpacesView_Night_1_en",20339,],
+["features.home.impl.spaces_HomeSpacesView_Day_0_en","features.home.impl.spaces_HomeSpacesView_Night_0_en",20350,],
+["features.home.impl.spaces_HomeSpacesView_Day_1_en","features.home.impl.spaces_HomeSpacesView_Night_1_en",20350,],
["features.home.impl_HomeViewA11y_en","",0,],
-["features.home.impl_HomeView_Day_0_en","features.home.impl_HomeView_Night_0_en",20336,],
-["features.home.impl_HomeView_Day_10_en","features.home.impl_HomeView_Night_10_en",20336,],
+["features.home.impl_HomeView_Day_0_en","features.home.impl_HomeView_Night_0_en",20350,],
+["features.home.impl_HomeView_Day_10_en","features.home.impl_HomeView_Night_10_en",20350,],
["features.home.impl_HomeView_Day_11_en","features.home.impl_HomeView_Night_11_en",0,],
["features.home.impl_HomeView_Day_12_en","features.home.impl_HomeView_Night_12_en",0,],
-["features.home.impl_HomeView_Day_13_en","features.home.impl_HomeView_Night_13_en",20336,],
-["features.home.impl_HomeView_Day_14_en","features.home.impl_HomeView_Night_14_en",20336,],
-["features.home.impl_HomeView_Day_15_en","features.home.impl_HomeView_Night_15_en",20336,],
-["features.home.impl_HomeView_Day_1_en","features.home.impl_HomeView_Night_1_en",20336,],
-["features.home.impl_HomeView_Day_2_en","features.home.impl_HomeView_Night_2_en",20336,],
-["features.home.impl_HomeView_Day_3_en","features.home.impl_HomeView_Night_3_en",20336,],
-["features.home.impl_HomeView_Day_4_en","features.home.impl_HomeView_Night_4_en",20339,],
-["features.home.impl_HomeView_Day_5_en","features.home.impl_HomeView_Night_5_en",20336,],
-["features.home.impl_HomeView_Day_6_en","features.home.impl_HomeView_Night_6_en",20336,],
-["features.home.impl_HomeView_Day_7_en","features.home.impl_HomeView_Night_7_en",20336,],
-["features.home.impl_HomeView_Day_8_en","features.home.impl_HomeView_Night_8_en",20336,],
-["features.home.impl_HomeView_Day_9_en","features.home.impl_HomeView_Night_9_en",20336,],
+["features.home.impl_HomeView_Day_13_en","features.home.impl_HomeView_Night_13_en",20350,],
+["features.home.impl_HomeView_Day_14_en","features.home.impl_HomeView_Night_14_en",20350,],
+["features.home.impl_HomeView_Day_15_en","features.home.impl_HomeView_Night_15_en",20350,],
+["features.home.impl_HomeView_Day_1_en","features.home.impl_HomeView_Night_1_en",20350,],
+["features.home.impl_HomeView_Day_2_en","features.home.impl_HomeView_Night_2_en",20350,],
+["features.home.impl_HomeView_Day_3_en","features.home.impl_HomeView_Night_3_en",20350,],
+["features.home.impl_HomeView_Day_4_en","features.home.impl_HomeView_Night_4_en",20350,],
+["features.home.impl_HomeView_Day_5_en","features.home.impl_HomeView_Night_5_en",20350,],
+["features.home.impl_HomeView_Day_6_en","features.home.impl_HomeView_Night_6_en",20350,],
+["features.home.impl_HomeView_Day_7_en","features.home.impl_HomeView_Night_7_en",20350,],
+["features.home.impl_HomeView_Day_8_en","features.home.impl_HomeView_Night_8_en",20350,],
+["features.home.impl_HomeView_Day_9_en","features.home.impl_HomeView_Night_9_en",20350,],
["libraries.designsystem.theme.components_HorizontalDivider_Dividers_en","",0,],
["libraries.designsystem.ruler_HorizontalRuler_Day_0_en","libraries.designsystem.ruler_HorizontalRuler_Night_0_en",0,],
["libraries.designsystem.theme.components_IconButton_Buttons_en","",0,],
@@ -480,8 +478,8 @@ export const screenshots = [
["libraries.designsystem.icons_IconsCompound_Day_5_en","libraries.designsystem.icons_IconsCompound_Night_5_en",0,],
["libraries.designsystem.icons_IconsOther_Day_0_en","libraries.designsystem.icons_IconsOther_Night_0_en",0,],
["features.messages.impl.crypto.identity_IdentityChangeStateView_Day_0_en","features.messages.impl.crypto.identity_IdentityChangeStateView_Night_0_en",0,],
-["features.messages.impl.crypto.identity_IdentityChangeStateView_Day_1_en","features.messages.impl.crypto.identity_IdentityChangeStateView_Night_1_en",20336,],
-["features.messages.impl.crypto.identity_IdentityChangeStateView_Day_2_en","features.messages.impl.crypto.identity_IdentityChangeStateView_Night_2_en",20336,],
+["features.messages.impl.crypto.identity_IdentityChangeStateView_Day_1_en","features.messages.impl.crypto.identity_IdentityChangeStateView_Night_1_en",20350,],
+["features.messages.impl.crypto.identity_IdentityChangeStateView_Day_2_en","features.messages.impl.crypto.identity_IdentityChangeStateView_Night_2_en",20350,],
["libraries.mediaviewer.impl.gallery.ui_ImageItemView_Day_0_en","libraries.mediaviewer.impl.gallery.ui_ImageItemView_Night_0_en",0,],
["libraries.matrix.ui.messages.reply_InReplyToView_Day_0_en","libraries.matrix.ui.messages.reply_InReplyToView_Night_0_en",0,],
["libraries.matrix.ui.messages.reply_InReplyToView_Day_10_en","libraries.matrix.ui.messages.reply_InReplyToView_Night_10_en",0,],
@@ -489,96 +487,97 @@ export const screenshots = [
["libraries.matrix.ui.messages.reply_InReplyToView_Day_1_en","libraries.matrix.ui.messages.reply_InReplyToView_Night_1_en",0,],
["libraries.matrix.ui.messages.reply_InReplyToView_Day_2_en","libraries.matrix.ui.messages.reply_InReplyToView_Night_2_en",0,],
["libraries.matrix.ui.messages.reply_InReplyToView_Day_3_en","libraries.matrix.ui.messages.reply_InReplyToView_Night_3_en",0,],
-["libraries.matrix.ui.messages.reply_InReplyToView_Day_4_en","libraries.matrix.ui.messages.reply_InReplyToView_Night_4_en",20336,],
+["libraries.matrix.ui.messages.reply_InReplyToView_Day_4_en","libraries.matrix.ui.messages.reply_InReplyToView_Night_4_en",20350,],
["libraries.matrix.ui.messages.reply_InReplyToView_Day_5_en","libraries.matrix.ui.messages.reply_InReplyToView_Night_5_en",0,],
["libraries.matrix.ui.messages.reply_InReplyToView_Day_6_en","libraries.matrix.ui.messages.reply_InReplyToView_Night_6_en",0,],
["libraries.matrix.ui.messages.reply_InReplyToView_Day_7_en","libraries.matrix.ui.messages.reply_InReplyToView_Night_7_en",0,],
-["libraries.matrix.ui.messages.reply_InReplyToView_Day_8_en","libraries.matrix.ui.messages.reply_InReplyToView_Night_8_en",20336,],
+["libraries.matrix.ui.messages.reply_InReplyToView_Day_8_en","libraries.matrix.ui.messages.reply_InReplyToView_Night_8_en",20350,],
["libraries.matrix.ui.messages.reply_InReplyToView_Day_9_en","libraries.matrix.ui.messages.reply_InReplyToView_Night_9_en",0,],
-["features.call.impl.ui_IncomingCallScreen_Day_0_en","features.call.impl.ui_IncomingCallScreen_Night_0_en",20336,],
-["features.verifysession.impl.incoming_IncomingVerificationView_Day_0_en","features.verifysession.impl.incoming_IncomingVerificationView_Night_0_en",20336,],
-["features.verifysession.impl.incoming_IncomingVerificationView_Day_10_en","features.verifysession.impl.incoming_IncomingVerificationView_Night_10_en",20336,],
-["features.verifysession.impl.incoming_IncomingVerificationView_Day_11_en","features.verifysession.impl.incoming_IncomingVerificationView_Night_11_en",20336,],
-["features.verifysession.impl.incoming_IncomingVerificationView_Day_12_en","features.verifysession.impl.incoming_IncomingVerificationView_Night_12_en",20336,],
-["features.verifysession.impl.incoming_IncomingVerificationView_Day_13_en","features.verifysession.impl.incoming_IncomingVerificationView_Night_13_en",20336,],
-["features.verifysession.impl.incoming_IncomingVerificationView_Day_1_en","features.verifysession.impl.incoming_IncomingVerificationView_Night_1_en",20336,],
-["features.verifysession.impl.incoming_IncomingVerificationView_Day_2_en","features.verifysession.impl.incoming_IncomingVerificationView_Night_2_en",20336,],
-["features.verifysession.impl.incoming_IncomingVerificationView_Day_3_en","features.verifysession.impl.incoming_IncomingVerificationView_Night_3_en",20336,],
-["features.verifysession.impl.incoming_IncomingVerificationView_Day_4_en","features.verifysession.impl.incoming_IncomingVerificationView_Night_4_en",20336,],
-["features.verifysession.impl.incoming_IncomingVerificationView_Day_5_en","features.verifysession.impl.incoming_IncomingVerificationView_Night_5_en",20336,],
-["features.verifysession.impl.incoming_IncomingVerificationView_Day_6_en","features.verifysession.impl.incoming_IncomingVerificationView_Night_6_en",20336,],
-["features.verifysession.impl.incoming_IncomingVerificationView_Day_7_en","features.verifysession.impl.incoming_IncomingVerificationView_Night_7_en",20336,],
-["features.verifysession.impl.incoming_IncomingVerificationView_Day_8_en","features.verifysession.impl.incoming_IncomingVerificationView_Night_8_en",20336,],
-["features.verifysession.impl.incoming_IncomingVerificationView_Day_9_en","features.verifysession.impl.incoming_IncomingVerificationView_Night_9_en",20336,],
+["features.call.impl.ui_IncomingCallScreen_Day_0_en","features.call.impl.ui_IncomingCallScreen_Night_0_en",20350,],
+["features.verifysession.impl.incoming_IncomingVerificationView_Day_0_en","features.verifysession.impl.incoming_IncomingVerificationView_Night_0_en",20350,],
+["features.verifysession.impl.incoming_IncomingVerificationView_Day_10_en","features.verifysession.impl.incoming_IncomingVerificationView_Night_10_en",20350,],
+["features.verifysession.impl.incoming_IncomingVerificationView_Day_11_en","features.verifysession.impl.incoming_IncomingVerificationView_Night_11_en",20350,],
+["features.verifysession.impl.incoming_IncomingVerificationView_Day_12_en","features.verifysession.impl.incoming_IncomingVerificationView_Night_12_en",20350,],
+["features.verifysession.impl.incoming_IncomingVerificationView_Day_13_en","features.verifysession.impl.incoming_IncomingVerificationView_Night_13_en",20350,],
+["features.verifysession.impl.incoming_IncomingVerificationView_Day_1_en","features.verifysession.impl.incoming_IncomingVerificationView_Night_1_en",20350,],
+["features.verifysession.impl.incoming_IncomingVerificationView_Day_2_en","features.verifysession.impl.incoming_IncomingVerificationView_Night_2_en",20350,],
+["features.verifysession.impl.incoming_IncomingVerificationView_Day_3_en","features.verifysession.impl.incoming_IncomingVerificationView_Night_3_en",20350,],
+["features.verifysession.impl.incoming_IncomingVerificationView_Day_4_en","features.verifysession.impl.incoming_IncomingVerificationView_Night_4_en",20350,],
+["features.verifysession.impl.incoming_IncomingVerificationView_Day_5_en","features.verifysession.impl.incoming_IncomingVerificationView_Night_5_en",20350,],
+["features.verifysession.impl.incoming_IncomingVerificationView_Day_6_en","features.verifysession.impl.incoming_IncomingVerificationView_Night_6_en",20350,],
+["features.verifysession.impl.incoming_IncomingVerificationView_Day_7_en","features.verifysession.impl.incoming_IncomingVerificationView_Night_7_en",20350,],
+["features.verifysession.impl.incoming_IncomingVerificationView_Day_8_en","features.verifysession.impl.incoming_IncomingVerificationView_Night_8_en",20350,],
+["features.verifysession.impl.incoming_IncomingVerificationView_Day_9_en","features.verifysession.impl.incoming_IncomingVerificationView_Night_9_en",20350,],
["features.networkmonitor.api.ui_Indicator_Day_0_en","features.networkmonitor.api.ui_Indicator_Night_0_en",0,],
["libraries.designsystem.atomic.molecules_InfoListItemMolecule_Day_0_en","libraries.designsystem.atomic.molecules_InfoListItemMolecule_Night_0_en",0,],
["libraries.designsystem.atomic.organisms_InfoListOrganism_Day_0_en","libraries.designsystem.atomic.organisms_InfoListOrganism_Night_0_en",0,],
["libraries.matrix.ui.media_InitialsAvatarBitmapGenerator_Day_0_en","libraries.matrix.ui.media_InitialsAvatarBitmapGenerator_Night_0_en",0,],
-["features.call.impl.ui_InvalidAudioDeviceDialog_Day_0_en","features.call.impl.ui_InvalidAudioDeviceDialog_Night_0_en",20336,],
-["features.invitepeople.impl_InvitePeopleView_Day_0_en","features.invitepeople.impl_InvitePeopleView_Night_0_en",20336,],
-["features.invitepeople.impl_InvitePeopleView_Day_1_en","features.invitepeople.impl_InvitePeopleView_Night_1_en",20336,],
+["features.call.impl.ui_InvalidAudioDeviceDialog_Day_0_en","features.call.impl.ui_InvalidAudioDeviceDialog_Night_0_en",20350,],
+["features.invitepeople.impl_InvitePeopleView_Day_0_en","features.invitepeople.impl_InvitePeopleView_Night_0_en",20350,],
+["features.invitepeople.impl_InvitePeopleView_Day_1_en","features.invitepeople.impl_InvitePeopleView_Night_1_en",20350,],
["features.invitepeople.impl_InvitePeopleView_Day_2_en","features.invitepeople.impl_InvitePeopleView_Night_2_en",0,],
["features.invitepeople.impl_InvitePeopleView_Day_3_en","features.invitepeople.impl_InvitePeopleView_Night_3_en",0,],
-["features.invitepeople.impl_InvitePeopleView_Day_4_en","features.invitepeople.impl_InvitePeopleView_Night_4_en",20336,],
-["features.invitepeople.impl_InvitePeopleView_Day_5_en","features.invitepeople.impl_InvitePeopleView_Night_5_en",20336,],
-["features.invitepeople.impl_InvitePeopleView_Day_6_en","features.invitepeople.impl_InvitePeopleView_Night_6_en",20336,],
-["features.invitepeople.impl_InvitePeopleView_Day_7_en","features.invitepeople.impl_InvitePeopleView_Night_7_en",20336,],
+["features.invitepeople.impl_InvitePeopleView_Day_4_en","features.invitepeople.impl_InvitePeopleView_Night_4_en",20350,],
+["features.invitepeople.impl_InvitePeopleView_Day_5_en","features.invitepeople.impl_InvitePeopleView_Night_5_en",20350,],
+["features.invitepeople.impl_InvitePeopleView_Day_6_en","features.invitepeople.impl_InvitePeopleView_Night_6_en",20350,],
+["features.invitepeople.impl_InvitePeopleView_Day_7_en","features.invitepeople.impl_InvitePeopleView_Night_7_en",20350,],
["features.invitepeople.impl_InvitePeopleView_Day_8_en","features.invitepeople.impl_InvitePeopleView_Night_8_en",0,],
-["libraries.matrix.ui.components_InviteSenderView_Day_0_en","libraries.matrix.ui.components_InviteSenderView_Night_0_en",20336,],
-["features.startchat.impl.joinbyaddress_JoinRoomByAddressView_Day_0_en","features.startchat.impl.joinbyaddress_JoinRoomByAddressView_Night_0_en",20336,],
-["features.startchat.impl.joinbyaddress_JoinRoomByAddressView_Day_1_en","features.startchat.impl.joinbyaddress_JoinRoomByAddressView_Night_1_en",20336,],
-["features.startchat.impl.joinbyaddress_JoinRoomByAddressView_Day_2_en","features.startchat.impl.joinbyaddress_JoinRoomByAddressView_Night_2_en",20336,],
-["features.startchat.impl.joinbyaddress_JoinRoomByAddressView_Day_3_en","features.startchat.impl.joinbyaddress_JoinRoomByAddressView_Night_3_en",20336,],
-["features.startchat.impl.joinbyaddress_JoinRoomByAddressView_Day_4_en","features.startchat.impl.joinbyaddress_JoinRoomByAddressView_Night_4_en",20336,],
-["features.startchat.impl.joinbyaddress_JoinRoomByAddressView_Day_5_en","features.startchat.impl.joinbyaddress_JoinRoomByAddressView_Night_5_en",20336,],
+["features.invitepeople.impl_InvitePeopleView_Day_9_en","features.invitepeople.impl_InvitePeopleView_Night_9_en",20350,],
+["libraries.matrix.ui.components_InviteSenderView_Day_0_en","libraries.matrix.ui.components_InviteSenderView_Night_0_en",20350,],
+["features.startchat.impl.joinbyaddress_JoinRoomByAddressView_Day_0_en","features.startchat.impl.joinbyaddress_JoinRoomByAddressView_Night_0_en",20350,],
+["features.startchat.impl.joinbyaddress_JoinRoomByAddressView_Day_1_en","features.startchat.impl.joinbyaddress_JoinRoomByAddressView_Night_1_en",20350,],
+["features.startchat.impl.joinbyaddress_JoinRoomByAddressView_Day_2_en","features.startchat.impl.joinbyaddress_JoinRoomByAddressView_Night_2_en",20350,],
+["features.startchat.impl.joinbyaddress_JoinRoomByAddressView_Day_3_en","features.startchat.impl.joinbyaddress_JoinRoomByAddressView_Night_3_en",20350,],
+["features.startchat.impl.joinbyaddress_JoinRoomByAddressView_Day_4_en","features.startchat.impl.joinbyaddress_JoinRoomByAddressView_Night_4_en",20350,],
+["features.startchat.impl.joinbyaddress_JoinRoomByAddressView_Day_5_en","features.startchat.impl.joinbyaddress_JoinRoomByAddressView_Night_5_en",20350,],
["features.joinroom.impl_JoinRoomView_Day_0_en","features.joinroom.impl_JoinRoomView_Night_0_en",0,],
-["features.joinroom.impl_JoinRoomView_Day_10_en","features.joinroom.impl_JoinRoomView_Night_10_en",20336,],
-["features.joinroom.impl_JoinRoomView_Day_11_en","features.joinroom.impl_JoinRoomView_Night_11_en",20336,],
-["features.joinroom.impl_JoinRoomView_Day_12_en","features.joinroom.impl_JoinRoomView_Night_12_en",20336,],
-["features.joinroom.impl_JoinRoomView_Day_13_en","features.joinroom.impl_JoinRoomView_Night_13_en",20336,],
-["features.joinroom.impl_JoinRoomView_Day_14_en","features.joinroom.impl_JoinRoomView_Night_14_en",20336,],
-["features.joinroom.impl_JoinRoomView_Day_15_en","features.joinroom.impl_JoinRoomView_Night_15_en",20336,],
-["features.joinroom.impl_JoinRoomView_Day_16_en","features.joinroom.impl_JoinRoomView_Night_16_en",20336,],
-["features.joinroom.impl_JoinRoomView_Day_1_en","features.joinroom.impl_JoinRoomView_Night_1_en",20336,],
-["features.joinroom.impl_JoinRoomView_Day_2_en","features.joinroom.impl_JoinRoomView_Night_2_en",20336,],
-["features.joinroom.impl_JoinRoomView_Day_3_en","features.joinroom.impl_JoinRoomView_Night_3_en",20336,],
-["features.joinroom.impl_JoinRoomView_Day_4_en","features.joinroom.impl_JoinRoomView_Night_4_en",20336,],
-["features.joinroom.impl_JoinRoomView_Day_5_en","features.joinroom.impl_JoinRoomView_Night_5_en",20336,],
-["features.joinroom.impl_JoinRoomView_Day_6_en","features.joinroom.impl_JoinRoomView_Night_6_en",20336,],
-["features.joinroom.impl_JoinRoomView_Day_7_en","features.joinroom.impl_JoinRoomView_Night_7_en",20336,],
-["features.joinroom.impl_JoinRoomView_Day_8_en","features.joinroom.impl_JoinRoomView_Night_8_en",20336,],
-["features.joinroom.impl_JoinRoomView_Day_9_en","features.joinroom.impl_JoinRoomView_Night_9_en",20336,],
-["features.knockrequests.impl.banner_KnockRequestsBannerView_Day_0_en","features.knockrequests.impl.banner_KnockRequestsBannerView_Night_0_en",20336,],
-["features.knockrequests.impl.banner_KnockRequestsBannerView_Day_1_en","features.knockrequests.impl.banner_KnockRequestsBannerView_Night_1_en",20336,],
-["features.knockrequests.impl.banner_KnockRequestsBannerView_Day_2_en","features.knockrequests.impl.banner_KnockRequestsBannerView_Night_2_en",20336,],
-["features.knockrequests.impl.banner_KnockRequestsBannerView_Day_3_en","features.knockrequests.impl.banner_KnockRequestsBannerView_Night_3_en",20336,],
-["features.knockrequests.impl.banner_KnockRequestsBannerView_Day_4_en","features.knockrequests.impl.banner_KnockRequestsBannerView_Night_4_en",20336,],
-["features.knockrequests.impl.banner_KnockRequestsBannerView_Day_5_en","features.knockrequests.impl.banner_KnockRequestsBannerView_Night_5_en",20336,],
-["features.knockrequests.impl.banner_KnockRequestsBannerView_Day_6_en","features.knockrequests.impl.banner_KnockRequestsBannerView_Night_6_en",20336,],
-["features.knockrequests.impl.list_KnockRequestsListView_Day_0_en","features.knockrequests.impl.list_KnockRequestsListView_Night_0_en",20336,],
-["features.knockrequests.impl.list_KnockRequestsListView_Day_10_en","features.knockrequests.impl.list_KnockRequestsListView_Night_10_en",20336,],
-["features.knockrequests.impl.list_KnockRequestsListView_Day_1_en","features.knockrequests.impl.list_KnockRequestsListView_Night_1_en",20336,],
-["features.knockrequests.impl.list_KnockRequestsListView_Day_2_en","features.knockrequests.impl.list_KnockRequestsListView_Night_2_en",20336,],
-["features.knockrequests.impl.list_KnockRequestsListView_Day_3_en","features.knockrequests.impl.list_KnockRequestsListView_Night_3_en",20336,],
-["features.knockrequests.impl.list_KnockRequestsListView_Day_4_en","features.knockrequests.impl.list_KnockRequestsListView_Night_4_en",20336,],
-["features.knockrequests.impl.list_KnockRequestsListView_Day_5_en","features.knockrequests.impl.list_KnockRequestsListView_Night_5_en",20336,],
-["features.knockrequests.impl.list_KnockRequestsListView_Day_6_en","features.knockrequests.impl.list_KnockRequestsListView_Night_6_en",20336,],
-["features.knockrequests.impl.list_KnockRequestsListView_Day_7_en","features.knockrequests.impl.list_KnockRequestsListView_Night_7_en",20336,],
-["features.knockrequests.impl.list_KnockRequestsListView_Day_8_en","features.knockrequests.impl.list_KnockRequestsListView_Night_8_en",20336,],
-["features.knockrequests.impl.list_KnockRequestsListView_Day_9_en","features.knockrequests.impl.list_KnockRequestsListView_Night_9_en",20336,],
+["features.joinroom.impl_JoinRoomView_Day_10_en","features.joinroom.impl_JoinRoomView_Night_10_en",20350,],
+["features.joinroom.impl_JoinRoomView_Day_11_en","features.joinroom.impl_JoinRoomView_Night_11_en",20350,],
+["features.joinroom.impl_JoinRoomView_Day_12_en","features.joinroom.impl_JoinRoomView_Night_12_en",20350,],
+["features.joinroom.impl_JoinRoomView_Day_13_en","features.joinroom.impl_JoinRoomView_Night_13_en",20350,],
+["features.joinroom.impl_JoinRoomView_Day_14_en","features.joinroom.impl_JoinRoomView_Night_14_en",20350,],
+["features.joinroom.impl_JoinRoomView_Day_15_en","features.joinroom.impl_JoinRoomView_Night_15_en",20350,],
+["features.joinroom.impl_JoinRoomView_Day_16_en","features.joinroom.impl_JoinRoomView_Night_16_en",20350,],
+["features.joinroom.impl_JoinRoomView_Day_1_en","features.joinroom.impl_JoinRoomView_Night_1_en",20350,],
+["features.joinroom.impl_JoinRoomView_Day_2_en","features.joinroom.impl_JoinRoomView_Night_2_en",20350,],
+["features.joinroom.impl_JoinRoomView_Day_3_en","features.joinroom.impl_JoinRoomView_Night_3_en",20350,],
+["features.joinroom.impl_JoinRoomView_Day_4_en","features.joinroom.impl_JoinRoomView_Night_4_en",20350,],
+["features.joinroom.impl_JoinRoomView_Day_5_en","features.joinroom.impl_JoinRoomView_Night_5_en",20350,],
+["features.joinroom.impl_JoinRoomView_Day_6_en","features.joinroom.impl_JoinRoomView_Night_6_en",20350,],
+["features.joinroom.impl_JoinRoomView_Day_7_en","features.joinroom.impl_JoinRoomView_Night_7_en",20350,],
+["features.joinroom.impl_JoinRoomView_Day_8_en","features.joinroom.impl_JoinRoomView_Night_8_en",20350,],
+["features.joinroom.impl_JoinRoomView_Day_9_en","features.joinroom.impl_JoinRoomView_Night_9_en",20350,],
+["features.knockrequests.impl.banner_KnockRequestsBannerView_Day_0_en","features.knockrequests.impl.banner_KnockRequestsBannerView_Night_0_en",20350,],
+["features.knockrequests.impl.banner_KnockRequestsBannerView_Day_1_en","features.knockrequests.impl.banner_KnockRequestsBannerView_Night_1_en",20350,],
+["features.knockrequests.impl.banner_KnockRequestsBannerView_Day_2_en","features.knockrequests.impl.banner_KnockRequestsBannerView_Night_2_en",20350,],
+["features.knockrequests.impl.banner_KnockRequestsBannerView_Day_3_en","features.knockrequests.impl.banner_KnockRequestsBannerView_Night_3_en",20350,],
+["features.knockrequests.impl.banner_KnockRequestsBannerView_Day_4_en","features.knockrequests.impl.banner_KnockRequestsBannerView_Night_4_en",20350,],
+["features.knockrequests.impl.banner_KnockRequestsBannerView_Day_5_en","features.knockrequests.impl.banner_KnockRequestsBannerView_Night_5_en",20350,],
+["features.knockrequests.impl.banner_KnockRequestsBannerView_Day_6_en","features.knockrequests.impl.banner_KnockRequestsBannerView_Night_6_en",20350,],
+["features.knockrequests.impl.list_KnockRequestsListView_Day_0_en","features.knockrequests.impl.list_KnockRequestsListView_Night_0_en",20350,],
+["features.knockrequests.impl.list_KnockRequestsListView_Day_10_en","features.knockrequests.impl.list_KnockRequestsListView_Night_10_en",20350,],
+["features.knockrequests.impl.list_KnockRequestsListView_Day_1_en","features.knockrequests.impl.list_KnockRequestsListView_Night_1_en",20350,],
+["features.knockrequests.impl.list_KnockRequestsListView_Day_2_en","features.knockrequests.impl.list_KnockRequestsListView_Night_2_en",20350,],
+["features.knockrequests.impl.list_KnockRequestsListView_Day_3_en","features.knockrequests.impl.list_KnockRequestsListView_Night_3_en",20350,],
+["features.knockrequests.impl.list_KnockRequestsListView_Day_4_en","features.knockrequests.impl.list_KnockRequestsListView_Night_4_en",20350,],
+["features.knockrequests.impl.list_KnockRequestsListView_Day_5_en","features.knockrequests.impl.list_KnockRequestsListView_Night_5_en",20350,],
+["features.knockrequests.impl.list_KnockRequestsListView_Day_6_en","features.knockrequests.impl.list_KnockRequestsListView_Night_6_en",20350,],
+["features.knockrequests.impl.list_KnockRequestsListView_Day_7_en","features.knockrequests.impl.list_KnockRequestsListView_Night_7_en",20350,],
+["features.knockrequests.impl.list_KnockRequestsListView_Day_8_en","features.knockrequests.impl.list_KnockRequestsListView_Night_8_en",20350,],
+["features.knockrequests.impl.list_KnockRequestsListView_Day_9_en","features.knockrequests.impl.list_KnockRequestsListView_Night_9_en",20350,],
["libraries.designsystem.components_LabelledCheckbox_Toggles_en","",0,],
["features.leaveroom.impl_LeaveRoomView_Day_0_en","features.leaveroom.impl_LeaveRoomView_Night_0_en",0,],
-["features.leaveroom.impl_LeaveRoomView_Day_1_en","features.leaveroom.impl_LeaveRoomView_Night_1_en",20336,],
-["features.leaveroom.impl_LeaveRoomView_Day_2_en","features.leaveroom.impl_LeaveRoomView_Night_2_en",20336,],
-["features.leaveroom.impl_LeaveRoomView_Day_3_en","features.leaveroom.impl_LeaveRoomView_Night_3_en",20336,],
-["features.leaveroom.impl_LeaveRoomView_Day_4_en","features.leaveroom.impl_LeaveRoomView_Night_4_en",20336,],
-["features.leaveroom.impl_LeaveRoomView_Day_5_en","features.leaveroom.impl_LeaveRoomView_Night_5_en",20336,],
-["features.leaveroom.impl_LeaveRoomView_Day_6_en","features.leaveroom.impl_LeaveRoomView_Night_6_en",20336,],
-["features.leaveroom.impl_LeaveRoomView_Day_7_en","features.leaveroom.impl_LeaveRoomView_Night_7_en",20336,],
+["features.leaveroom.impl_LeaveRoomView_Day_1_en","features.leaveroom.impl_LeaveRoomView_Night_1_en",20350,],
+["features.leaveroom.impl_LeaveRoomView_Day_2_en","features.leaveroom.impl_LeaveRoomView_Night_2_en",20350,],
+["features.leaveroom.impl_LeaveRoomView_Day_3_en","features.leaveroom.impl_LeaveRoomView_Night_3_en",20350,],
+["features.leaveroom.impl_LeaveRoomView_Day_4_en","features.leaveroom.impl_LeaveRoomView_Night_4_en",20350,],
+["features.leaveroom.impl_LeaveRoomView_Day_5_en","features.leaveroom.impl_LeaveRoomView_Night_5_en",20350,],
+["features.leaveroom.impl_LeaveRoomView_Day_6_en","features.leaveroom.impl_LeaveRoomView_Night_6_en",20350,],
+["features.leaveroom.impl_LeaveRoomView_Day_7_en","features.leaveroom.impl_LeaveRoomView_Night_7_en",20350,],
["libraries.designsystem.background_LightGradientBackground_Day_0_en","libraries.designsystem.background_LightGradientBackground_Night_0_en",0,],
["libraries.designsystem.theme.components_LinearProgressIndicator_Progress_Indicators_en","",0,],
["features.messages.impl.link_LinkView_Day_0_en","features.messages.impl.link_LinkView_Night_0_en",0,],
-["features.messages.impl.link_LinkView_Day_1_en","features.messages.impl.link_LinkView_Night_1_en",20336,],
+["features.messages.impl.link_LinkView_Day_1_en","features.messages.impl.link_LinkView_Night_1_en",20350,],
["libraries.designsystem.components.dialogs_ListDialogContent_Dialogs_en","",0,],
["libraries.designsystem.components.dialogs_ListDialog_Day_0_en","libraries.designsystem.components.dialogs_ListDialog_Night_0_en",0,],
["libraries.designsystem.theme.components_ListItemPrimaryActionWithIcon_List_item_-_Primary_action_&_Icon_List_items_en","",0,],
@@ -633,36 +632,36 @@ export const screenshots = [
["libraries.designsystem.theme.components_ListSupportingTextSmallPadding_List_supporting_text_-_small_padding_List_sections_en","",0,],
["libraries.textcomposer.components_LiveWaveformView_Day_0_en","libraries.textcomposer.components_LiveWaveformView_Night_0_en",0,],
["appnav.room.joined_LoadingRoomNodeView_Day_0_en","appnav.room.joined_LoadingRoomNodeView_Night_0_en",0,],
-["appnav.room.joined_LoadingRoomNodeView_Day_1_en","appnav.room.joined_LoadingRoomNodeView_Night_1_en",20336,],
-["features.lockscreen.impl.settings_LockScreenSettingsView_Day_0_en","features.lockscreen.impl.settings_LockScreenSettingsView_Night_0_en",20336,],
-["features.lockscreen.impl.settings_LockScreenSettingsView_Day_1_en","features.lockscreen.impl.settings_LockScreenSettingsView_Night_1_en",20336,],
-["features.lockscreen.impl.settings_LockScreenSettingsView_Day_2_en","features.lockscreen.impl.settings_LockScreenSettingsView_Night_2_en",20336,],
+["appnav.room.joined_LoadingRoomNodeView_Day_1_en","appnav.room.joined_LoadingRoomNodeView_Night_1_en",20350,],
+["features.lockscreen.impl.settings_LockScreenSettingsView_Day_0_en","features.lockscreen.impl.settings_LockScreenSettingsView_Night_0_en",20350,],
+["features.lockscreen.impl.settings_LockScreenSettingsView_Day_1_en","features.lockscreen.impl.settings_LockScreenSettingsView_Night_1_en",20350,],
+["features.lockscreen.impl.settings_LockScreenSettingsView_Day_2_en","features.lockscreen.impl.settings_LockScreenSettingsView_Night_2_en",20350,],
["appnav.loggedin_LoggedInView_Day_0_en","appnav.loggedin_LoggedInView_Night_0_en",0,],
-["appnav.loggedin_LoggedInView_Day_1_en","appnav.loggedin_LoggedInView_Night_1_en",20336,],
-["appnav.loggedin_LoggedInView_Day_2_en","appnav.loggedin_LoggedInView_Night_2_en",20336,],
-["appnav.loggedin_LoggedInView_Day_3_en","appnav.loggedin_LoggedInView_Night_3_en",20336,],
-["features.login.impl.login_LoginModeView_Day_0_en","features.login.impl.login_LoginModeView_Night_0_en",20336,],
-["features.login.impl.login_LoginModeView_Day_1_en","features.login.impl.login_LoginModeView_Night_1_en",20336,],
-["features.login.impl.login_LoginModeView_Day_2_en","features.login.impl.login_LoginModeView_Night_2_en",20336,],
-["features.login.impl.login_LoginModeView_Day_3_en","features.login.impl.login_LoginModeView_Night_3_en",20336,],
-["features.login.impl.login_LoginModeView_Day_4_en","features.login.impl.login_LoginModeView_Night_4_en",20336,],
-["features.login.impl.screens.loginpassword_LoginPasswordView_Day_0_en","features.login.impl.screens.loginpassword_LoginPasswordView_Night_0_en",20336,],
-["features.login.impl.screens.loginpassword_LoginPasswordView_Day_1_en","features.login.impl.screens.loginpassword_LoginPasswordView_Night_1_en",20336,],
-["features.login.impl.screens.loginpassword_LoginPasswordView_Day_2_en","features.login.impl.screens.loginpassword_LoginPasswordView_Night_2_en",20336,],
-["features.logout.impl_LogoutView_Day_0_en","features.logout.impl_LogoutView_Night_0_en",20336,],
-["features.logout.impl_LogoutView_Day_10_en","features.logout.impl_LogoutView_Night_10_en",20336,],
-["features.logout.impl_LogoutView_Day_11_en","features.logout.impl_LogoutView_Night_11_en",20336,],
-["features.logout.impl_LogoutView_Day_1_en","features.logout.impl_LogoutView_Night_1_en",20336,],
-["features.logout.impl_LogoutView_Day_2_en","features.logout.impl_LogoutView_Night_2_en",20336,],
-["features.logout.impl_LogoutView_Day_3_en","features.logout.impl_LogoutView_Night_3_en",20336,],
-["features.logout.impl_LogoutView_Day_4_en","features.logout.impl_LogoutView_Night_4_en",20336,],
-["features.logout.impl_LogoutView_Day_5_en","features.logout.impl_LogoutView_Night_5_en",20336,],
-["features.logout.impl_LogoutView_Day_6_en","features.logout.impl_LogoutView_Night_6_en",20336,],
-["features.logout.impl_LogoutView_Day_7_en","features.logout.impl_LogoutView_Night_7_en",20336,],
-["features.logout.impl_LogoutView_Day_8_en","features.logout.impl_LogoutView_Night_8_en",20336,],
-["features.logout.impl_LogoutView_Day_9_en","features.logout.impl_LogoutView_Night_9_en",20336,],
+["appnav.loggedin_LoggedInView_Day_1_en","appnav.loggedin_LoggedInView_Night_1_en",20350,],
+["appnav.loggedin_LoggedInView_Day_2_en","appnav.loggedin_LoggedInView_Night_2_en",20350,],
+["appnav.loggedin_LoggedInView_Day_3_en","appnav.loggedin_LoggedInView_Night_3_en",20350,],
+["features.login.impl.login_LoginModeView_Day_0_en","features.login.impl.login_LoginModeView_Night_0_en",20350,],
+["features.login.impl.login_LoginModeView_Day_1_en","features.login.impl.login_LoginModeView_Night_1_en",20350,],
+["features.login.impl.login_LoginModeView_Day_2_en","features.login.impl.login_LoginModeView_Night_2_en",20350,],
+["features.login.impl.login_LoginModeView_Day_3_en","features.login.impl.login_LoginModeView_Night_3_en",20350,],
+["features.login.impl.login_LoginModeView_Day_4_en","features.login.impl.login_LoginModeView_Night_4_en",20350,],
+["features.login.impl.screens.loginpassword_LoginPasswordView_Day_0_en","features.login.impl.screens.loginpassword_LoginPasswordView_Night_0_en",20350,],
+["features.login.impl.screens.loginpassword_LoginPasswordView_Day_1_en","features.login.impl.screens.loginpassword_LoginPasswordView_Night_1_en",20350,],
+["features.login.impl.screens.loginpassword_LoginPasswordView_Day_2_en","features.login.impl.screens.loginpassword_LoginPasswordView_Night_2_en",20350,],
+["features.logout.impl_LogoutView_Day_0_en","features.logout.impl_LogoutView_Night_0_en",20350,],
+["features.logout.impl_LogoutView_Day_10_en","features.logout.impl_LogoutView_Night_10_en",20350,],
+["features.logout.impl_LogoutView_Day_11_en","features.logout.impl_LogoutView_Night_11_en",20350,],
+["features.logout.impl_LogoutView_Day_1_en","features.logout.impl_LogoutView_Night_1_en",20350,],
+["features.logout.impl_LogoutView_Day_2_en","features.logout.impl_LogoutView_Night_2_en",20350,],
+["features.logout.impl_LogoutView_Day_3_en","features.logout.impl_LogoutView_Night_3_en",20350,],
+["features.logout.impl_LogoutView_Day_4_en","features.logout.impl_LogoutView_Night_4_en",20350,],
+["features.logout.impl_LogoutView_Day_5_en","features.logout.impl_LogoutView_Night_5_en",20350,],
+["features.logout.impl_LogoutView_Day_6_en","features.logout.impl_LogoutView_Night_6_en",20350,],
+["features.logout.impl_LogoutView_Day_7_en","features.logout.impl_LogoutView_Night_7_en",20350,],
+["features.logout.impl_LogoutView_Day_8_en","features.logout.impl_LogoutView_Night_8_en",20350,],
+["features.logout.impl_LogoutView_Day_9_en","features.logout.impl_LogoutView_Night_9_en",20350,],
["libraries.designsystem.components.button_MainActionButton_Buttons_en","",0,],
-["libraries.textcomposer_MarkdownTextComposerEdit_Day_0_en","libraries.textcomposer_MarkdownTextComposerEdit_Night_0_en",20336,],
+["libraries.textcomposer_MarkdownTextComposerEdit_Day_0_en","libraries.textcomposer_MarkdownTextComposerEdit_Night_0_en",20350,],
["libraries.textcomposer.components.markdown_MarkdownTextInput_Day_0_en","libraries.textcomposer.components.markdown_MarkdownTextInput_Night_0_en",0,],
["libraries.designsystem.atomic.atoms_MatrixBadgeAtomInfo_Day_0_en","libraries.designsystem.atomic.atoms_MatrixBadgeAtomInfo_Night_0_en",0,],
["libraries.designsystem.atomic.atoms_MatrixBadgeAtomNegative_Day_0_en","libraries.designsystem.atomic.atoms_MatrixBadgeAtomNegative_Night_0_en",0,],
@@ -675,22 +674,22 @@ export const screenshots = [
["libraries.matrix.ui.components_MatrixUserRow_Day_1_en","libraries.matrix.ui.components_MatrixUserRow_Night_1_en",0,],
["libraries.mediaviewer.impl.local.audio_MediaAudioView_Day_0_en","libraries.mediaviewer.impl.local.audio_MediaAudioView_Night_0_en",0,],
["libraries.mediaviewer.impl.local.audio_MediaAudioView_Day_1_en","libraries.mediaviewer.impl.local.audio_MediaAudioView_Night_1_en",0,],
-["libraries.mediaviewer.impl.details_MediaDeleteConfirmationBottomSheet_Day_0_en","libraries.mediaviewer.impl.details_MediaDeleteConfirmationBottomSheet_Night_0_en",20336,],
-["libraries.mediaviewer.impl.details_MediaDetailsBottomSheet_Day_0_en","libraries.mediaviewer.impl.details_MediaDetailsBottomSheet_Night_0_en",20336,],
+["libraries.mediaviewer.impl.details_MediaDeleteConfirmationBottomSheet_Day_0_en","libraries.mediaviewer.impl.details_MediaDeleteConfirmationBottomSheet_Night_0_en",20350,],
+["libraries.mediaviewer.impl.details_MediaDetailsBottomSheet_Day_0_en","libraries.mediaviewer.impl.details_MediaDetailsBottomSheet_Night_0_en",20350,],
["libraries.mediaviewer.impl.local.file_MediaFileView_Day_0_en","libraries.mediaviewer.impl.local.file_MediaFileView_Night_0_en",0,],
-["libraries.mediaviewer.impl.gallery_MediaGalleryView_Day_0_en","libraries.mediaviewer.impl.gallery_MediaGalleryView_Night_0_en",20336,],
-["libraries.mediaviewer.impl.gallery_MediaGalleryView_Day_10_en","libraries.mediaviewer.impl.gallery_MediaGalleryView_Night_10_en",20336,],
-["libraries.mediaviewer.impl.gallery_MediaGalleryView_Day_11_en","libraries.mediaviewer.impl.gallery_MediaGalleryView_Night_11_en",20336,],
-["libraries.mediaviewer.impl.gallery_MediaGalleryView_Day_12_en","libraries.mediaviewer.impl.gallery_MediaGalleryView_Night_12_en",20336,],
-["libraries.mediaviewer.impl.gallery_MediaGalleryView_Day_1_en","libraries.mediaviewer.impl.gallery_MediaGalleryView_Night_1_en",20336,],
-["libraries.mediaviewer.impl.gallery_MediaGalleryView_Day_2_en","libraries.mediaviewer.impl.gallery_MediaGalleryView_Night_2_en",20336,],
-["libraries.mediaviewer.impl.gallery_MediaGalleryView_Day_3_en","libraries.mediaviewer.impl.gallery_MediaGalleryView_Night_3_en",20336,],
-["libraries.mediaviewer.impl.gallery_MediaGalleryView_Day_4_en","libraries.mediaviewer.impl.gallery_MediaGalleryView_Night_4_en",20336,],
-["libraries.mediaviewer.impl.gallery_MediaGalleryView_Day_5_en","libraries.mediaviewer.impl.gallery_MediaGalleryView_Night_5_en",20336,],
-["libraries.mediaviewer.impl.gallery_MediaGalleryView_Day_6_en","libraries.mediaviewer.impl.gallery_MediaGalleryView_Night_6_en",20336,],
-["libraries.mediaviewer.impl.gallery_MediaGalleryView_Day_7_en","libraries.mediaviewer.impl.gallery_MediaGalleryView_Night_7_en",20336,],
-["libraries.mediaviewer.impl.gallery_MediaGalleryView_Day_8_en","libraries.mediaviewer.impl.gallery_MediaGalleryView_Night_8_en",20336,],
-["libraries.mediaviewer.impl.gallery_MediaGalleryView_Day_9_en","libraries.mediaviewer.impl.gallery_MediaGalleryView_Night_9_en",20336,],
+["libraries.mediaviewer.impl.gallery_MediaGalleryView_Day_0_en","libraries.mediaviewer.impl.gallery_MediaGalleryView_Night_0_en",20350,],
+["libraries.mediaviewer.impl.gallery_MediaGalleryView_Day_10_en","libraries.mediaviewer.impl.gallery_MediaGalleryView_Night_10_en",20350,],
+["libraries.mediaviewer.impl.gallery_MediaGalleryView_Day_11_en","libraries.mediaviewer.impl.gallery_MediaGalleryView_Night_11_en",20350,],
+["libraries.mediaviewer.impl.gallery_MediaGalleryView_Day_12_en","libraries.mediaviewer.impl.gallery_MediaGalleryView_Night_12_en",20350,],
+["libraries.mediaviewer.impl.gallery_MediaGalleryView_Day_1_en","libraries.mediaviewer.impl.gallery_MediaGalleryView_Night_1_en",20350,],
+["libraries.mediaviewer.impl.gallery_MediaGalleryView_Day_2_en","libraries.mediaviewer.impl.gallery_MediaGalleryView_Night_2_en",20350,],
+["libraries.mediaviewer.impl.gallery_MediaGalleryView_Day_3_en","libraries.mediaviewer.impl.gallery_MediaGalleryView_Night_3_en",20350,],
+["libraries.mediaviewer.impl.gallery_MediaGalleryView_Day_4_en","libraries.mediaviewer.impl.gallery_MediaGalleryView_Night_4_en",20350,],
+["libraries.mediaviewer.impl.gallery_MediaGalleryView_Day_5_en","libraries.mediaviewer.impl.gallery_MediaGalleryView_Night_5_en",20350,],
+["libraries.mediaviewer.impl.gallery_MediaGalleryView_Day_6_en","libraries.mediaviewer.impl.gallery_MediaGalleryView_Night_6_en",20350,],
+["libraries.mediaviewer.impl.gallery_MediaGalleryView_Day_7_en","libraries.mediaviewer.impl.gallery_MediaGalleryView_Night_7_en",20350,],
+["libraries.mediaviewer.impl.gallery_MediaGalleryView_Day_8_en","libraries.mediaviewer.impl.gallery_MediaGalleryView_Night_8_en",20350,],
+["libraries.mediaviewer.impl.gallery_MediaGalleryView_Day_9_en","libraries.mediaviewer.impl.gallery_MediaGalleryView_Night_9_en",20350,],
["libraries.mediaviewer.impl.local.image_MediaImageView_Day_0_en","libraries.mediaviewer.impl.local.image_MediaImageView_Night_0_en",0,],
["libraries.mediaviewer.impl.local.player_MediaPlayerControllerView_Day_0_en","libraries.mediaviewer.impl.local.player_MediaPlayerControllerView_Night_0_en",0,],
["libraries.mediaviewer.impl.local.player_MediaPlayerControllerView_Day_1_en","libraries.mediaviewer.impl.local.player_MediaPlayerControllerView_Night_1_en",0,],
@@ -698,14 +697,14 @@ export const screenshots = [
["libraries.mediaviewer.impl.local.video_MediaVideoView_Day_0_en","libraries.mediaviewer.impl.local.video_MediaVideoView_Night_0_en",0,],
["libraries.mediaviewer.impl.viewer_MediaViewerView_0_en","",0,],
["libraries.mediaviewer.impl.viewer_MediaViewerView_10_en","",0,],
-["libraries.mediaviewer.impl.viewer_MediaViewerView_11_en","",20336,],
-["libraries.mediaviewer.impl.viewer_MediaViewerView_12_en","",20336,],
+["libraries.mediaviewer.impl.viewer_MediaViewerView_11_en","",20350,],
+["libraries.mediaviewer.impl.viewer_MediaViewerView_12_en","",20350,],
["libraries.mediaviewer.impl.viewer_MediaViewerView_13_en","",0,],
-["libraries.mediaviewer.impl.viewer_MediaViewerView_14_en","",20336,],
+["libraries.mediaviewer.impl.viewer_MediaViewerView_14_en","",20350,],
["libraries.mediaviewer.impl.viewer_MediaViewerView_15_en","",0,],
["libraries.mediaviewer.impl.viewer_MediaViewerView_16_en","",0,],
["libraries.mediaviewer.impl.viewer_MediaViewerView_1_en","",0,],
-["libraries.mediaviewer.impl.viewer_MediaViewerView_2_en","",20336,],
+["libraries.mediaviewer.impl.viewer_MediaViewerView_2_en","",20350,],
["libraries.mediaviewer.impl.viewer_MediaViewerView_3_en","",0,],
["libraries.mediaviewer.impl.viewer_MediaViewerView_4_en","",0,],
["libraries.mediaviewer.impl.viewer_MediaViewerView_5_en","",0,],
@@ -719,7 +718,7 @@ export const screenshots = [
["libraries.textcomposer.mentions_MentionSpanTheme_Day_0_en","libraries.textcomposer.mentions_MentionSpanTheme_Night_0_en",0,],
["libraries.designsystem.theme.components.previews_Menu_Menus_en","",0,],
["features.messages.impl.messagecomposer_MessageComposerViewVoice_Day_0_en","features.messages.impl.messagecomposer_MessageComposerViewVoice_Night_0_en",0,],
-["features.messages.impl.messagecomposer_MessageComposerView_Day_0_en","features.messages.impl.messagecomposer_MessageComposerView_Night_0_en",20336,],
+["features.messages.impl.messagecomposer_MessageComposerView_Day_0_en","features.messages.impl.messagecomposer_MessageComposerView_Night_0_en",20350,],
["features.messages.impl.timeline.components_MessageEventBubble_Day_0_en","features.messages.impl.timeline.components_MessageEventBubble_Night_0_en",0,],
["features.messages.impl.timeline.components_MessageEventBubble_Day_1_en","features.messages.impl.timeline.components_MessageEventBubble_Night_1_en",0,],
["features.messages.impl.timeline.components_MessageEventBubble_Day_2_en","features.messages.impl.timeline.components_MessageEventBubble_Night_2_en",0,],
@@ -728,7 +727,7 @@ export const screenshots = [
["features.messages.impl.timeline.components_MessageEventBubble_Day_5_en","features.messages.impl.timeline.components_MessageEventBubble_Night_5_en",0,],
["features.messages.impl.timeline.components_MessageEventBubble_Day_6_en","features.messages.impl.timeline.components_MessageEventBubble_Night_6_en",0,],
["features.messages.impl.timeline.components_MessageEventBubble_Day_7_en","features.messages.impl.timeline.components_MessageEventBubble_Night_7_en",0,],
-["features.messages.impl.timeline.components_MessageShieldView_Day_0_en","features.messages.impl.timeline.components_MessageShieldView_Night_0_en",20336,],
+["features.messages.impl.timeline.components_MessageShieldView_Day_0_en","features.messages.impl.timeline.components_MessageShieldView_Night_0_en",20350,],
["features.messages.impl.timeline.components_MessageStateEventContainer_Day_0_en","features.messages.impl.timeline.components_MessageStateEventContainer_Night_0_en",0,],
["features.messages.impl.timeline.components_MessagesReactionButtonAdd_Day_0_en","features.messages.impl.timeline.components_MessagesReactionButtonAdd_Night_0_en",0,],
["features.messages.impl.timeline.components_MessagesReactionButtonExtra_Day_0_en","features.messages.impl.timeline.components_MessagesReactionButtonExtra_Night_0_en",0,],
@@ -736,27 +735,27 @@ export const screenshots = [
["features.messages.impl.timeline.components_MessagesReactionButton_Day_1_en","features.messages.impl.timeline.components_MessagesReactionButton_Night_1_en",0,],
["features.messages.impl.timeline.components_MessagesReactionButton_Day_2_en","features.messages.impl.timeline.components_MessagesReactionButton_Night_2_en",0,],
["features.messages.impl.timeline.components_MessagesReactionButton_Day_3_en","features.messages.impl.timeline.components_MessagesReactionButton_Night_3_en",0,],
-["features.messages.impl.crypto.identity_MessagesViewWithIdentityChange_Day_0_en","features.messages.impl.crypto.identity_MessagesViewWithIdentityChange_Night_0_en",20336,],
-["features.messages.impl.crypto.identity_MessagesViewWithIdentityChange_Day_1_en","features.messages.impl.crypto.identity_MessagesViewWithIdentityChange_Night_1_en",20336,],
-["features.messages.impl.crypto.identity_MessagesViewWithIdentityChange_Day_2_en","features.messages.impl.crypto.identity_MessagesViewWithIdentityChange_Night_2_en",20336,],
-["features.messages.impl_MessagesView_Day_0_en","features.messages.impl_MessagesView_Night_0_en",20336,],
-["features.messages.impl_MessagesView_Day_10_en","features.messages.impl_MessagesView_Night_10_en",20336,],
-["features.messages.impl_MessagesView_Day_11_en","features.messages.impl_MessagesView_Night_11_en",20336,],
-["features.messages.impl_MessagesView_Day_12_en","features.messages.impl_MessagesView_Night_12_en",20336,],
-["features.messages.impl_MessagesView_Day_13_en","features.messages.impl_MessagesView_Night_13_en",20336,],
-["features.messages.impl_MessagesView_Day_14_en","features.messages.impl_MessagesView_Night_14_en",20336,],
-["features.messages.impl_MessagesView_Day_15_en","features.messages.impl_MessagesView_Night_15_en",20336,],
-["features.messages.impl_MessagesView_Day_1_en","features.messages.impl_MessagesView_Night_1_en",20336,],
-["features.messages.impl_MessagesView_Day_2_en","features.messages.impl_MessagesView_Night_2_en",20336,],
-["features.messages.impl_MessagesView_Day_3_en","features.messages.impl_MessagesView_Night_3_en",20336,],
-["features.messages.impl_MessagesView_Day_4_en","features.messages.impl_MessagesView_Night_4_en",20336,],
-["features.messages.impl_MessagesView_Day_5_en","features.messages.impl_MessagesView_Night_5_en",20336,],
-["features.messages.impl_MessagesView_Day_6_en","features.messages.impl_MessagesView_Night_6_en",20336,],
-["features.messages.impl_MessagesView_Day_7_en","features.messages.impl_MessagesView_Night_7_en",20336,],
-["features.messages.impl_MessagesView_Day_8_en","features.messages.impl_MessagesView_Night_8_en",20336,],
-["features.messages.impl_MessagesView_Day_9_en","features.messages.impl_MessagesView_Night_9_en",20336,],
+["features.messages.impl.crypto.identity_MessagesViewWithIdentityChange_Day_0_en","features.messages.impl.crypto.identity_MessagesViewWithIdentityChange_Night_0_en",20350,],
+["features.messages.impl.crypto.identity_MessagesViewWithIdentityChange_Day_1_en","features.messages.impl.crypto.identity_MessagesViewWithIdentityChange_Night_1_en",20350,],
+["features.messages.impl.crypto.identity_MessagesViewWithIdentityChange_Day_2_en","features.messages.impl.crypto.identity_MessagesViewWithIdentityChange_Night_2_en",20350,],
+["features.messages.impl_MessagesView_Day_0_en","features.messages.impl_MessagesView_Night_0_en",20350,],
+["features.messages.impl_MessagesView_Day_10_en","features.messages.impl_MessagesView_Night_10_en",20350,],
+["features.messages.impl_MessagesView_Day_11_en","features.messages.impl_MessagesView_Night_11_en",20350,],
+["features.messages.impl_MessagesView_Day_12_en","features.messages.impl_MessagesView_Night_12_en",20350,],
+["features.messages.impl_MessagesView_Day_13_en","features.messages.impl_MessagesView_Night_13_en",20350,],
+["features.messages.impl_MessagesView_Day_14_en","features.messages.impl_MessagesView_Night_14_en",20350,],
+["features.messages.impl_MessagesView_Day_15_en","features.messages.impl_MessagesView_Night_15_en",20350,],
+["features.messages.impl_MessagesView_Day_1_en","features.messages.impl_MessagesView_Night_1_en",20350,],
+["features.messages.impl_MessagesView_Day_2_en","features.messages.impl_MessagesView_Night_2_en",20350,],
+["features.messages.impl_MessagesView_Day_3_en","features.messages.impl_MessagesView_Night_3_en",20350,],
+["features.messages.impl_MessagesView_Day_4_en","features.messages.impl_MessagesView_Night_4_en",20350,],
+["features.messages.impl_MessagesView_Day_5_en","features.messages.impl_MessagesView_Night_5_en",20350,],
+["features.messages.impl_MessagesView_Day_6_en","features.messages.impl_MessagesView_Night_6_en",20350,],
+["features.messages.impl_MessagesView_Day_7_en","features.messages.impl_MessagesView_Night_7_en",20350,],
+["features.messages.impl_MessagesView_Day_8_en","features.messages.impl_MessagesView_Night_8_en",20350,],
+["features.messages.impl_MessagesView_Day_9_en","features.messages.impl_MessagesView_Night_9_en",20350,],
["features.migration.impl_MigrationView_Day_0_en","features.migration.impl_MigrationView_Night_0_en",0,],
-["features.migration.impl_MigrationView_Day_1_en","features.migration.impl_MigrationView_Night_1_en",20336,],
+["features.migration.impl_MigrationView_Day_1_en","features.migration.impl_MigrationView_Night_1_en",20350,],
["libraries.designsystem.theme.components_ModalBottomSheetDark_Bottom_Sheets_en","",0,],
["libraries.designsystem.theme.components_ModalBottomSheetLight_Bottom_Sheets_en","",0,],
["appicon.element_MonochromeIcon_en","",0,],
@@ -766,109 +765,109 @@ export const screenshots = [
["libraries.designsystem.components.list_MutipleSelectionListItemSelected_Multiple_selection_List_item_-_selection_in_supporting_text_List_items_en","",0,],
["libraries.designsystem.components.list_MutipleSelectionListItem_Multiple_selection_List_item_-_no_selection_List_items_en","",0,],
["libraries.designsystem.theme.components_NavigationBar_App_Bars_en","",0,],
-["features.preferences.impl.notifications_NotificationSettingsView_Day_0_en","features.preferences.impl.notifications_NotificationSettingsView_Night_0_en",20336,],
-["features.preferences.impl.notifications_NotificationSettingsView_Day_10_en","features.preferences.impl.notifications_NotificationSettingsView_Night_10_en",20336,],
-["features.preferences.impl.notifications_NotificationSettingsView_Day_11_en","features.preferences.impl.notifications_NotificationSettingsView_Night_11_en",20336,],
-["features.preferences.impl.notifications_NotificationSettingsView_Day_12_en","features.preferences.impl.notifications_NotificationSettingsView_Night_12_en",20336,],
-["features.preferences.impl.notifications_NotificationSettingsView_Day_13_en","features.preferences.impl.notifications_NotificationSettingsView_Night_13_en",20336,],
-["features.preferences.impl.notifications_NotificationSettingsView_Day_1_en","features.preferences.impl.notifications_NotificationSettingsView_Night_1_en",20336,],
-["features.preferences.impl.notifications_NotificationSettingsView_Day_2_en","features.preferences.impl.notifications_NotificationSettingsView_Night_2_en",20336,],
-["features.preferences.impl.notifications_NotificationSettingsView_Day_3_en","features.preferences.impl.notifications_NotificationSettingsView_Night_3_en",20336,],
-["features.preferences.impl.notifications_NotificationSettingsView_Day_4_en","features.preferences.impl.notifications_NotificationSettingsView_Night_4_en",20336,],
-["features.preferences.impl.notifications_NotificationSettingsView_Day_5_en","features.preferences.impl.notifications_NotificationSettingsView_Night_5_en",20336,],
-["features.preferences.impl.notifications_NotificationSettingsView_Day_6_en","features.preferences.impl.notifications_NotificationSettingsView_Night_6_en",20336,],
-["features.preferences.impl.notifications_NotificationSettingsView_Day_7_en","features.preferences.impl.notifications_NotificationSettingsView_Night_7_en",20336,],
-["features.preferences.impl.notifications_NotificationSettingsView_Day_8_en","features.preferences.impl.notifications_NotificationSettingsView_Night_8_en",20336,],
-["features.preferences.impl.notifications_NotificationSettingsView_Day_9_en","features.preferences.impl.notifications_NotificationSettingsView_Night_9_en",20336,],
-["features.ftue.impl.notifications_NotificationsOptInView_Day_0_en","features.ftue.impl.notifications_NotificationsOptInView_Night_0_en",20336,],
+["features.preferences.impl.notifications_NotificationSettingsView_Day_0_en","features.preferences.impl.notifications_NotificationSettingsView_Night_0_en",20350,],
+["features.preferences.impl.notifications_NotificationSettingsView_Day_10_en","features.preferences.impl.notifications_NotificationSettingsView_Night_10_en",20350,],
+["features.preferences.impl.notifications_NotificationSettingsView_Day_11_en","features.preferences.impl.notifications_NotificationSettingsView_Night_11_en",20350,],
+["features.preferences.impl.notifications_NotificationSettingsView_Day_12_en","features.preferences.impl.notifications_NotificationSettingsView_Night_12_en",20350,],
+["features.preferences.impl.notifications_NotificationSettingsView_Day_13_en","features.preferences.impl.notifications_NotificationSettingsView_Night_13_en",20350,],
+["features.preferences.impl.notifications_NotificationSettingsView_Day_1_en","features.preferences.impl.notifications_NotificationSettingsView_Night_1_en",20350,],
+["features.preferences.impl.notifications_NotificationSettingsView_Day_2_en","features.preferences.impl.notifications_NotificationSettingsView_Night_2_en",20350,],
+["features.preferences.impl.notifications_NotificationSettingsView_Day_3_en","features.preferences.impl.notifications_NotificationSettingsView_Night_3_en",20350,],
+["features.preferences.impl.notifications_NotificationSettingsView_Day_4_en","features.preferences.impl.notifications_NotificationSettingsView_Night_4_en",20350,],
+["features.preferences.impl.notifications_NotificationSettingsView_Day_5_en","features.preferences.impl.notifications_NotificationSettingsView_Night_5_en",20350,],
+["features.preferences.impl.notifications_NotificationSettingsView_Day_6_en","features.preferences.impl.notifications_NotificationSettingsView_Night_6_en",20350,],
+["features.preferences.impl.notifications_NotificationSettingsView_Day_7_en","features.preferences.impl.notifications_NotificationSettingsView_Night_7_en",20350,],
+["features.preferences.impl.notifications_NotificationSettingsView_Day_8_en","features.preferences.impl.notifications_NotificationSettingsView_Night_8_en",20350,],
+["features.preferences.impl.notifications_NotificationSettingsView_Day_9_en","features.preferences.impl.notifications_NotificationSettingsView_Night_9_en",20350,],
+["features.ftue.impl.notifications_NotificationsOptInView_Day_0_en","features.ftue.impl.notifications_NotificationsOptInView_Night_0_en",20350,],
["libraries.designsystem.atomic.pages_OnBoardingPage_Day_0_en","libraries.designsystem.atomic.pages_OnBoardingPage_Night_0_en",0,],
-["features.login.impl.screens.onboarding_OnBoardingView_Day_0_en","features.login.impl.screens.onboarding_OnBoardingView_Night_0_en",20336,],
-["features.login.impl.screens.onboarding_OnBoardingView_Day_1_en","features.login.impl.screens.onboarding_OnBoardingView_Night_1_en",20336,],
-["features.login.impl.screens.onboarding_OnBoardingView_Day_2_en","features.login.impl.screens.onboarding_OnBoardingView_Night_2_en",20336,],
-["features.login.impl.screens.onboarding_OnBoardingView_Day_3_en","features.login.impl.screens.onboarding_OnBoardingView_Night_3_en",20336,],
-["features.login.impl.screens.onboarding_OnBoardingView_Day_4_en","features.login.impl.screens.onboarding_OnBoardingView_Night_4_en",20336,],
-["features.login.impl.screens.onboarding_OnBoardingView_Day_5_en","features.login.impl.screens.onboarding_OnBoardingView_Night_5_en",20336,],
-["features.login.impl.screens.onboarding_OnBoardingView_Day_6_en","features.login.impl.screens.onboarding_OnBoardingView_Night_6_en",20336,],
+["features.login.impl.screens.onboarding_OnBoardingView_Day_0_en","features.login.impl.screens.onboarding_OnBoardingView_Night_0_en",20350,],
+["features.login.impl.screens.onboarding_OnBoardingView_Day_1_en","features.login.impl.screens.onboarding_OnBoardingView_Night_1_en",20350,],
+["features.login.impl.screens.onboarding_OnBoardingView_Day_2_en","features.login.impl.screens.onboarding_OnBoardingView_Night_2_en",20350,],
+["features.login.impl.screens.onboarding_OnBoardingView_Day_3_en","features.login.impl.screens.onboarding_OnBoardingView_Night_3_en",20350,],
+["features.login.impl.screens.onboarding_OnBoardingView_Day_4_en","features.login.impl.screens.onboarding_OnBoardingView_Night_4_en",20350,],
+["features.login.impl.screens.onboarding_OnBoardingView_Day_5_en","features.login.impl.screens.onboarding_OnBoardingView_Night_5_en",20350,],
+["features.login.impl.screens.onboarding_OnBoardingView_Day_6_en","features.login.impl.screens.onboarding_OnBoardingView_Night_6_en",20350,],
["libraries.designsystem.background_OnboardingBackground_Day_0_en","libraries.designsystem.background_OnboardingBackground_Night_0_en",0,],
-["libraries.matrix.ui.components_OrganizationHeader_Day_0_en","libraries.matrix.ui.components_OrganizationHeader_Night_0_en",20336,],
-["features.verifysession.impl.outgoing_OutgoingVerificationView_Day_0_en","features.verifysession.impl.outgoing_OutgoingVerificationView_Night_0_en",20336,],
-["features.verifysession.impl.outgoing_OutgoingVerificationView_Day_10_en","features.verifysession.impl.outgoing_OutgoingVerificationView_Night_10_en",20336,],
-["features.verifysession.impl.outgoing_OutgoingVerificationView_Day_11_en","features.verifysession.impl.outgoing_OutgoingVerificationView_Night_11_en",20336,],
+["libraries.matrix.ui.components_OrganizationHeader_Day_0_en","libraries.matrix.ui.components_OrganizationHeader_Night_0_en",20350,],
+["features.verifysession.impl.outgoing_OutgoingVerificationView_Day_0_en","features.verifysession.impl.outgoing_OutgoingVerificationView_Night_0_en",20350,],
+["features.verifysession.impl.outgoing_OutgoingVerificationView_Day_10_en","features.verifysession.impl.outgoing_OutgoingVerificationView_Night_10_en",20350,],
+["features.verifysession.impl.outgoing_OutgoingVerificationView_Day_11_en","features.verifysession.impl.outgoing_OutgoingVerificationView_Night_11_en",20350,],
["features.verifysession.impl.outgoing_OutgoingVerificationView_Day_12_en","features.verifysession.impl.outgoing_OutgoingVerificationView_Night_12_en",0,],
["features.verifysession.impl.outgoing_OutgoingVerificationView_Day_13_en","features.verifysession.impl.outgoing_OutgoingVerificationView_Night_13_en",0,],
-["features.verifysession.impl.outgoing_OutgoingVerificationView_Day_1_en","features.verifysession.impl.outgoing_OutgoingVerificationView_Night_1_en",20336,],
-["features.verifysession.impl.outgoing_OutgoingVerificationView_Day_2_en","features.verifysession.impl.outgoing_OutgoingVerificationView_Night_2_en",20336,],
-["features.verifysession.impl.outgoing_OutgoingVerificationView_Day_3_en","features.verifysession.impl.outgoing_OutgoingVerificationView_Night_3_en",20336,],
-["features.verifysession.impl.outgoing_OutgoingVerificationView_Day_4_en","features.verifysession.impl.outgoing_OutgoingVerificationView_Night_4_en",20336,],
-["features.verifysession.impl.outgoing_OutgoingVerificationView_Day_5_en","features.verifysession.impl.outgoing_OutgoingVerificationView_Night_5_en",20336,],
-["features.verifysession.impl.outgoing_OutgoingVerificationView_Day_6_en","features.verifysession.impl.outgoing_OutgoingVerificationView_Night_6_en",20336,],
-["features.verifysession.impl.outgoing_OutgoingVerificationView_Day_7_en","features.verifysession.impl.outgoing_OutgoingVerificationView_Night_7_en",20336,],
-["features.verifysession.impl.outgoing_OutgoingVerificationView_Day_8_en","features.verifysession.impl.outgoing_OutgoingVerificationView_Night_8_en",20336,],
-["features.verifysession.impl.outgoing_OutgoingVerificationView_Day_9_en","features.verifysession.impl.outgoing_OutgoingVerificationView_Night_9_en",20336,],
+["features.verifysession.impl.outgoing_OutgoingVerificationView_Day_1_en","features.verifysession.impl.outgoing_OutgoingVerificationView_Night_1_en",20350,],
+["features.verifysession.impl.outgoing_OutgoingVerificationView_Day_2_en","features.verifysession.impl.outgoing_OutgoingVerificationView_Night_2_en",20350,],
+["features.verifysession.impl.outgoing_OutgoingVerificationView_Day_3_en","features.verifysession.impl.outgoing_OutgoingVerificationView_Night_3_en",20350,],
+["features.verifysession.impl.outgoing_OutgoingVerificationView_Day_4_en","features.verifysession.impl.outgoing_OutgoingVerificationView_Night_4_en",20350,],
+["features.verifysession.impl.outgoing_OutgoingVerificationView_Day_5_en","features.verifysession.impl.outgoing_OutgoingVerificationView_Night_5_en",20350,],
+["features.verifysession.impl.outgoing_OutgoingVerificationView_Day_6_en","features.verifysession.impl.outgoing_OutgoingVerificationView_Night_6_en",20350,],
+["features.verifysession.impl.outgoing_OutgoingVerificationView_Day_7_en","features.verifysession.impl.outgoing_OutgoingVerificationView_Night_7_en",20350,],
+["features.verifysession.impl.outgoing_OutgoingVerificationView_Day_8_en","features.verifysession.impl.outgoing_OutgoingVerificationView_Night_8_en",20350,],
+["features.verifysession.impl.outgoing_OutgoingVerificationView_Day_9_en","features.verifysession.impl.outgoing_OutgoingVerificationView_Night_9_en",20350,],
["libraries.designsystem.theme.components_OutlinedButtonLargeLowPadding_Buttons_en","",0,],
["libraries.designsystem.theme.components_OutlinedButtonLarge_Buttons_en","",0,],
["libraries.designsystem.theme.components_OutlinedButtonMediumLowPadding_Buttons_en","",0,],
["libraries.designsystem.theme.components_OutlinedButtonMedium_Buttons_en","",0,],
["libraries.designsystem.theme.components_OutlinedButtonSmall_Buttons_en","",0,],
-["libraries.mediaviewer.impl.local.pdf_PdfPagesErrorView_Day_0_en","libraries.mediaviewer.impl.local.pdf_PdfPagesErrorView_Night_0_en",20336,],
-["features.changeroommemberroles.impl_PendingMemberRowWithLongName_Day_0_en","features.changeroommemberroles.impl_PendingMemberRowWithLongName_Night_0_en",20336,],
-["libraries.permissions.api_PermissionsView_Day_0_en","libraries.permissions.api_PermissionsView_Night_0_en",20336,],
-["libraries.permissions.api_PermissionsView_Day_1_en","libraries.permissions.api_PermissionsView_Night_1_en",20336,],
-["libraries.permissions.api_PermissionsView_Day_2_en","libraries.permissions.api_PermissionsView_Night_2_en",20336,],
-["libraries.permissions.api_PermissionsView_Day_3_en","libraries.permissions.api_PermissionsView_Night_3_en",20336,],
+["libraries.mediaviewer.impl.local.pdf_PdfPagesErrorView_Day_0_en","libraries.mediaviewer.impl.local.pdf_PdfPagesErrorView_Night_0_en",20350,],
+["features.changeroommemberroles.impl_PendingMemberRowWithLongName_Day_0_en","features.changeroommemberroles.impl_PendingMemberRowWithLongName_Night_0_en",20350,],
+["libraries.permissions.api_PermissionsView_Day_0_en","libraries.permissions.api_PermissionsView_Night_0_en",20350,],
+["libraries.permissions.api_PermissionsView_Day_1_en","libraries.permissions.api_PermissionsView_Night_1_en",20350,],
+["libraries.permissions.api_PermissionsView_Day_2_en","libraries.permissions.api_PermissionsView_Night_2_en",20350,],
+["libraries.permissions.api_PermissionsView_Day_3_en","libraries.permissions.api_PermissionsView_Night_3_en",20350,],
["features.lockscreen.impl.components_PinEntryTextField_Day_0_en","features.lockscreen.impl.components_PinEntryTextField_Night_0_en",0,],
["libraries.designsystem.components_PinIcon_Day_0_en","libraries.designsystem.components_PinIcon_Night_0_en",0,],
["features.lockscreen.impl.unlock.keypad_PinKeypad_Day_0_en","features.lockscreen.impl.unlock.keypad_PinKeypad_Night_0_en",0,],
-["features.lockscreen.impl.unlock_PinUnlockViewInApp_Day_0_en","features.lockscreen.impl.unlock_PinUnlockViewInApp_Night_0_en",20336,],
-["features.lockscreen.impl.unlock_PinUnlockViewInApp_Day_1_en","features.lockscreen.impl.unlock_PinUnlockViewInApp_Night_1_en",20336,],
-["features.lockscreen.impl.unlock_PinUnlockViewInApp_Day_2_en","features.lockscreen.impl.unlock_PinUnlockViewInApp_Night_2_en",20336,],
-["features.lockscreen.impl.unlock_PinUnlockViewInApp_Day_3_en","features.lockscreen.impl.unlock_PinUnlockViewInApp_Night_3_en",20336,],
-["features.lockscreen.impl.unlock_PinUnlockViewInApp_Day_4_en","features.lockscreen.impl.unlock_PinUnlockViewInApp_Night_4_en",20336,],
-["features.lockscreen.impl.unlock_PinUnlockViewInApp_Day_5_en","features.lockscreen.impl.unlock_PinUnlockViewInApp_Night_5_en",20336,],
-["features.lockscreen.impl.unlock_PinUnlockViewInApp_Day_6_en","features.lockscreen.impl.unlock_PinUnlockViewInApp_Night_6_en",20336,],
-["features.lockscreen.impl.unlock_PinUnlockViewInApp_Day_7_en","features.lockscreen.impl.unlock_PinUnlockViewInApp_Night_7_en",20336,],
-["features.lockscreen.impl.unlock_PinUnlockView_Day_0_en","features.lockscreen.impl.unlock_PinUnlockView_Night_0_en",20336,],
-["features.lockscreen.impl.unlock_PinUnlockView_Day_1_en","features.lockscreen.impl.unlock_PinUnlockView_Night_1_en",20336,],
-["features.lockscreen.impl.unlock_PinUnlockView_Day_2_en","features.lockscreen.impl.unlock_PinUnlockView_Night_2_en",20336,],
-["features.lockscreen.impl.unlock_PinUnlockView_Day_3_en","features.lockscreen.impl.unlock_PinUnlockView_Night_3_en",20336,],
-["features.lockscreen.impl.unlock_PinUnlockView_Day_4_en","features.lockscreen.impl.unlock_PinUnlockView_Night_4_en",20336,],
-["features.lockscreen.impl.unlock_PinUnlockView_Day_5_en","features.lockscreen.impl.unlock_PinUnlockView_Night_5_en",20336,],
-["features.lockscreen.impl.unlock_PinUnlockView_Day_6_en","features.lockscreen.impl.unlock_PinUnlockView_Night_6_en",20336,],
-["features.lockscreen.impl.unlock_PinUnlockView_Day_7_en","features.lockscreen.impl.unlock_PinUnlockView_Night_7_en",20336,],
+["features.lockscreen.impl.unlock_PinUnlockViewInApp_Day_0_en","features.lockscreen.impl.unlock_PinUnlockViewInApp_Night_0_en",20350,],
+["features.lockscreen.impl.unlock_PinUnlockViewInApp_Day_1_en","features.lockscreen.impl.unlock_PinUnlockViewInApp_Night_1_en",20350,],
+["features.lockscreen.impl.unlock_PinUnlockViewInApp_Day_2_en","features.lockscreen.impl.unlock_PinUnlockViewInApp_Night_2_en",20350,],
+["features.lockscreen.impl.unlock_PinUnlockViewInApp_Day_3_en","features.lockscreen.impl.unlock_PinUnlockViewInApp_Night_3_en",20350,],
+["features.lockscreen.impl.unlock_PinUnlockViewInApp_Day_4_en","features.lockscreen.impl.unlock_PinUnlockViewInApp_Night_4_en",20350,],
+["features.lockscreen.impl.unlock_PinUnlockViewInApp_Day_5_en","features.lockscreen.impl.unlock_PinUnlockViewInApp_Night_5_en",20350,],
+["features.lockscreen.impl.unlock_PinUnlockViewInApp_Day_6_en","features.lockscreen.impl.unlock_PinUnlockViewInApp_Night_6_en",20350,],
+["features.lockscreen.impl.unlock_PinUnlockViewInApp_Day_7_en","features.lockscreen.impl.unlock_PinUnlockViewInApp_Night_7_en",20350,],
+["features.lockscreen.impl.unlock_PinUnlockView_Day_0_en","features.lockscreen.impl.unlock_PinUnlockView_Night_0_en",20350,],
+["features.lockscreen.impl.unlock_PinUnlockView_Day_1_en","features.lockscreen.impl.unlock_PinUnlockView_Night_1_en",20350,],
+["features.lockscreen.impl.unlock_PinUnlockView_Day_2_en","features.lockscreen.impl.unlock_PinUnlockView_Night_2_en",20350,],
+["features.lockscreen.impl.unlock_PinUnlockView_Day_3_en","features.lockscreen.impl.unlock_PinUnlockView_Night_3_en",20350,],
+["features.lockscreen.impl.unlock_PinUnlockView_Day_4_en","features.lockscreen.impl.unlock_PinUnlockView_Night_4_en",20350,],
+["features.lockscreen.impl.unlock_PinUnlockView_Day_5_en","features.lockscreen.impl.unlock_PinUnlockView_Night_5_en",20350,],
+["features.lockscreen.impl.unlock_PinUnlockView_Day_6_en","features.lockscreen.impl.unlock_PinUnlockView_Night_6_en",20350,],
+["features.lockscreen.impl.unlock_PinUnlockView_Day_7_en","features.lockscreen.impl.unlock_PinUnlockView_Night_7_en",20350,],
["features.messages.impl.pinned.banner_PinnedMessagesBannerView_Day_0_en","features.messages.impl.pinned.banner_PinnedMessagesBannerView_Night_0_en",0,],
-["features.messages.impl.pinned.banner_PinnedMessagesBannerView_Day_10_en","features.messages.impl.pinned.banner_PinnedMessagesBannerView_Night_10_en",20336,],
-["features.messages.impl.pinned.banner_PinnedMessagesBannerView_Day_1_en","features.messages.impl.pinned.banner_PinnedMessagesBannerView_Night_1_en",20336,],
-["features.messages.impl.pinned.banner_PinnedMessagesBannerView_Day_2_en","features.messages.impl.pinned.banner_PinnedMessagesBannerView_Night_2_en",20336,],
-["features.messages.impl.pinned.banner_PinnedMessagesBannerView_Day_3_en","features.messages.impl.pinned.banner_PinnedMessagesBannerView_Night_3_en",20336,],
-["features.messages.impl.pinned.banner_PinnedMessagesBannerView_Day_4_en","features.messages.impl.pinned.banner_PinnedMessagesBannerView_Night_4_en",20336,],
-["features.messages.impl.pinned.banner_PinnedMessagesBannerView_Day_5_en","features.messages.impl.pinned.banner_PinnedMessagesBannerView_Night_5_en",20336,],
-["features.messages.impl.pinned.banner_PinnedMessagesBannerView_Day_6_en","features.messages.impl.pinned.banner_PinnedMessagesBannerView_Night_6_en",20336,],
-["features.messages.impl.pinned.banner_PinnedMessagesBannerView_Day_7_en","features.messages.impl.pinned.banner_PinnedMessagesBannerView_Night_7_en",20336,],
-["features.messages.impl.pinned.banner_PinnedMessagesBannerView_Day_8_en","features.messages.impl.pinned.banner_PinnedMessagesBannerView_Night_8_en",20336,],
-["features.messages.impl.pinned.banner_PinnedMessagesBannerView_Day_9_en","features.messages.impl.pinned.banner_PinnedMessagesBannerView_Night_9_en",20336,],
-["features.messages.impl.pinned.list_PinnedMessagesListView_Day_0_en","features.messages.impl.pinned.list_PinnedMessagesListView_Night_0_en",20336,],
-["features.messages.impl.pinned.list_PinnedMessagesListView_Day_1_en","features.messages.impl.pinned.list_PinnedMessagesListView_Night_1_en",20336,],
-["features.messages.impl.pinned.list_PinnedMessagesListView_Day_2_en","features.messages.impl.pinned.list_PinnedMessagesListView_Night_2_en",20336,],
-["features.messages.impl.pinned.list_PinnedMessagesListView_Day_3_en","features.messages.impl.pinned.list_PinnedMessagesListView_Night_3_en",20336,],
+["features.messages.impl.pinned.banner_PinnedMessagesBannerView_Day_10_en","features.messages.impl.pinned.banner_PinnedMessagesBannerView_Night_10_en",20350,],
+["features.messages.impl.pinned.banner_PinnedMessagesBannerView_Day_1_en","features.messages.impl.pinned.banner_PinnedMessagesBannerView_Night_1_en",20350,],
+["features.messages.impl.pinned.banner_PinnedMessagesBannerView_Day_2_en","features.messages.impl.pinned.banner_PinnedMessagesBannerView_Night_2_en",20350,],
+["features.messages.impl.pinned.banner_PinnedMessagesBannerView_Day_3_en","features.messages.impl.pinned.banner_PinnedMessagesBannerView_Night_3_en",20350,],
+["features.messages.impl.pinned.banner_PinnedMessagesBannerView_Day_4_en","features.messages.impl.pinned.banner_PinnedMessagesBannerView_Night_4_en",20350,],
+["features.messages.impl.pinned.banner_PinnedMessagesBannerView_Day_5_en","features.messages.impl.pinned.banner_PinnedMessagesBannerView_Night_5_en",20350,],
+["features.messages.impl.pinned.banner_PinnedMessagesBannerView_Day_6_en","features.messages.impl.pinned.banner_PinnedMessagesBannerView_Night_6_en",20350,],
+["features.messages.impl.pinned.banner_PinnedMessagesBannerView_Day_7_en","features.messages.impl.pinned.banner_PinnedMessagesBannerView_Night_7_en",20350,],
+["features.messages.impl.pinned.banner_PinnedMessagesBannerView_Day_8_en","features.messages.impl.pinned.banner_PinnedMessagesBannerView_Night_8_en",20350,],
+["features.messages.impl.pinned.banner_PinnedMessagesBannerView_Day_9_en","features.messages.impl.pinned.banner_PinnedMessagesBannerView_Night_9_en",20350,],
+["features.messages.impl.pinned.list_PinnedMessagesListView_Day_0_en","features.messages.impl.pinned.list_PinnedMessagesListView_Night_0_en",20350,],
+["features.messages.impl.pinned.list_PinnedMessagesListView_Day_1_en","features.messages.impl.pinned.list_PinnedMessagesListView_Night_1_en",20350,],
+["features.messages.impl.pinned.list_PinnedMessagesListView_Day_2_en","features.messages.impl.pinned.list_PinnedMessagesListView_Night_2_en",20350,],
+["features.messages.impl.pinned.list_PinnedMessagesListView_Day_3_en","features.messages.impl.pinned.list_PinnedMessagesListView_Night_3_en",20350,],
["libraries.designsystem.atomic.atoms_PlaceholderAtom_Day_0_en","libraries.designsystem.atomic.atoms_PlaceholderAtom_Night_0_en",0,],
-["features.poll.api.pollcontent_PollAnswerViewDisclosedNotSelected_Day_0_en","features.poll.api.pollcontent_PollAnswerViewDisclosedNotSelected_Night_0_en",20336,],
-["features.poll.api.pollcontent_PollAnswerViewDisclosedSelected_Day_0_en","features.poll.api.pollcontent_PollAnswerViewDisclosedSelected_Night_0_en",20336,],
-["features.poll.api.pollcontent_PollAnswerViewEndedSelected_Day_0_en","features.poll.api.pollcontent_PollAnswerViewEndedSelected_Night_0_en",20336,],
-["features.poll.api.pollcontent_PollAnswerViewEndedWinnerNotSelected_Day_0_en","features.poll.api.pollcontent_PollAnswerViewEndedWinnerNotSelected_Night_0_en",20336,],
-["features.poll.api.pollcontent_PollAnswerViewEndedWinnerSelected_Day_0_en","features.poll.api.pollcontent_PollAnswerViewEndedWinnerSelected_Night_0_en",20336,],
+["features.poll.api.pollcontent_PollAnswerViewDisclosedNotSelected_Day_0_en","features.poll.api.pollcontent_PollAnswerViewDisclosedNotSelected_Night_0_en",20350,],
+["features.poll.api.pollcontent_PollAnswerViewDisclosedSelected_Day_0_en","features.poll.api.pollcontent_PollAnswerViewDisclosedSelected_Night_0_en",20350,],
+["features.poll.api.pollcontent_PollAnswerViewEndedSelected_Day_0_en","features.poll.api.pollcontent_PollAnswerViewEndedSelected_Night_0_en",20350,],
+["features.poll.api.pollcontent_PollAnswerViewEndedWinnerNotSelected_Day_0_en","features.poll.api.pollcontent_PollAnswerViewEndedWinnerNotSelected_Night_0_en",20350,],
+["features.poll.api.pollcontent_PollAnswerViewEndedWinnerSelected_Day_0_en","features.poll.api.pollcontent_PollAnswerViewEndedWinnerSelected_Night_0_en",20350,],
["features.poll.api.pollcontent_PollAnswerViewUndisclosedNotSelected_Day_0_en","features.poll.api.pollcontent_PollAnswerViewUndisclosedNotSelected_Night_0_en",0,],
["features.poll.api.pollcontent_PollAnswerViewUndisclosedSelected_Day_0_en","features.poll.api.pollcontent_PollAnswerViewUndisclosedSelected_Night_0_en",0,],
-["features.poll.api.pollcontent_PollContentViewCreatorEditable_Day_0_en","features.poll.api.pollcontent_PollContentViewCreatorEditable_Night_0_en",20336,],
-["features.poll.api.pollcontent_PollContentViewCreatorEnded_Day_0_en","features.poll.api.pollcontent_PollContentViewCreatorEnded_Night_0_en",20336,],
-["features.poll.api.pollcontent_PollContentViewCreator_Day_0_en","features.poll.api.pollcontent_PollContentViewCreator_Night_0_en",20336,],
-["features.poll.api.pollcontent_PollContentViewDisclosed_Day_0_en","features.poll.api.pollcontent_PollContentViewDisclosed_Night_0_en",20336,],
-["features.poll.api.pollcontent_PollContentViewEnded_Day_0_en","features.poll.api.pollcontent_PollContentViewEnded_Night_0_en",20336,],
-["features.poll.api.pollcontent_PollContentViewUndisclosed_Day_0_en","features.poll.api.pollcontent_PollContentViewUndisclosed_Night_0_en",20336,],
-["features.poll.impl.history_PollHistoryView_Day_0_en","features.poll.impl.history_PollHistoryView_Night_0_en",20336,],
-["features.poll.impl.history_PollHistoryView_Day_1_en","features.poll.impl.history_PollHistoryView_Night_1_en",20336,],
-["features.poll.impl.history_PollHistoryView_Day_2_en","features.poll.impl.history_PollHistoryView_Night_2_en",20336,],
-["features.poll.impl.history_PollHistoryView_Day_3_en","features.poll.impl.history_PollHistoryView_Night_3_en",20336,],
-["features.poll.impl.history_PollHistoryView_Day_4_en","features.poll.impl.history_PollHistoryView_Night_4_en",20336,],
+["features.poll.api.pollcontent_PollContentViewCreatorEditable_Day_0_en","features.poll.api.pollcontent_PollContentViewCreatorEditable_Night_0_en",20350,],
+["features.poll.api.pollcontent_PollContentViewCreatorEnded_Day_0_en","features.poll.api.pollcontent_PollContentViewCreatorEnded_Night_0_en",20350,],
+["features.poll.api.pollcontent_PollContentViewCreator_Day_0_en","features.poll.api.pollcontent_PollContentViewCreator_Night_0_en",20350,],
+["features.poll.api.pollcontent_PollContentViewDisclosed_Day_0_en","features.poll.api.pollcontent_PollContentViewDisclosed_Night_0_en",20350,],
+["features.poll.api.pollcontent_PollContentViewEnded_Day_0_en","features.poll.api.pollcontent_PollContentViewEnded_Night_0_en",20350,],
+["features.poll.api.pollcontent_PollContentViewUndisclosed_Day_0_en","features.poll.api.pollcontent_PollContentViewUndisclosed_Night_0_en",20350,],
+["features.poll.impl.history_PollHistoryView_Day_0_en","features.poll.impl.history_PollHistoryView_Night_0_en",20350,],
+["features.poll.impl.history_PollHistoryView_Day_1_en","features.poll.impl.history_PollHistoryView_Night_1_en",20350,],
+["features.poll.impl.history_PollHistoryView_Day_2_en","features.poll.impl.history_PollHistoryView_Night_2_en",20350,],
+["features.poll.impl.history_PollHistoryView_Day_3_en","features.poll.impl.history_PollHistoryView_Night_3_en",20350,],
+["features.poll.impl.history_PollHistoryView_Day_4_en","features.poll.impl.history_PollHistoryView_Night_4_en",20350,],
["features.poll.api.pollcontent_PollTitleView_Day_0_en","features.poll.api.pollcontent_PollTitleView_Night_0_en",0,],
["libraries.designsystem.components.preferences_PreferenceCategory_Preferences_en","",0,],
["libraries.designsystem.components.preferences_PreferenceCheckbox_Preferences_en","",0,],
@@ -882,203 +881,206 @@ export const screenshots = [
["libraries.designsystem.components.preferences_PreferenceRow_Preferences_en","",0,],
["libraries.designsystem.components.preferences_PreferenceSlide_Preferences_en","",0,],
["libraries.designsystem.components.preferences_PreferenceSwitch_Preferences_en","",0,],
-["features.preferences.impl.root_PreferencesRootViewDark_0_en","",20336,],
-["features.preferences.impl.root_PreferencesRootViewDark_1_en","",20336,],
-["features.preferences.impl.root_PreferencesRootViewLight_0_en","",20336,],
-["features.preferences.impl.root_PreferencesRootViewLight_1_en","",20336,],
+["features.preferences.impl.root_PreferencesRootViewDark_0_en","",20350,],
+["features.preferences.impl.root_PreferencesRootViewDark_1_en","",20350,],
+["features.preferences.impl.root_PreferencesRootViewLight_0_en","",20350,],
+["features.preferences.impl.root_PreferencesRootViewLight_1_en","",20350,],
["features.messages.impl.timeline.components.event_ProgressButton_Day_0_en","features.messages.impl.timeline.components.event_ProgressButton_Night_0_en",0,],
-["libraries.designsystem.components_ProgressDialogContent_Dialogs_en","",20336,],
-["libraries.designsystem.components_ProgressDialog_Day_0_en","libraries.designsystem.components_ProgressDialog_Night_0_en",20336,],
-["features.messages.impl.timeline.protection_ProtectedView_Day_0_en","features.messages.impl.timeline.protection_ProtectedView_Night_0_en",20336,],
-["features.messages.impl.timeline.protection_ProtectedView_Day_1_en","features.messages.impl.timeline.protection_ProtectedView_Night_1_en",20336,],
-["features.messages.impl.timeline.protection_ProtectedView_Day_2_en","features.messages.impl.timeline.protection_ProtectedView_Night_2_en",20336,],
-["features.messages.impl.timeline.protection_ProtectedView_Day_3_en","features.messages.impl.timeline.protection_ProtectedView_Night_3_en",20336,],
-["libraries.troubleshoot.impl.history_PushHistoryView_Day_0_en","libraries.troubleshoot.impl.history_PushHistoryView_Night_0_en",20336,],
-["libraries.troubleshoot.impl.history_PushHistoryView_Day_1_en","libraries.troubleshoot.impl.history_PushHistoryView_Night_1_en",20336,],
-["libraries.troubleshoot.impl.history_PushHistoryView_Day_2_en","libraries.troubleshoot.impl.history_PushHistoryView_Night_2_en",20336,],
-["features.login.impl.screens.qrcode.confirmation_QrCodeConfirmationView_Day_0_en","features.login.impl.screens.qrcode.confirmation_QrCodeConfirmationView_Night_0_en",20336,],
-["features.login.impl.screens.qrcode.confirmation_QrCodeConfirmationView_Day_1_en","features.login.impl.screens.qrcode.confirmation_QrCodeConfirmationView_Night_1_en",20336,],
-["features.login.impl.screens.qrcode.confirmation_QrCodeConfirmationView_Day_2_en","features.login.impl.screens.qrcode.confirmation_QrCodeConfirmationView_Night_2_en",20336,],
-["features.login.impl.screens.qrcode.error_QrCodeErrorView_Day_0_en","features.login.impl.screens.qrcode.error_QrCodeErrorView_Night_0_en",20336,],
-["features.login.impl.screens.qrcode.error_QrCodeErrorView_Day_1_en","features.login.impl.screens.qrcode.error_QrCodeErrorView_Night_1_en",20336,],
-["features.login.impl.screens.qrcode.error_QrCodeErrorView_Day_2_en","features.login.impl.screens.qrcode.error_QrCodeErrorView_Night_2_en",20336,],
-["features.login.impl.screens.qrcode.error_QrCodeErrorView_Day_3_en","features.login.impl.screens.qrcode.error_QrCodeErrorView_Night_3_en",20336,],
-["features.login.impl.screens.qrcode.error_QrCodeErrorView_Day_4_en","features.login.impl.screens.qrcode.error_QrCodeErrorView_Night_4_en",20336,],
-["features.login.impl.screens.qrcode.error_QrCodeErrorView_Day_5_en","features.login.impl.screens.qrcode.error_QrCodeErrorView_Night_5_en",20336,],
-["features.login.impl.screens.qrcode.error_QrCodeErrorView_Day_6_en","features.login.impl.screens.qrcode.error_QrCodeErrorView_Night_6_en",20336,],
-["features.login.impl.screens.qrcode.intro_QrCodeIntroView_Day_0_en","features.login.impl.screens.qrcode.intro_QrCodeIntroView_Night_0_en",20336,],
-["features.login.impl.screens.qrcode.intro_QrCodeIntroView_Day_1_en","features.login.impl.screens.qrcode.intro_QrCodeIntroView_Night_1_en",20336,],
-["features.login.impl.screens.qrcode.scan_QrCodeScanView_Day_0_en","features.login.impl.screens.qrcode.scan_QrCodeScanView_Night_0_en",20336,],
-["features.login.impl.screens.qrcode.scan_QrCodeScanView_Day_1_en","features.login.impl.screens.qrcode.scan_QrCodeScanView_Night_1_en",20336,],
-["features.login.impl.screens.qrcode.scan_QrCodeScanView_Day_2_en","features.login.impl.screens.qrcode.scan_QrCodeScanView_Night_2_en",20336,],
-["features.login.impl.screens.qrcode.scan_QrCodeScanView_Day_3_en","features.login.impl.screens.qrcode.scan_QrCodeScanView_Night_3_en",20336,],
-["features.login.impl.screens.qrcode.scan_QrCodeScanView_Day_4_en","features.login.impl.screens.qrcode.scan_QrCodeScanView_Night_4_en",20336,],
-["features.login.impl.screens.qrcode.scan_QrCodeScanView_Day_5_en","features.login.impl.screens.qrcode.scan_QrCodeScanView_Night_5_en",20336,],
+["libraries.designsystem.components_ProgressDialogContent_Dialogs_en","",20350,],
+["libraries.designsystem.components_ProgressDialogWithContent_Day_0_en","libraries.designsystem.components_ProgressDialogWithContent_Night_0_en",20350,],
+["libraries.designsystem.components_ProgressDialogWithTextAndContent_Day_0_en","libraries.designsystem.components_ProgressDialogWithTextAndContent_Night_0_en",0,],
+["libraries.designsystem.components_ProgressDialog_Day_0_en","libraries.designsystem.components_ProgressDialog_Night_0_en",20350,],
+["features.messages.impl.timeline.protection_ProtectedView_Day_0_en","features.messages.impl.timeline.protection_ProtectedView_Night_0_en",20350,],
+["features.messages.impl.timeline.protection_ProtectedView_Day_1_en","features.messages.impl.timeline.protection_ProtectedView_Night_1_en",20350,],
+["features.messages.impl.timeline.protection_ProtectedView_Day_2_en","features.messages.impl.timeline.protection_ProtectedView_Night_2_en",20350,],
+["features.messages.impl.timeline.protection_ProtectedView_Day_3_en","features.messages.impl.timeline.protection_ProtectedView_Night_3_en",20350,],
+["libraries.troubleshoot.impl.history_PushHistoryView_Day_0_en","libraries.troubleshoot.impl.history_PushHistoryView_Night_0_en",20350,],
+["libraries.troubleshoot.impl.history_PushHistoryView_Day_1_en","libraries.troubleshoot.impl.history_PushHistoryView_Night_1_en",20350,],
+["libraries.troubleshoot.impl.history_PushHistoryView_Day_2_en","libraries.troubleshoot.impl.history_PushHistoryView_Night_2_en",20350,],
+["features.login.impl.screens.qrcode.confirmation_QrCodeConfirmationView_Day_0_en","features.login.impl.screens.qrcode.confirmation_QrCodeConfirmationView_Night_0_en",20350,],
+["features.login.impl.screens.qrcode.confirmation_QrCodeConfirmationView_Day_1_en","features.login.impl.screens.qrcode.confirmation_QrCodeConfirmationView_Night_1_en",20350,],
+["features.login.impl.screens.qrcode.confirmation_QrCodeConfirmationView_Day_2_en","features.login.impl.screens.qrcode.confirmation_QrCodeConfirmationView_Night_2_en",20350,],
+["features.login.impl.screens.qrcode.error_QrCodeErrorView_Day_0_en","features.login.impl.screens.qrcode.error_QrCodeErrorView_Night_0_en",20350,],
+["features.login.impl.screens.qrcode.error_QrCodeErrorView_Day_1_en","features.login.impl.screens.qrcode.error_QrCodeErrorView_Night_1_en",20350,],
+["features.login.impl.screens.qrcode.error_QrCodeErrorView_Day_2_en","features.login.impl.screens.qrcode.error_QrCodeErrorView_Night_2_en",20350,],
+["features.login.impl.screens.qrcode.error_QrCodeErrorView_Day_3_en","features.login.impl.screens.qrcode.error_QrCodeErrorView_Night_3_en",20350,],
+["features.login.impl.screens.qrcode.error_QrCodeErrorView_Day_4_en","features.login.impl.screens.qrcode.error_QrCodeErrorView_Night_4_en",20350,],
+["features.login.impl.screens.qrcode.error_QrCodeErrorView_Day_5_en","features.login.impl.screens.qrcode.error_QrCodeErrorView_Night_5_en",20350,],
+["features.login.impl.screens.qrcode.error_QrCodeErrorView_Day_6_en","features.login.impl.screens.qrcode.error_QrCodeErrorView_Night_6_en",20350,],
+["features.login.impl.screens.qrcode.intro_QrCodeIntroView_Day_0_en","features.login.impl.screens.qrcode.intro_QrCodeIntroView_Night_0_en",20350,],
+["features.login.impl.screens.qrcode.intro_QrCodeIntroView_Day_1_en","features.login.impl.screens.qrcode.intro_QrCodeIntroView_Night_1_en",20350,],
+["features.login.impl.screens.qrcode.scan_QrCodeScanView_Day_0_en","features.login.impl.screens.qrcode.scan_QrCodeScanView_Night_0_en",20350,],
+["features.login.impl.screens.qrcode.scan_QrCodeScanView_Day_1_en","features.login.impl.screens.qrcode.scan_QrCodeScanView_Night_1_en",20350,],
+["features.login.impl.screens.qrcode.scan_QrCodeScanView_Day_2_en","features.login.impl.screens.qrcode.scan_QrCodeScanView_Night_2_en",20350,],
+["features.login.impl.screens.qrcode.scan_QrCodeScanView_Day_3_en","features.login.impl.screens.qrcode.scan_QrCodeScanView_Night_3_en",20350,],
+["features.login.impl.screens.qrcode.scan_QrCodeScanView_Day_4_en","features.login.impl.screens.qrcode.scan_QrCodeScanView_Night_4_en",20350,],
+["features.login.impl.screens.qrcode.scan_QrCodeScanView_Day_5_en","features.login.impl.screens.qrcode.scan_QrCodeScanView_Night_5_en",20350,],
["libraries.designsystem.theme.components_RadioButton_Toggles_en","",0,],
-["features.rageshake.api.detection_RageshakeDialogContent_Day_0_en","features.rageshake.api.detection_RageshakeDialogContent_Night_0_en",20336,],
-["features.rageshake.api.preferences_RageshakePreferencesView_Day_0_en","features.rageshake.api.preferences_RageshakePreferencesView_Night_0_en",20336,],
+["features.rageshake.api.detection_RageshakeDialogContent_Day_0_en","features.rageshake.api.detection_RageshakeDialogContent_Night_0_en",20350,],
+["features.rageshake.api.preferences_RageshakePreferencesView_Day_0_en","features.rageshake.api.preferences_RageshakePreferencesView_Night_0_en",20350,],
["features.rageshake.api.preferences_RageshakePreferencesView_Day_1_en","features.rageshake.api.preferences_RageshakePreferencesView_Night_1_en",0,],
["features.messages.impl.timeline.components.reactionsummary_ReactionSummaryViewContent_Day_0_en","features.messages.impl.timeline.components.reactionsummary_ReactionSummaryViewContent_Night_0_en",0,],
-["features.messages.impl.timeline.components.receipt.bottomsheet_ReadReceiptBottomSheet_Day_0_en","features.messages.impl.timeline.components.receipt.bottomsheet_ReadReceiptBottomSheet_Night_0_en",20336,],
-["features.messages.impl.timeline.components.receipt.bottomsheet_ReadReceiptBottomSheet_Day_1_en","features.messages.impl.timeline.components.receipt.bottomsheet_ReadReceiptBottomSheet_Night_1_en",20336,],
-["features.messages.impl.timeline.components.receipt.bottomsheet_ReadReceiptBottomSheet_Day_2_en","features.messages.impl.timeline.components.receipt.bottomsheet_ReadReceiptBottomSheet_Night_2_en",20336,],
-["features.messages.impl.timeline.components.receipt.bottomsheet_ReadReceiptBottomSheet_Day_3_en","features.messages.impl.timeline.components.receipt.bottomsheet_ReadReceiptBottomSheet_Night_3_en",20336,],
-["features.messages.impl.timeline.components.receipt.bottomsheet_ReadReceiptBottomSheet_Day_4_en","features.messages.impl.timeline.components.receipt.bottomsheet_ReadReceiptBottomSheet_Night_4_en",20336,],
-["features.messages.impl.timeline.components.receipt.bottomsheet_ReadReceiptBottomSheet_Day_5_en","features.messages.impl.timeline.components.receipt.bottomsheet_ReadReceiptBottomSheet_Night_5_en",20336,],
-["features.securebackup.impl.setup.views_RecoveryKeyView_Day_0_en","features.securebackup.impl.setup.views_RecoveryKeyView_Night_0_en",20336,],
-["features.securebackup.impl.setup.views_RecoveryKeyView_Day_10_en","features.securebackup.impl.setup.views_RecoveryKeyView_Night_10_en",20336,],
-["features.securebackup.impl.setup.views_RecoveryKeyView_Day_11_en","features.securebackup.impl.setup.views_RecoveryKeyView_Night_11_en",20336,],
-["features.securebackup.impl.setup.views_RecoveryKeyView_Day_12_en","features.securebackup.impl.setup.views_RecoveryKeyView_Night_12_en",20336,],
-["features.securebackup.impl.setup.views_RecoveryKeyView_Day_13_en","features.securebackup.impl.setup.views_RecoveryKeyView_Night_13_en",20336,],
-["features.securebackup.impl.setup.views_RecoveryKeyView_Day_14_en","features.securebackup.impl.setup.views_RecoveryKeyView_Night_14_en",20336,],
-["features.securebackup.impl.setup.views_RecoveryKeyView_Day_1_en","features.securebackup.impl.setup.views_RecoveryKeyView_Night_1_en",20336,],
-["features.securebackup.impl.setup.views_RecoveryKeyView_Day_2_en","features.securebackup.impl.setup.views_RecoveryKeyView_Night_2_en",20336,],
-["features.securebackup.impl.setup.views_RecoveryKeyView_Day_3_en","features.securebackup.impl.setup.views_RecoveryKeyView_Night_3_en",20336,],
-["features.securebackup.impl.setup.views_RecoveryKeyView_Day_4_en","features.securebackup.impl.setup.views_RecoveryKeyView_Night_4_en",20336,],
-["features.securebackup.impl.setup.views_RecoveryKeyView_Day_5_en","features.securebackup.impl.setup.views_RecoveryKeyView_Night_5_en",20336,],
-["features.securebackup.impl.setup.views_RecoveryKeyView_Day_6_en","features.securebackup.impl.setup.views_RecoveryKeyView_Night_6_en",20336,],
-["features.securebackup.impl.setup.views_RecoveryKeyView_Day_7_en","features.securebackup.impl.setup.views_RecoveryKeyView_Night_7_en",20336,],
-["features.securebackup.impl.setup.views_RecoveryKeyView_Day_8_en","features.securebackup.impl.setup.views_RecoveryKeyView_Night_8_en",20336,],
-["features.securebackup.impl.setup.views_RecoveryKeyView_Day_9_en","features.securebackup.impl.setup.views_RecoveryKeyView_Night_9_en",20336,],
+["features.messages.impl.timeline.components.receipt.bottomsheet_ReadReceiptBottomSheet_Day_0_en","features.messages.impl.timeline.components.receipt.bottomsheet_ReadReceiptBottomSheet_Night_0_en",20350,],
+["features.messages.impl.timeline.components.receipt.bottomsheet_ReadReceiptBottomSheet_Day_1_en","features.messages.impl.timeline.components.receipt.bottomsheet_ReadReceiptBottomSheet_Night_1_en",20350,],
+["features.messages.impl.timeline.components.receipt.bottomsheet_ReadReceiptBottomSheet_Day_2_en","features.messages.impl.timeline.components.receipt.bottomsheet_ReadReceiptBottomSheet_Night_2_en",20350,],
+["features.messages.impl.timeline.components.receipt.bottomsheet_ReadReceiptBottomSheet_Day_3_en","features.messages.impl.timeline.components.receipt.bottomsheet_ReadReceiptBottomSheet_Night_3_en",20350,],
+["features.messages.impl.timeline.components.receipt.bottomsheet_ReadReceiptBottomSheet_Day_4_en","features.messages.impl.timeline.components.receipt.bottomsheet_ReadReceiptBottomSheet_Night_4_en",20350,],
+["features.messages.impl.timeline.components.receipt.bottomsheet_ReadReceiptBottomSheet_Day_5_en","features.messages.impl.timeline.components.receipt.bottomsheet_ReadReceiptBottomSheet_Night_5_en",20350,],
+["features.securebackup.impl.setup.views_RecoveryKeyView_Day_0_en","features.securebackup.impl.setup.views_RecoveryKeyView_Night_0_en",20350,],
+["features.securebackup.impl.setup.views_RecoveryKeyView_Day_10_en","features.securebackup.impl.setup.views_RecoveryKeyView_Night_10_en",20350,],
+["features.securebackup.impl.setup.views_RecoveryKeyView_Day_11_en","features.securebackup.impl.setup.views_RecoveryKeyView_Night_11_en",20350,],
+["features.securebackup.impl.setup.views_RecoveryKeyView_Day_12_en","features.securebackup.impl.setup.views_RecoveryKeyView_Night_12_en",20350,],
+["features.securebackup.impl.setup.views_RecoveryKeyView_Day_13_en","features.securebackup.impl.setup.views_RecoveryKeyView_Night_13_en",20350,],
+["features.securebackup.impl.setup.views_RecoveryKeyView_Day_14_en","features.securebackup.impl.setup.views_RecoveryKeyView_Night_14_en",20350,],
+["features.securebackup.impl.setup.views_RecoveryKeyView_Day_1_en","features.securebackup.impl.setup.views_RecoveryKeyView_Night_1_en",20350,],
+["features.securebackup.impl.setup.views_RecoveryKeyView_Day_2_en","features.securebackup.impl.setup.views_RecoveryKeyView_Night_2_en",20350,],
+["features.securebackup.impl.setup.views_RecoveryKeyView_Day_3_en","features.securebackup.impl.setup.views_RecoveryKeyView_Night_3_en",20350,],
+["features.securebackup.impl.setup.views_RecoveryKeyView_Day_4_en","features.securebackup.impl.setup.views_RecoveryKeyView_Night_4_en",20350,],
+["features.securebackup.impl.setup.views_RecoveryKeyView_Day_5_en","features.securebackup.impl.setup.views_RecoveryKeyView_Night_5_en",20350,],
+["features.securebackup.impl.setup.views_RecoveryKeyView_Day_6_en","features.securebackup.impl.setup.views_RecoveryKeyView_Night_6_en",20350,],
+["features.securebackup.impl.setup.views_RecoveryKeyView_Day_7_en","features.securebackup.impl.setup.views_RecoveryKeyView_Night_7_en",20350,],
+["features.securebackup.impl.setup.views_RecoveryKeyView_Day_8_en","features.securebackup.impl.setup.views_RecoveryKeyView_Night_8_en",20350,],
+["features.securebackup.impl.setup.views_RecoveryKeyView_Day_9_en","features.securebackup.impl.setup.views_RecoveryKeyView_Night_9_en",20350,],
["libraries.designsystem.atomic.atoms_RedIndicatorAtom_Day_0_en","libraries.designsystem.atomic.atoms_RedIndicatorAtom_Night_0_en",0,],
["features.messages.impl.timeline.components_ReplySwipeIndicator_Day_0_en","features.messages.impl.timeline.components_ReplySwipeIndicator_Night_0_en",0,],
-["features.messages.impl.report_ReportMessageView_Day_0_en","features.messages.impl.report_ReportMessageView_Night_0_en",20336,],
-["features.messages.impl.report_ReportMessageView_Day_1_en","features.messages.impl.report_ReportMessageView_Night_1_en",20336,],
-["features.messages.impl.report_ReportMessageView_Day_2_en","features.messages.impl.report_ReportMessageView_Night_2_en",20336,],
-["features.messages.impl.report_ReportMessageView_Day_3_en","features.messages.impl.report_ReportMessageView_Night_3_en",20336,],
-["features.messages.impl.report_ReportMessageView_Day_4_en","features.messages.impl.report_ReportMessageView_Night_4_en",20336,],
-["features.messages.impl.report_ReportMessageView_Day_5_en","features.messages.impl.report_ReportMessageView_Night_5_en",20336,],
-["features.reportroom.impl_ReportRoomView_Day_0_en","features.reportroom.impl_ReportRoomView_Night_0_en",20336,],
-["features.reportroom.impl_ReportRoomView_Day_1_en","features.reportroom.impl_ReportRoomView_Night_1_en",20336,],
-["features.reportroom.impl_ReportRoomView_Day_2_en","features.reportroom.impl_ReportRoomView_Night_2_en",20336,],
-["features.reportroom.impl_ReportRoomView_Day_3_en","features.reportroom.impl_ReportRoomView_Night_3_en",20336,],
-["features.reportroom.impl_ReportRoomView_Day_4_en","features.reportroom.impl_ReportRoomView_Night_4_en",20336,],
-["features.securebackup.impl.reset.password_ResetIdentityPasswordView_Day_0_en","features.securebackup.impl.reset.password_ResetIdentityPasswordView_Night_0_en",20336,],
-["features.securebackup.impl.reset.password_ResetIdentityPasswordView_Day_1_en","features.securebackup.impl.reset.password_ResetIdentityPasswordView_Night_1_en",20336,],
-["features.securebackup.impl.reset.password_ResetIdentityPasswordView_Day_2_en","features.securebackup.impl.reset.password_ResetIdentityPasswordView_Night_2_en",20336,],
-["features.securebackup.impl.reset.password_ResetIdentityPasswordView_Day_3_en","features.securebackup.impl.reset.password_ResetIdentityPasswordView_Night_3_en",20336,],
-["features.securebackup.impl.reset.root_ResetIdentityRootView_Day_0_en","features.securebackup.impl.reset.root_ResetIdentityRootView_Night_0_en",20336,],
-["features.securebackup.impl.reset.root_ResetIdentityRootView_Day_1_en","features.securebackup.impl.reset.root_ResetIdentityRootView_Night_1_en",20336,],
+["features.messages.impl.report_ReportMessageView_Day_0_en","features.messages.impl.report_ReportMessageView_Night_0_en",20350,],
+["features.messages.impl.report_ReportMessageView_Day_1_en","features.messages.impl.report_ReportMessageView_Night_1_en",20350,],
+["features.messages.impl.report_ReportMessageView_Day_2_en","features.messages.impl.report_ReportMessageView_Night_2_en",20350,],
+["features.messages.impl.report_ReportMessageView_Day_3_en","features.messages.impl.report_ReportMessageView_Night_3_en",20350,],
+["features.messages.impl.report_ReportMessageView_Day_4_en","features.messages.impl.report_ReportMessageView_Night_4_en",20350,],
+["features.messages.impl.report_ReportMessageView_Day_5_en","features.messages.impl.report_ReportMessageView_Night_5_en",20350,],
+["features.reportroom.impl_ReportRoomView_Day_0_en","features.reportroom.impl_ReportRoomView_Night_0_en",20350,],
+["features.reportroom.impl_ReportRoomView_Day_1_en","features.reportroom.impl_ReportRoomView_Night_1_en",20350,],
+["features.reportroom.impl_ReportRoomView_Day_2_en","features.reportroom.impl_ReportRoomView_Night_2_en",20350,],
+["features.reportroom.impl_ReportRoomView_Day_3_en","features.reportroom.impl_ReportRoomView_Night_3_en",20350,],
+["features.reportroom.impl_ReportRoomView_Day_4_en","features.reportroom.impl_ReportRoomView_Night_4_en",20350,],
+["features.securebackup.impl.reset.password_ResetIdentityPasswordView_Day_0_en","features.securebackup.impl.reset.password_ResetIdentityPasswordView_Night_0_en",20350,],
+["features.securebackup.impl.reset.password_ResetIdentityPasswordView_Day_1_en","features.securebackup.impl.reset.password_ResetIdentityPasswordView_Night_1_en",20350,],
+["features.securebackup.impl.reset.password_ResetIdentityPasswordView_Day_2_en","features.securebackup.impl.reset.password_ResetIdentityPasswordView_Night_2_en",20350,],
+["features.securebackup.impl.reset.password_ResetIdentityPasswordView_Day_3_en","features.securebackup.impl.reset.password_ResetIdentityPasswordView_Night_3_en",20350,],
+["features.securebackup.impl.reset.root_ResetIdentityRootView_Day_0_en","features.securebackup.impl.reset.root_ResetIdentityRootView_Night_0_en",20350,],
+["features.securebackup.impl.reset.root_ResetIdentityRootView_Day_1_en","features.securebackup.impl.reset.root_ResetIdentityRootView_Night_1_en",20350,],
["features.messages.impl.crypto.sendfailure.resolve_ResolveVerifiedUserSendFailureView_Day_0_en","features.messages.impl.crypto.sendfailure.resolve_ResolveVerifiedUserSendFailureView_Night_0_en",0,],
-["features.messages.impl.crypto.sendfailure.resolve_ResolveVerifiedUserSendFailureView_Day_1_en","features.messages.impl.crypto.sendfailure.resolve_ResolveVerifiedUserSendFailureView_Night_1_en",20336,],
-["features.messages.impl.crypto.sendfailure.resolve_ResolveVerifiedUserSendFailureView_Day_2_en","features.messages.impl.crypto.sendfailure.resolve_ResolveVerifiedUserSendFailureView_Night_2_en",20336,],
-["libraries.designsystem.components.dialogs_RetryDialogContent_Dialogs_en","",20336,],
-["libraries.designsystem.components.dialogs_RetryDialog_Day_0_en","libraries.designsystem.components.dialogs_RetryDialog_Night_0_en",20336,],
-["features.roomdetails.impl.rolesandpermissions_RolesAndPermissionsView_Day_0_en","features.roomdetails.impl.rolesandpermissions_RolesAndPermissionsView_Night_0_en",20336,],
-["features.roomdetails.impl.rolesandpermissions_RolesAndPermissionsView_Day_1_en","features.roomdetails.impl.rolesandpermissions_RolesAndPermissionsView_Night_1_en",20336,],
-["features.roomdetails.impl.rolesandpermissions_RolesAndPermissionsView_Day_2_en","features.roomdetails.impl.rolesandpermissions_RolesAndPermissionsView_Night_2_en",20336,],
-["features.roomdetails.impl.rolesandpermissions_RolesAndPermissionsView_Day_3_en","features.roomdetails.impl.rolesandpermissions_RolesAndPermissionsView_Night_3_en",20336,],
-["features.roomdetails.impl.rolesandpermissions_RolesAndPermissionsView_Day_4_en","features.roomdetails.impl.rolesandpermissions_RolesAndPermissionsView_Night_4_en",20336,],
-["features.roomdetails.impl.rolesandpermissions_RolesAndPermissionsView_Day_5_en","features.roomdetails.impl.rolesandpermissions_RolesAndPermissionsView_Night_5_en",20336,],
-["features.roomdetails.impl.rolesandpermissions_RolesAndPermissionsView_Day_6_en","features.roomdetails.impl.rolesandpermissions_RolesAndPermissionsView_Night_6_en",20336,],
-["features.roomdetails.impl.rolesandpermissions_RolesAndPermissionsView_Day_7_en","features.roomdetails.impl.rolesandpermissions_RolesAndPermissionsView_Night_7_en",20336,],
-["features.roomdetails.impl.rolesandpermissions_RolesAndPermissionsView_Day_8_en","features.roomdetails.impl.rolesandpermissions_RolesAndPermissionsView_Night_8_en",20336,],
+["features.messages.impl.crypto.sendfailure.resolve_ResolveVerifiedUserSendFailureView_Day_1_en","features.messages.impl.crypto.sendfailure.resolve_ResolveVerifiedUserSendFailureView_Night_1_en",20350,],
+["features.messages.impl.crypto.sendfailure.resolve_ResolveVerifiedUserSendFailureView_Day_2_en","features.messages.impl.crypto.sendfailure.resolve_ResolveVerifiedUserSendFailureView_Night_2_en",20350,],
+["libraries.designsystem.components.dialogs_RetryDialogContent_Dialogs_en","",20350,],
+["libraries.designsystem.components.dialogs_RetryDialog_Day_0_en","libraries.designsystem.components.dialogs_RetryDialog_Night_0_en",20350,],
+["features.roomdetails.impl.rolesandpermissions_RolesAndPermissionsView_Day_0_en","features.roomdetails.impl.rolesandpermissions_RolesAndPermissionsView_Night_0_en",20350,],
+["features.roomdetails.impl.rolesandpermissions_RolesAndPermissionsView_Day_1_en","features.roomdetails.impl.rolesandpermissions_RolesAndPermissionsView_Night_1_en",20350,],
+["features.roomdetails.impl.rolesandpermissions_RolesAndPermissionsView_Day_2_en","features.roomdetails.impl.rolesandpermissions_RolesAndPermissionsView_Night_2_en",20350,],
+["features.roomdetails.impl.rolesandpermissions_RolesAndPermissionsView_Day_3_en","features.roomdetails.impl.rolesandpermissions_RolesAndPermissionsView_Night_3_en",20350,],
+["features.roomdetails.impl.rolesandpermissions_RolesAndPermissionsView_Day_4_en","features.roomdetails.impl.rolesandpermissions_RolesAndPermissionsView_Night_4_en",20350,],
+["features.roomdetails.impl.rolesandpermissions_RolesAndPermissionsView_Day_5_en","features.roomdetails.impl.rolesandpermissions_RolesAndPermissionsView_Night_5_en",20350,],
+["features.roomdetails.impl.rolesandpermissions_RolesAndPermissionsView_Day_6_en","features.roomdetails.impl.rolesandpermissions_RolesAndPermissionsView_Night_6_en",20350,],
+["features.roomdetails.impl.rolesandpermissions_RolesAndPermissionsView_Day_7_en","features.roomdetails.impl.rolesandpermissions_RolesAndPermissionsView_Night_7_en",20350,],
+["features.roomdetails.impl.rolesandpermissions_RolesAndPermissionsView_Day_8_en","features.roomdetails.impl.rolesandpermissions_RolesAndPermissionsView_Night_8_en",20350,],
["libraries.matrix.ui.room.address_RoomAddressField_Day_0_en","libraries.matrix.ui.room.address_RoomAddressField_Night_0_en",0,],
["features.roomaliasresolver.impl_RoomAliasResolverView_Day_0_en","features.roomaliasresolver.impl_RoomAliasResolverView_Night_0_en",0,],
-["features.roomaliasresolver.impl_RoomAliasResolverView_Day_1_en","features.roomaliasresolver.impl_RoomAliasResolverView_Night_1_en",20336,],
-["features.roomaliasresolver.impl_RoomAliasResolverView_Day_2_en","features.roomaliasresolver.impl_RoomAliasResolverView_Night_2_en",20336,],
-["features.roomdetails.impl_RoomDetailsDark_0_en","",20336,],
-["features.roomdetails.impl_RoomDetailsDark_10_en","",20336,],
-["features.roomdetails.impl_RoomDetailsDark_11_en","",20336,],
-["features.roomdetails.impl_RoomDetailsDark_12_en","",20336,],
-["features.roomdetails.impl_RoomDetailsDark_13_en","",20336,],
-["features.roomdetails.impl_RoomDetailsDark_14_en","",20336,],
-["features.roomdetails.impl_RoomDetailsDark_15_en","",20336,],
-["features.roomdetails.impl_RoomDetailsDark_16_en","",20336,],
-["features.roomdetails.impl_RoomDetailsDark_17_en","",20336,],
-["features.roomdetails.impl_RoomDetailsDark_18_en","",20336,],
-["features.roomdetails.impl_RoomDetailsDark_19_en","",20336,],
-["features.roomdetails.impl_RoomDetailsDark_1_en","",20336,],
-["features.roomdetails.impl_RoomDetailsDark_2_en","",20336,],
-["features.roomdetails.impl_RoomDetailsDark_3_en","",20336,],
-["features.roomdetails.impl_RoomDetailsDark_4_en","",20336,],
-["features.roomdetails.impl_RoomDetailsDark_5_en","",20336,],
-["features.roomdetails.impl_RoomDetailsDark_6_en","",20336,],
-["features.roomdetails.impl_RoomDetailsDark_7_en","",20336,],
-["features.roomdetails.impl_RoomDetailsDark_8_en","",20336,],
-["features.roomdetails.impl_RoomDetailsDark_9_en","",20336,],
-["features.roomdetails.impl.edit_RoomDetailsEditView_Day_0_en","features.roomdetails.impl.edit_RoomDetailsEditView_Night_0_en",20336,],
-["features.roomdetails.impl.edit_RoomDetailsEditView_Day_1_en","features.roomdetails.impl.edit_RoomDetailsEditView_Night_1_en",20336,],
-["features.roomdetails.impl.edit_RoomDetailsEditView_Day_2_en","features.roomdetails.impl.edit_RoomDetailsEditView_Night_2_en",20336,],
-["features.roomdetails.impl.edit_RoomDetailsEditView_Day_3_en","features.roomdetails.impl.edit_RoomDetailsEditView_Night_3_en",20336,],
-["features.roomdetails.impl.edit_RoomDetailsEditView_Day_4_en","features.roomdetails.impl.edit_RoomDetailsEditView_Night_4_en",20336,],
-["features.roomdetails.impl.edit_RoomDetailsEditView_Day_5_en","features.roomdetails.impl.edit_RoomDetailsEditView_Night_5_en",20336,],
-["features.roomdetails.impl.edit_RoomDetailsEditView_Day_6_en","features.roomdetails.impl.edit_RoomDetailsEditView_Night_6_en",20336,],
-["features.roomdetails.impl.edit_RoomDetailsEditView_Day_7_en","features.roomdetails.impl.edit_RoomDetailsEditView_Night_7_en",20336,],
-["features.roomdetails.impl_RoomDetails_0_en","",20336,],
-["features.roomdetails.impl_RoomDetails_10_en","",20336,],
-["features.roomdetails.impl_RoomDetails_11_en","",20336,],
-["features.roomdetails.impl_RoomDetails_12_en","",20336,],
-["features.roomdetails.impl_RoomDetails_13_en","",20336,],
-["features.roomdetails.impl_RoomDetails_14_en","",20336,],
-["features.roomdetails.impl_RoomDetails_15_en","",20336,],
-["features.roomdetails.impl_RoomDetails_16_en","",20336,],
-["features.roomdetails.impl_RoomDetails_17_en","",20336,],
-["features.roomdetails.impl_RoomDetails_18_en","",20336,],
-["features.roomdetails.impl_RoomDetails_19_en","",20336,],
-["features.roomdetails.impl_RoomDetails_1_en","",20336,],
-["features.roomdetails.impl_RoomDetails_2_en","",20336,],
-["features.roomdetails.impl_RoomDetails_3_en","",20336,],
-["features.roomdetails.impl_RoomDetails_4_en","",20336,],
-["features.roomdetails.impl_RoomDetails_5_en","",20336,],
-["features.roomdetails.impl_RoomDetails_6_en","",20336,],
-["features.roomdetails.impl_RoomDetails_7_en","",20336,],
-["features.roomdetails.impl_RoomDetails_8_en","",20336,],
-["features.roomdetails.impl_RoomDetails_9_en","",20336,],
-["features.roomdirectory.impl.root_RoomDirectoryView_Day_0_en","features.roomdirectory.impl.root_RoomDirectoryView_Night_0_en",20336,],
-["features.roomdirectory.impl.root_RoomDirectoryView_Day_1_en","features.roomdirectory.impl.root_RoomDirectoryView_Night_1_en",20336,],
-["features.roomdirectory.impl.root_RoomDirectoryView_Day_2_en","features.roomdirectory.impl.root_RoomDirectoryView_Night_2_en",20336,],
-["features.roomdetails.impl.invite_RoomInviteMembersView_Day_0_en","features.roomdetails.impl.invite_RoomInviteMembersView_Night_0_en",20336,],
-["features.roomdetails.impl.invite_RoomInviteMembersView_Day_1_en","features.roomdetails.impl.invite_RoomInviteMembersView_Night_1_en",20336,],
-["features.roomdetails.impl.invite_RoomInviteMembersView_Day_2_en","features.roomdetails.impl.invite_RoomInviteMembersView_Night_2_en",20336,],
-["features.home.impl.components_RoomListContentView_Day_0_en","features.home.impl.components_RoomListContentView_Night_0_en",20336,],
-["features.home.impl.components_RoomListContentView_Day_1_en","features.home.impl.components_RoomListContentView_Night_1_en",20336,],
+["features.roomaliasresolver.impl_RoomAliasResolverView_Day_1_en","features.roomaliasresolver.impl_RoomAliasResolverView_Night_1_en",20350,],
+["features.roomaliasresolver.impl_RoomAliasResolverView_Day_2_en","features.roomaliasresolver.impl_RoomAliasResolverView_Night_2_en",20350,],
+["features.roomdetails.impl_RoomDetailsDark_0_en","",20350,],
+["features.roomdetails.impl_RoomDetailsDark_10_en","",20350,],
+["features.roomdetails.impl_RoomDetailsDark_11_en","",20350,],
+["features.roomdetails.impl_RoomDetailsDark_12_en","",20350,],
+["features.roomdetails.impl_RoomDetailsDark_13_en","",20350,],
+["features.roomdetails.impl_RoomDetailsDark_14_en","",20350,],
+["features.roomdetails.impl_RoomDetailsDark_15_en","",20350,],
+["features.roomdetails.impl_RoomDetailsDark_16_en","",20350,],
+["features.roomdetails.impl_RoomDetailsDark_17_en","",20350,],
+["features.roomdetails.impl_RoomDetailsDark_18_en","",20350,],
+["features.roomdetails.impl_RoomDetailsDark_19_en","",20350,],
+["features.roomdetails.impl_RoomDetailsDark_1_en","",20350,],
+["features.roomdetails.impl_RoomDetailsDark_2_en","",20350,],
+["features.roomdetails.impl_RoomDetailsDark_3_en","",20350,],
+["features.roomdetails.impl_RoomDetailsDark_4_en","",20350,],
+["features.roomdetails.impl_RoomDetailsDark_5_en","",20350,],
+["features.roomdetails.impl_RoomDetailsDark_6_en","",20350,],
+["features.roomdetails.impl_RoomDetailsDark_7_en","",20350,],
+["features.roomdetails.impl_RoomDetailsDark_8_en","",20350,],
+["features.roomdetails.impl_RoomDetailsDark_9_en","",20350,],
+["features.roomdetails.impl.edit_RoomDetailsEditView_Day_0_en","features.roomdetails.impl.edit_RoomDetailsEditView_Night_0_en",20350,],
+["features.roomdetails.impl.edit_RoomDetailsEditView_Day_1_en","features.roomdetails.impl.edit_RoomDetailsEditView_Night_1_en",20350,],
+["features.roomdetails.impl.edit_RoomDetailsEditView_Day_2_en","features.roomdetails.impl.edit_RoomDetailsEditView_Night_2_en",20350,],
+["features.roomdetails.impl.edit_RoomDetailsEditView_Day_3_en","features.roomdetails.impl.edit_RoomDetailsEditView_Night_3_en",20350,],
+["features.roomdetails.impl.edit_RoomDetailsEditView_Day_4_en","features.roomdetails.impl.edit_RoomDetailsEditView_Night_4_en",20350,],
+["features.roomdetails.impl.edit_RoomDetailsEditView_Day_5_en","features.roomdetails.impl.edit_RoomDetailsEditView_Night_5_en",20350,],
+["features.roomdetails.impl.edit_RoomDetailsEditView_Day_6_en","features.roomdetails.impl.edit_RoomDetailsEditView_Night_6_en",20350,],
+["features.roomdetails.impl.edit_RoomDetailsEditView_Day_7_en","features.roomdetails.impl.edit_RoomDetailsEditView_Night_7_en",20350,],
+["features.roomdetails.impl_RoomDetails_0_en","",20350,],
+["features.roomdetails.impl_RoomDetails_10_en","",20350,],
+["features.roomdetails.impl_RoomDetails_11_en","",20350,],
+["features.roomdetails.impl_RoomDetails_12_en","",20350,],
+["features.roomdetails.impl_RoomDetails_13_en","",20350,],
+["features.roomdetails.impl_RoomDetails_14_en","",20350,],
+["features.roomdetails.impl_RoomDetails_15_en","",20350,],
+["features.roomdetails.impl_RoomDetails_16_en","",20350,],
+["features.roomdetails.impl_RoomDetails_17_en","",20350,],
+["features.roomdetails.impl_RoomDetails_18_en","",20350,],
+["features.roomdetails.impl_RoomDetails_19_en","",20350,],
+["features.roomdetails.impl_RoomDetails_1_en","",20350,],
+["features.roomdetails.impl_RoomDetails_2_en","",20350,],
+["features.roomdetails.impl_RoomDetails_3_en","",20350,],
+["features.roomdetails.impl_RoomDetails_4_en","",20350,],
+["features.roomdetails.impl_RoomDetails_5_en","",20350,],
+["features.roomdetails.impl_RoomDetails_6_en","",20350,],
+["features.roomdetails.impl_RoomDetails_7_en","",20350,],
+["features.roomdetails.impl_RoomDetails_8_en","",20350,],
+["features.roomdetails.impl_RoomDetails_9_en","",20350,],
+["features.roomdirectory.impl.root_RoomDirectoryView_Day_0_en","features.roomdirectory.impl.root_RoomDirectoryView_Night_0_en",20350,],
+["features.roomdirectory.impl.root_RoomDirectoryView_Day_1_en","features.roomdirectory.impl.root_RoomDirectoryView_Night_1_en",20350,],
+["features.roomdirectory.impl.root_RoomDirectoryView_Day_2_en","features.roomdirectory.impl.root_RoomDirectoryView_Night_2_en",20350,],
+["features.roomdetails.impl.invite_RoomInviteMembersView_Day_0_en","features.roomdetails.impl.invite_RoomInviteMembersView_Night_0_en",20350,],
+["features.roomdetails.impl.invite_RoomInviteMembersView_Day_1_en","features.roomdetails.impl.invite_RoomInviteMembersView_Night_1_en",20350,],
+["features.roomdetails.impl.invite_RoomInviteMembersView_Day_2_en","features.roomdetails.impl.invite_RoomInviteMembersView_Night_2_en",20350,],
+["features.roomdetails.impl.invite_RoomInviteMembersView_Day_3_en","features.roomdetails.impl.invite_RoomInviteMembersView_Night_3_en",20350,],
+["features.home.impl.components_RoomListContentView_Day_0_en","features.home.impl.components_RoomListContentView_Night_0_en",20350,],
+["features.home.impl.components_RoomListContentView_Day_1_en","features.home.impl.components_RoomListContentView_Night_1_en",20350,],
["features.home.impl.components_RoomListContentView_Day_2_en","features.home.impl.components_RoomListContentView_Night_2_en",0,],
-["features.home.impl.components_RoomListContentView_Day_3_en","features.home.impl.components_RoomListContentView_Night_3_en",20336,],
-["features.home.impl.components_RoomListContentView_Day_4_en","features.home.impl.components_RoomListContentView_Night_4_en",20336,],
-["features.home.impl.roomlist_RoomListDeclineInviteMenuContent_Day_0_en","features.home.impl.roomlist_RoomListDeclineInviteMenuContent_Night_0_en",20336,],
-["features.home.impl.filters_RoomListFiltersView_Day_0_en","features.home.impl.filters_RoomListFiltersView_Night_0_en",20336,],
-["features.home.impl.filters_RoomListFiltersView_Day_1_en","features.home.impl.filters_RoomListFiltersView_Night_1_en",20336,],
-["features.home.impl.roomlist_RoomListModalBottomSheetContent_Day_0_en","features.home.impl.roomlist_RoomListModalBottomSheetContent_Night_0_en",20336,],
-["features.home.impl.roomlist_RoomListModalBottomSheetContent_Day_1_en","features.home.impl.roomlist_RoomListModalBottomSheetContent_Night_1_en",20336,],
-["features.home.impl.roomlist_RoomListModalBottomSheetContent_Day_2_en","features.home.impl.roomlist_RoomListModalBottomSheetContent_Night_2_en",20336,],
+["features.home.impl.components_RoomListContentView_Day_3_en","features.home.impl.components_RoomListContentView_Night_3_en",20350,],
+["features.home.impl.components_RoomListContentView_Day_4_en","features.home.impl.components_RoomListContentView_Night_4_en",20350,],
+["features.home.impl.roomlist_RoomListDeclineInviteMenuContent_Day_0_en","features.home.impl.roomlist_RoomListDeclineInviteMenuContent_Night_0_en",20350,],
+["features.home.impl.filters_RoomListFiltersView_Day_0_en","features.home.impl.filters_RoomListFiltersView_Night_0_en",20350,],
+["features.home.impl.filters_RoomListFiltersView_Day_1_en","features.home.impl.filters_RoomListFiltersView_Night_1_en",20350,],
+["features.home.impl.roomlist_RoomListModalBottomSheetContent_Day_0_en","features.home.impl.roomlist_RoomListModalBottomSheetContent_Night_0_en",20350,],
+["features.home.impl.roomlist_RoomListModalBottomSheetContent_Day_1_en","features.home.impl.roomlist_RoomListModalBottomSheetContent_Night_1_en",20350,],
+["features.home.impl.roomlist_RoomListModalBottomSheetContent_Day_2_en","features.home.impl.roomlist_RoomListModalBottomSheetContent_Night_2_en",20350,],
["features.home.impl.search_RoomListSearchContent_Day_0_en","features.home.impl.search_RoomListSearchContent_Night_0_en",0,],
-["features.home.impl.search_RoomListSearchContent_Day_1_en","features.home.impl.search_RoomListSearchContent_Night_1_en",20336,],
-["features.roomdetails.impl.members_RoomMemberListViewBanned_Day_0_en","features.roomdetails.impl.members_RoomMemberListViewBanned_Night_0_en",20336,],
-["features.roomdetails.impl.members_RoomMemberListViewBanned_Day_1_en","features.roomdetails.impl.members_RoomMemberListViewBanned_Night_1_en",20336,],
-["features.roomdetails.impl.members_RoomMemberListViewBanned_Day_2_en","features.roomdetails.impl.members_RoomMemberListViewBanned_Night_2_en",20336,],
-["features.roomdetails.impl.members_RoomMemberListView_Day_0_en","features.roomdetails.impl.members_RoomMemberListView_Night_0_en",20336,],
-["features.roomdetails.impl.members_RoomMemberListView_Day_1_en","features.roomdetails.impl.members_RoomMemberListView_Night_1_en",20336,],
-["features.roomdetails.impl.members_RoomMemberListView_Day_2_en","features.roomdetails.impl.members_RoomMemberListView_Night_2_en",20336,],
-["features.roomdetails.impl.members_RoomMemberListView_Day_3_en","features.roomdetails.impl.members_RoomMemberListView_Night_3_en",20336,],
-["features.roomdetails.impl.members_RoomMemberListView_Day_4_en","features.roomdetails.impl.members_RoomMemberListView_Night_4_en",20336,],
-["features.roomdetails.impl.members_RoomMemberListView_Day_5_en","features.roomdetails.impl.members_RoomMemberListView_Night_5_en",20336,],
+["features.home.impl.search_RoomListSearchContent_Day_1_en","features.home.impl.search_RoomListSearchContent_Night_1_en",20350,],
+["features.roomdetails.impl.members_RoomMemberListViewBanned_Day_0_en","features.roomdetails.impl.members_RoomMemberListViewBanned_Night_0_en",20350,],
+["features.roomdetails.impl.members_RoomMemberListViewBanned_Day_1_en","features.roomdetails.impl.members_RoomMemberListViewBanned_Night_1_en",20350,],
+["features.roomdetails.impl.members_RoomMemberListViewBanned_Day_2_en","features.roomdetails.impl.members_RoomMemberListViewBanned_Night_2_en",20350,],
+["features.roomdetails.impl.members_RoomMemberListView_Day_0_en","features.roomdetails.impl.members_RoomMemberListView_Night_0_en",20350,],
+["features.roomdetails.impl.members_RoomMemberListView_Day_1_en","features.roomdetails.impl.members_RoomMemberListView_Night_1_en",20350,],
+["features.roomdetails.impl.members_RoomMemberListView_Day_2_en","features.roomdetails.impl.members_RoomMemberListView_Night_2_en",20350,],
+["features.roomdetails.impl.members_RoomMemberListView_Day_3_en","features.roomdetails.impl.members_RoomMemberListView_Night_3_en",20350,],
+["features.roomdetails.impl.members_RoomMemberListView_Day_4_en","features.roomdetails.impl.members_RoomMemberListView_Night_4_en",20350,],
+["features.roomdetails.impl.members_RoomMemberListView_Day_5_en","features.roomdetails.impl.members_RoomMemberListView_Night_5_en",20350,],
["features.roomdetails.impl.members_RoomMemberListView_Day_6_en","features.roomdetails.impl.members_RoomMemberListView_Night_6_en",0,],
-["features.roomdetails.impl.members_RoomMemberListView_Day_7_en","features.roomdetails.impl.members_RoomMemberListView_Night_7_en",20336,],
-["features.roomdetails.impl.members_RoomMemberListView_Day_8_en","features.roomdetails.impl.members_RoomMemberListView_Night_8_en",20336,],
-["features.roomdetails.impl.members_RoomMemberListView_Day_9_en","features.roomdetails.impl.members_RoomMemberListView_Night_9_en",20336,],
-["features.roommembermoderation.impl_RoomMemberModerationView_Day_0_en","features.roommembermoderation.impl_RoomMemberModerationView_Night_0_en",20336,],
-["features.roommembermoderation.impl_RoomMemberModerationView_Day_1_en","features.roommembermoderation.impl_RoomMemberModerationView_Night_1_en",20336,],
-["features.roommembermoderation.impl_RoomMemberModerationView_Day_2_en","features.roommembermoderation.impl_RoomMemberModerationView_Night_2_en",20336,],
-["features.roommembermoderation.impl_RoomMemberModerationView_Day_3_en","features.roommembermoderation.impl_RoomMemberModerationView_Night_3_en",20336,],
-["features.roommembermoderation.impl_RoomMemberModerationView_Day_4_en","features.roommembermoderation.impl_RoomMemberModerationView_Night_4_en",20336,],
-["features.roommembermoderation.impl_RoomMemberModerationView_Day_5_en","features.roommembermoderation.impl_RoomMemberModerationView_Night_5_en",20336,],
-["features.roommembermoderation.impl_RoomMemberModerationView_Day_6_en","features.roommembermoderation.impl_RoomMemberModerationView_Night_6_en",20336,],
-["features.roommembermoderation.impl_RoomMemberModerationView_Day_7_en","features.roommembermoderation.impl_RoomMemberModerationView_Night_7_en",20336,],
-["features.roomdetails.impl.notificationsettings_RoomNotificationSettingsOption_Day_0_en","features.roomdetails.impl.notificationsettings_RoomNotificationSettingsOption_Night_0_en",20336,],
-["features.roomdetails.impl.notificationsettings_RoomNotificationSettingsView_Day_0_en","features.roomdetails.impl.notificationsettings_RoomNotificationSettingsView_Night_0_en",20336,],
-["features.roomdetails.impl.notificationsettings_RoomNotificationSettingsView_Day_1_en","features.roomdetails.impl.notificationsettings_RoomNotificationSettingsView_Night_1_en",20336,],
-["features.roomdetails.impl.notificationsettings_RoomNotificationSettingsView_Day_2_en","features.roomdetails.impl.notificationsettings_RoomNotificationSettingsView_Night_2_en",20336,],
-["features.roomdetails.impl.notificationsettings_RoomNotificationSettingsView_Day_3_en","features.roomdetails.impl.notificationsettings_RoomNotificationSettingsView_Night_3_en",20336,],
-["features.roomdetails.impl.notificationsettings_RoomNotificationSettingsView_Day_4_en","features.roomdetails.impl.notificationsettings_RoomNotificationSettingsView_Night_4_en",20336,],
-["features.roomdetails.impl.notificationsettings_RoomNotificationSettingsView_Day_5_en","features.roomdetails.impl.notificationsettings_RoomNotificationSettingsView_Night_5_en",20336,],
-["features.roomdetails.impl.notificationsettings_RoomNotificationSettingsView_Day_6_en","features.roomdetails.impl.notificationsettings_RoomNotificationSettingsView_Night_6_en",20336,],
-["libraries.roomselect.impl_RoomSelectView_Day_0_en","libraries.roomselect.impl_RoomSelectView_Night_0_en",20336,],
-["libraries.roomselect.impl_RoomSelectView_Day_1_en","libraries.roomselect.impl_RoomSelectView_Night_1_en",20336,],
-["libraries.roomselect.impl_RoomSelectView_Day_2_en","libraries.roomselect.impl_RoomSelectView_Night_2_en",20336,],
-["libraries.roomselect.impl_RoomSelectView_Day_3_en","libraries.roomselect.impl_RoomSelectView_Night_3_en",20336,],
-["libraries.roomselect.impl_RoomSelectView_Day_4_en","libraries.roomselect.impl_RoomSelectView_Night_4_en",20336,],
-["libraries.roomselect.impl_RoomSelectView_Day_5_en","libraries.roomselect.impl_RoomSelectView_Night_5_en",20336,],
+["features.roomdetails.impl.members_RoomMemberListView_Day_7_en","features.roomdetails.impl.members_RoomMemberListView_Night_7_en",20350,],
+["features.roomdetails.impl.members_RoomMemberListView_Day_8_en","features.roomdetails.impl.members_RoomMemberListView_Night_8_en",20350,],
+["features.roomdetails.impl.members_RoomMemberListView_Day_9_en","features.roomdetails.impl.members_RoomMemberListView_Night_9_en",20350,],
+["features.roommembermoderation.impl_RoomMemberModerationView_Day_0_en","features.roommembermoderation.impl_RoomMemberModerationView_Night_0_en",20350,],
+["features.roommembermoderation.impl_RoomMemberModerationView_Day_1_en","features.roommembermoderation.impl_RoomMemberModerationView_Night_1_en",20350,],
+["features.roommembermoderation.impl_RoomMemberModerationView_Day_2_en","features.roommembermoderation.impl_RoomMemberModerationView_Night_2_en",20350,],
+["features.roommembermoderation.impl_RoomMemberModerationView_Day_3_en","features.roommembermoderation.impl_RoomMemberModerationView_Night_3_en",20350,],
+["features.roommembermoderation.impl_RoomMemberModerationView_Day_4_en","features.roommembermoderation.impl_RoomMemberModerationView_Night_4_en",20350,],
+["features.roommembermoderation.impl_RoomMemberModerationView_Day_5_en","features.roommembermoderation.impl_RoomMemberModerationView_Night_5_en",20350,],
+["features.roommembermoderation.impl_RoomMemberModerationView_Day_6_en","features.roommembermoderation.impl_RoomMemberModerationView_Night_6_en",20350,],
+["features.roommembermoderation.impl_RoomMemberModerationView_Day_7_en","features.roommembermoderation.impl_RoomMemberModerationView_Night_7_en",20350,],
+["features.roomdetails.impl.notificationsettings_RoomNotificationSettingsOption_Day_0_en","features.roomdetails.impl.notificationsettings_RoomNotificationSettingsOption_Night_0_en",20350,],
+["features.roomdetails.impl.notificationsettings_RoomNotificationSettingsView_Day_0_en","features.roomdetails.impl.notificationsettings_RoomNotificationSettingsView_Night_0_en",20350,],
+["features.roomdetails.impl.notificationsettings_RoomNotificationSettingsView_Day_1_en","features.roomdetails.impl.notificationsettings_RoomNotificationSettingsView_Night_1_en",20350,],
+["features.roomdetails.impl.notificationsettings_RoomNotificationSettingsView_Day_2_en","features.roomdetails.impl.notificationsettings_RoomNotificationSettingsView_Night_2_en",20350,],
+["features.roomdetails.impl.notificationsettings_RoomNotificationSettingsView_Day_3_en","features.roomdetails.impl.notificationsettings_RoomNotificationSettingsView_Night_3_en",20350,],
+["features.roomdetails.impl.notificationsettings_RoomNotificationSettingsView_Day_4_en","features.roomdetails.impl.notificationsettings_RoomNotificationSettingsView_Night_4_en",20350,],
+["features.roomdetails.impl.notificationsettings_RoomNotificationSettingsView_Day_5_en","features.roomdetails.impl.notificationsettings_RoomNotificationSettingsView_Night_5_en",20350,],
+["features.roomdetails.impl.notificationsettings_RoomNotificationSettingsView_Day_6_en","features.roomdetails.impl.notificationsettings_RoomNotificationSettingsView_Night_6_en",20350,],
+["libraries.roomselect.impl_RoomSelectView_Day_0_en","libraries.roomselect.impl_RoomSelectView_Night_0_en",20350,],
+["libraries.roomselect.impl_RoomSelectView_Day_1_en","libraries.roomselect.impl_RoomSelectView_Night_1_en",20350,],
+["libraries.roomselect.impl_RoomSelectView_Day_2_en","libraries.roomselect.impl_RoomSelectView_Night_2_en",20350,],
+["libraries.roomselect.impl_RoomSelectView_Day_3_en","libraries.roomselect.impl_RoomSelectView_Night_3_en",20350,],
+["libraries.roomselect.impl_RoomSelectView_Day_4_en","libraries.roomselect.impl_RoomSelectView_Night_4_en",20350,],
+["libraries.roomselect.impl_RoomSelectView_Day_5_en","libraries.roomselect.impl_RoomSelectView_Night_5_en",20350,],
["features.home.impl.components_RoomSummaryPlaceholderRow_Day_0_en","features.home.impl.components_RoomSummaryPlaceholderRow_Night_0_en",0,],
["features.home.impl.components_RoomSummaryRow_Day_0_en","features.home.impl.components_RoomSummaryRow_Night_0_en",0,],
["features.home.impl.components_RoomSummaryRow_Day_10_en","features.home.impl.components_RoomSummaryRow_Night_10_en",0,],
@@ -1101,13 +1103,13 @@ export const screenshots = [
["features.home.impl.components_RoomSummaryRow_Day_26_en","features.home.impl.components_RoomSummaryRow_Night_26_en",0,],
["features.home.impl.components_RoomSummaryRow_Day_27_en","features.home.impl.components_RoomSummaryRow_Night_27_en",0,],
["features.home.impl.components_RoomSummaryRow_Day_28_en","features.home.impl.components_RoomSummaryRow_Night_28_en",0,],
-["features.home.impl.components_RoomSummaryRow_Day_29_en","features.home.impl.components_RoomSummaryRow_Night_29_en",20336,],
-["features.home.impl.components_RoomSummaryRow_Day_2_en","features.home.impl.components_RoomSummaryRow_Night_2_en",20336,],
-["features.home.impl.components_RoomSummaryRow_Day_30_en","features.home.impl.components_RoomSummaryRow_Night_30_en",20336,],
-["features.home.impl.components_RoomSummaryRow_Day_31_en","features.home.impl.components_RoomSummaryRow_Night_31_en",20336,],
-["features.home.impl.components_RoomSummaryRow_Day_32_en","features.home.impl.components_RoomSummaryRow_Night_32_en",20336,],
-["features.home.impl.components_RoomSummaryRow_Day_33_en","features.home.impl.components_RoomSummaryRow_Night_33_en",20336,],
-["features.home.impl.components_RoomSummaryRow_Day_34_en","features.home.impl.components_RoomSummaryRow_Night_34_en",20336,],
+["features.home.impl.components_RoomSummaryRow_Day_29_en","features.home.impl.components_RoomSummaryRow_Night_29_en",20350,],
+["features.home.impl.components_RoomSummaryRow_Day_2_en","features.home.impl.components_RoomSummaryRow_Night_2_en",20350,],
+["features.home.impl.components_RoomSummaryRow_Day_30_en","features.home.impl.components_RoomSummaryRow_Night_30_en",20350,],
+["features.home.impl.components_RoomSummaryRow_Day_31_en","features.home.impl.components_RoomSummaryRow_Night_31_en",20350,],
+["features.home.impl.components_RoomSummaryRow_Day_32_en","features.home.impl.components_RoomSummaryRow_Night_32_en",20350,],
+["features.home.impl.components_RoomSummaryRow_Day_33_en","features.home.impl.components_RoomSummaryRow_Night_33_en",20350,],
+["features.home.impl.components_RoomSummaryRow_Day_34_en","features.home.impl.components_RoomSummaryRow_Night_34_en",20350,],
["features.home.impl.components_RoomSummaryRow_Day_3_en","features.home.impl.components_RoomSummaryRow_Night_3_en",0,],
["features.home.impl.components_RoomSummaryRow_Day_4_en","features.home.impl.components_RoomSummaryRow_Night_4_en",0,],
["features.home.impl.components_RoomSummaryRow_Day_5_en","features.home.impl.components_RoomSummaryRow_Night_5_en",0,],
@@ -1115,80 +1117,80 @@ export const screenshots = [
["features.home.impl.components_RoomSummaryRow_Day_7_en","features.home.impl.components_RoomSummaryRow_Night_7_en",0,],
["features.home.impl.components_RoomSummaryRow_Day_8_en","features.home.impl.components_RoomSummaryRow_Night_8_en",0,],
["features.home.impl.components_RoomSummaryRow_Day_9_en","features.home.impl.components_RoomSummaryRow_Night_9_en",0,],
-["appnav.root_RootView_Day_0_en","appnav.root_RootView_Night_0_en",20336,],
-["appnav.root_RootView_Day_1_en","appnav.root_RootView_Night_1_en",20336,],
-["appnav.root_RootView_Day_2_en","appnav.root_RootView_Night_2_en",20336,],
+["appnav.root_RootView_Day_0_en","appnav.root_RootView_Night_0_en",20350,],
+["appnav.root_RootView_Day_1_en","appnav.root_RootView_Night_1_en",20350,],
+["appnav.root_RootView_Day_2_en","appnav.root_RootView_Night_2_en",20350,],
["appicon.enterprise_RoundIcon_en","",0,],
["appicon.element_RoundIcon_en","",0,],
["libraries.designsystem.atomic.atoms_RoundedIconAtom_Day_0_en","libraries.designsystem.atomic.atoms_RoundedIconAtom_Night_0_en",0,],
-["features.verifysession.impl.emoji_SasEmojis_Day_0_en","features.verifysession.impl.emoji_SasEmojis_Night_0_en",20336,],
-["features.login.impl.screens.searchaccountprovider_SearchAccountProviderView_Day_0_en","features.login.impl.screens.searchaccountprovider_SearchAccountProviderView_Night_0_en",20336,],
-["features.login.impl.screens.searchaccountprovider_SearchAccountProviderView_Day_1_en","features.login.impl.screens.searchaccountprovider_SearchAccountProviderView_Night_1_en",20336,],
+["features.verifysession.impl.emoji_SasEmojis_Day_0_en","features.verifysession.impl.emoji_SasEmojis_Night_0_en",20350,],
+["features.login.impl.screens.searchaccountprovider_SearchAccountProviderView_Day_0_en","features.login.impl.screens.searchaccountprovider_SearchAccountProviderView_Night_0_en",20350,],
+["features.login.impl.screens.searchaccountprovider_SearchAccountProviderView_Day_1_en","features.login.impl.screens.searchaccountprovider_SearchAccountProviderView_Night_1_en",20350,],
["libraries.designsystem.theme.components_SearchBarActiveNoneQuery_Search_views_en","",0,],
["libraries.designsystem.theme.components_SearchBarActiveWithContent_Search_views_en","",0,],
-["libraries.designsystem.theme.components_SearchBarActiveWithNoResults_Search_views_en","",20336,],
+["libraries.designsystem.theme.components_SearchBarActiveWithNoResults_Search_views_en","",20350,],
["libraries.designsystem.theme.components_SearchBarActiveWithQueryNoBackButton_Search_views_en","",0,],
["libraries.designsystem.theme.components_SearchBarActiveWithQuery_Search_views_en","",0,],
["libraries.designsystem.theme.components_SearchBarInactive_Search_views_en","",0,],
-["features.startchat.impl.components_SearchMultipleUsersResultItem_en","",20336,],
-["features.startchat.impl.components_SearchSingleUserResultItem_en","",20336,],
-["features.securebackup.impl.disable_SecureBackupDisableView_Day_0_en","features.securebackup.impl.disable_SecureBackupDisableView_Night_0_en",20336,],
-["features.securebackup.impl.disable_SecureBackupDisableView_Day_1_en","features.securebackup.impl.disable_SecureBackupDisableView_Night_1_en",20336,],
-["features.securebackup.impl.disable_SecureBackupDisableView_Day_2_en","features.securebackup.impl.disable_SecureBackupDisableView_Night_2_en",20336,],
-["features.securebackup.impl.disable_SecureBackupDisableView_Day_3_en","features.securebackup.impl.disable_SecureBackupDisableView_Night_3_en",20336,],
-["features.securebackup.impl.enter_SecureBackupEnterRecoveryKeyView_Day_0_en","features.securebackup.impl.enter_SecureBackupEnterRecoveryKeyView_Night_0_en",20336,],
-["features.securebackup.impl.enter_SecureBackupEnterRecoveryKeyView_Day_1_en","features.securebackup.impl.enter_SecureBackupEnterRecoveryKeyView_Night_1_en",20336,],
-["features.securebackup.impl.enter_SecureBackupEnterRecoveryKeyView_Day_2_en","features.securebackup.impl.enter_SecureBackupEnterRecoveryKeyView_Night_2_en",20336,],
-["features.securebackup.impl.enter_SecureBackupEnterRecoveryKeyView_Day_3_en","features.securebackup.impl.enter_SecureBackupEnterRecoveryKeyView_Night_3_en",20336,],
-["features.securebackup.impl.enter_SecureBackupEnterRecoveryKeyView_Day_4_en","features.securebackup.impl.enter_SecureBackupEnterRecoveryKeyView_Night_4_en",20336,],
-["features.securebackup.impl.root_SecureBackupRootView_Day_0_en","features.securebackup.impl.root_SecureBackupRootView_Night_0_en",20336,],
-["features.securebackup.impl.root_SecureBackupRootView_Day_10_en","features.securebackup.impl.root_SecureBackupRootView_Night_10_en",20336,],
-["features.securebackup.impl.root_SecureBackupRootView_Day_11_en","features.securebackup.impl.root_SecureBackupRootView_Night_11_en",20336,],
-["features.securebackup.impl.root_SecureBackupRootView_Day_12_en","features.securebackup.impl.root_SecureBackupRootView_Night_12_en",20336,],
-["features.securebackup.impl.root_SecureBackupRootView_Day_13_en","features.securebackup.impl.root_SecureBackupRootView_Night_13_en",20336,],
-["features.securebackup.impl.root_SecureBackupRootView_Day_14_en","features.securebackup.impl.root_SecureBackupRootView_Night_14_en",20336,],
-["features.securebackup.impl.root_SecureBackupRootView_Day_15_en","features.securebackup.impl.root_SecureBackupRootView_Night_15_en",20336,],
-["features.securebackup.impl.root_SecureBackupRootView_Day_16_en","features.securebackup.impl.root_SecureBackupRootView_Night_16_en",20336,],
-["features.securebackup.impl.root_SecureBackupRootView_Day_17_en","features.securebackup.impl.root_SecureBackupRootView_Night_17_en",20336,],
-["features.securebackup.impl.root_SecureBackupRootView_Day_1_en","features.securebackup.impl.root_SecureBackupRootView_Night_1_en",20336,],
-["features.securebackup.impl.root_SecureBackupRootView_Day_2_en","features.securebackup.impl.root_SecureBackupRootView_Night_2_en",20336,],
-["features.securebackup.impl.root_SecureBackupRootView_Day_3_en","features.securebackup.impl.root_SecureBackupRootView_Night_3_en",20336,],
-["features.securebackup.impl.root_SecureBackupRootView_Day_4_en","features.securebackup.impl.root_SecureBackupRootView_Night_4_en",20336,],
-["features.securebackup.impl.root_SecureBackupRootView_Day_5_en","features.securebackup.impl.root_SecureBackupRootView_Night_5_en",20336,],
-["features.securebackup.impl.root_SecureBackupRootView_Day_6_en","features.securebackup.impl.root_SecureBackupRootView_Night_6_en",20336,],
-["features.securebackup.impl.root_SecureBackupRootView_Day_7_en","features.securebackup.impl.root_SecureBackupRootView_Night_7_en",20336,],
-["features.securebackup.impl.root_SecureBackupRootView_Day_8_en","features.securebackup.impl.root_SecureBackupRootView_Night_8_en",20336,],
-["features.securebackup.impl.root_SecureBackupRootView_Day_9_en","features.securebackup.impl.root_SecureBackupRootView_Night_9_en",20336,],
-["features.securebackup.impl.setup_SecureBackupSetupViewChange_Day_0_en","features.securebackup.impl.setup_SecureBackupSetupViewChange_Night_0_en",20336,],
-["features.securebackup.impl.setup_SecureBackupSetupViewChange_Day_1_en","features.securebackup.impl.setup_SecureBackupSetupViewChange_Night_1_en",20336,],
-["features.securebackup.impl.setup_SecureBackupSetupViewChange_Day_2_en","features.securebackup.impl.setup_SecureBackupSetupViewChange_Night_2_en",20336,],
-["features.securebackup.impl.setup_SecureBackupSetupViewChange_Day_3_en","features.securebackup.impl.setup_SecureBackupSetupViewChange_Night_3_en",20336,],
-["features.securebackup.impl.setup_SecureBackupSetupViewChange_Day_4_en","features.securebackup.impl.setup_SecureBackupSetupViewChange_Night_4_en",20336,],
-["features.securebackup.impl.setup_SecureBackupSetupViewChange_Day_5_en","features.securebackup.impl.setup_SecureBackupSetupViewChange_Night_5_en",20336,],
-["features.securebackup.impl.setup_SecureBackupSetupView_Day_0_en","features.securebackup.impl.setup_SecureBackupSetupView_Night_0_en",20336,],
-["features.securebackup.impl.setup_SecureBackupSetupView_Day_1_en","features.securebackup.impl.setup_SecureBackupSetupView_Night_1_en",20336,],
-["features.securebackup.impl.setup_SecureBackupSetupView_Day_2_en","features.securebackup.impl.setup_SecureBackupSetupView_Night_2_en",20336,],
-["features.securebackup.impl.setup_SecureBackupSetupView_Day_3_en","features.securebackup.impl.setup_SecureBackupSetupView_Night_3_en",20336,],
-["features.securebackup.impl.setup_SecureBackupSetupView_Day_4_en","features.securebackup.impl.setup_SecureBackupSetupView_Night_4_en",20336,],
-["features.securebackup.impl.setup_SecureBackupSetupView_Day_5_en","features.securebackup.impl.setup_SecureBackupSetupView_Night_5_en",20336,],
-["features.roomdetails.impl.securityandprivacy_SecurityAndPrivacyViewDark_0_en","",20336,],
-["features.roomdetails.impl.securityandprivacy_SecurityAndPrivacyViewDark_1_en","",20336,],
-["features.roomdetails.impl.securityandprivacy_SecurityAndPrivacyViewDark_2_en","",20336,],
-["features.roomdetails.impl.securityandprivacy_SecurityAndPrivacyViewDark_3_en","",20336,],
-["features.roomdetails.impl.securityandprivacy_SecurityAndPrivacyViewDark_4_en","",20336,],
-["features.roomdetails.impl.securityandprivacy_SecurityAndPrivacyViewDark_5_en","",20336,],
-["features.roomdetails.impl.securityandprivacy_SecurityAndPrivacyViewDark_6_en","",20336,],
-["features.roomdetails.impl.securityandprivacy_SecurityAndPrivacyViewDark_7_en","",20336,],
-["features.roomdetails.impl.securityandprivacy_SecurityAndPrivacyViewDark_8_en","",20336,],
-["features.roomdetails.impl.securityandprivacy_SecurityAndPrivacyViewLight_0_en","",20336,],
-["features.roomdetails.impl.securityandprivacy_SecurityAndPrivacyViewLight_1_en","",20336,],
-["features.roomdetails.impl.securityandprivacy_SecurityAndPrivacyViewLight_2_en","",20336,],
-["features.roomdetails.impl.securityandprivacy_SecurityAndPrivacyViewLight_3_en","",20336,],
-["features.roomdetails.impl.securityandprivacy_SecurityAndPrivacyViewLight_4_en","",20336,],
-["features.roomdetails.impl.securityandprivacy_SecurityAndPrivacyViewLight_5_en","",20336,],
-["features.roomdetails.impl.securityandprivacy_SecurityAndPrivacyViewLight_6_en","",20336,],
-["features.roomdetails.impl.securityandprivacy_SecurityAndPrivacyViewLight_7_en","",20336,],
-["features.roomdetails.impl.securityandprivacy_SecurityAndPrivacyViewLight_8_en","",20336,],
+["features.startchat.impl.components_SearchMultipleUsersResultItem_en","",20350,],
+["features.startchat.impl.components_SearchSingleUserResultItem_en","",20350,],
+["features.securebackup.impl.disable_SecureBackupDisableView_Day_0_en","features.securebackup.impl.disable_SecureBackupDisableView_Night_0_en",20350,],
+["features.securebackup.impl.disable_SecureBackupDisableView_Day_1_en","features.securebackup.impl.disable_SecureBackupDisableView_Night_1_en",20350,],
+["features.securebackup.impl.disable_SecureBackupDisableView_Day_2_en","features.securebackup.impl.disable_SecureBackupDisableView_Night_2_en",20350,],
+["features.securebackup.impl.disable_SecureBackupDisableView_Day_3_en","features.securebackup.impl.disable_SecureBackupDisableView_Night_3_en",20350,],
+["features.securebackup.impl.enter_SecureBackupEnterRecoveryKeyView_Day_0_en","features.securebackup.impl.enter_SecureBackupEnterRecoveryKeyView_Night_0_en",20350,],
+["features.securebackup.impl.enter_SecureBackupEnterRecoveryKeyView_Day_1_en","features.securebackup.impl.enter_SecureBackupEnterRecoveryKeyView_Night_1_en",20350,],
+["features.securebackup.impl.enter_SecureBackupEnterRecoveryKeyView_Day_2_en","features.securebackup.impl.enter_SecureBackupEnterRecoveryKeyView_Night_2_en",20350,],
+["features.securebackup.impl.enter_SecureBackupEnterRecoveryKeyView_Day_3_en","features.securebackup.impl.enter_SecureBackupEnterRecoveryKeyView_Night_3_en",20350,],
+["features.securebackup.impl.enter_SecureBackupEnterRecoveryKeyView_Day_4_en","features.securebackup.impl.enter_SecureBackupEnterRecoveryKeyView_Night_4_en",20350,],
+["features.securebackup.impl.root_SecureBackupRootView_Day_0_en","features.securebackup.impl.root_SecureBackupRootView_Night_0_en",20350,],
+["features.securebackup.impl.root_SecureBackupRootView_Day_10_en","features.securebackup.impl.root_SecureBackupRootView_Night_10_en",20350,],
+["features.securebackup.impl.root_SecureBackupRootView_Day_11_en","features.securebackup.impl.root_SecureBackupRootView_Night_11_en",20350,],
+["features.securebackup.impl.root_SecureBackupRootView_Day_12_en","features.securebackup.impl.root_SecureBackupRootView_Night_12_en",20350,],
+["features.securebackup.impl.root_SecureBackupRootView_Day_13_en","features.securebackup.impl.root_SecureBackupRootView_Night_13_en",20350,],
+["features.securebackup.impl.root_SecureBackupRootView_Day_14_en","features.securebackup.impl.root_SecureBackupRootView_Night_14_en",20350,],
+["features.securebackup.impl.root_SecureBackupRootView_Day_15_en","features.securebackup.impl.root_SecureBackupRootView_Night_15_en",20350,],
+["features.securebackup.impl.root_SecureBackupRootView_Day_16_en","features.securebackup.impl.root_SecureBackupRootView_Night_16_en",20350,],
+["features.securebackup.impl.root_SecureBackupRootView_Day_17_en","features.securebackup.impl.root_SecureBackupRootView_Night_17_en",20350,],
+["features.securebackup.impl.root_SecureBackupRootView_Day_1_en","features.securebackup.impl.root_SecureBackupRootView_Night_1_en",20350,],
+["features.securebackup.impl.root_SecureBackupRootView_Day_2_en","features.securebackup.impl.root_SecureBackupRootView_Night_2_en",20350,],
+["features.securebackup.impl.root_SecureBackupRootView_Day_3_en","features.securebackup.impl.root_SecureBackupRootView_Night_3_en",20350,],
+["features.securebackup.impl.root_SecureBackupRootView_Day_4_en","features.securebackup.impl.root_SecureBackupRootView_Night_4_en",20350,],
+["features.securebackup.impl.root_SecureBackupRootView_Day_5_en","features.securebackup.impl.root_SecureBackupRootView_Night_5_en",20350,],
+["features.securebackup.impl.root_SecureBackupRootView_Day_6_en","features.securebackup.impl.root_SecureBackupRootView_Night_6_en",20350,],
+["features.securebackup.impl.root_SecureBackupRootView_Day_7_en","features.securebackup.impl.root_SecureBackupRootView_Night_7_en",20350,],
+["features.securebackup.impl.root_SecureBackupRootView_Day_8_en","features.securebackup.impl.root_SecureBackupRootView_Night_8_en",20350,],
+["features.securebackup.impl.root_SecureBackupRootView_Day_9_en","features.securebackup.impl.root_SecureBackupRootView_Night_9_en",20350,],
+["features.securebackup.impl.setup_SecureBackupSetupViewChange_Day_0_en","features.securebackup.impl.setup_SecureBackupSetupViewChange_Night_0_en",20350,],
+["features.securebackup.impl.setup_SecureBackupSetupViewChange_Day_1_en","features.securebackup.impl.setup_SecureBackupSetupViewChange_Night_1_en",20350,],
+["features.securebackup.impl.setup_SecureBackupSetupViewChange_Day_2_en","features.securebackup.impl.setup_SecureBackupSetupViewChange_Night_2_en",20350,],
+["features.securebackup.impl.setup_SecureBackupSetupViewChange_Day_3_en","features.securebackup.impl.setup_SecureBackupSetupViewChange_Night_3_en",20350,],
+["features.securebackup.impl.setup_SecureBackupSetupViewChange_Day_4_en","features.securebackup.impl.setup_SecureBackupSetupViewChange_Night_4_en",20350,],
+["features.securebackup.impl.setup_SecureBackupSetupViewChange_Day_5_en","features.securebackup.impl.setup_SecureBackupSetupViewChange_Night_5_en",20350,],
+["features.securebackup.impl.setup_SecureBackupSetupView_Day_0_en","features.securebackup.impl.setup_SecureBackupSetupView_Night_0_en",20350,],
+["features.securebackup.impl.setup_SecureBackupSetupView_Day_1_en","features.securebackup.impl.setup_SecureBackupSetupView_Night_1_en",20350,],
+["features.securebackup.impl.setup_SecureBackupSetupView_Day_2_en","features.securebackup.impl.setup_SecureBackupSetupView_Night_2_en",20350,],
+["features.securebackup.impl.setup_SecureBackupSetupView_Day_3_en","features.securebackup.impl.setup_SecureBackupSetupView_Night_3_en",20350,],
+["features.securebackup.impl.setup_SecureBackupSetupView_Day_4_en","features.securebackup.impl.setup_SecureBackupSetupView_Night_4_en",20350,],
+["features.securebackup.impl.setup_SecureBackupSetupView_Day_5_en","features.securebackup.impl.setup_SecureBackupSetupView_Night_5_en",20350,],
+["features.roomdetails.impl.securityandprivacy_SecurityAndPrivacyViewDark_0_en","",20350,],
+["features.roomdetails.impl.securityandprivacy_SecurityAndPrivacyViewDark_1_en","",20350,],
+["features.roomdetails.impl.securityandprivacy_SecurityAndPrivacyViewDark_2_en","",20350,],
+["features.roomdetails.impl.securityandprivacy_SecurityAndPrivacyViewDark_3_en","",20350,],
+["features.roomdetails.impl.securityandprivacy_SecurityAndPrivacyViewDark_4_en","",20350,],
+["features.roomdetails.impl.securityandprivacy_SecurityAndPrivacyViewDark_5_en","",20350,],
+["features.roomdetails.impl.securityandprivacy_SecurityAndPrivacyViewDark_6_en","",20350,],
+["features.roomdetails.impl.securityandprivacy_SecurityAndPrivacyViewDark_7_en","",20350,],
+["features.roomdetails.impl.securityandprivacy_SecurityAndPrivacyViewDark_8_en","",20350,],
+["features.roomdetails.impl.securityandprivacy_SecurityAndPrivacyViewLight_0_en","",20350,],
+["features.roomdetails.impl.securityandprivacy_SecurityAndPrivacyViewLight_1_en","",20350,],
+["features.roomdetails.impl.securityandprivacy_SecurityAndPrivacyViewLight_2_en","",20350,],
+["features.roomdetails.impl.securityandprivacy_SecurityAndPrivacyViewLight_3_en","",20350,],
+["features.roomdetails.impl.securityandprivacy_SecurityAndPrivacyViewLight_4_en","",20350,],
+["features.roomdetails.impl.securityandprivacy_SecurityAndPrivacyViewLight_5_en","",20350,],
+["features.roomdetails.impl.securityandprivacy_SecurityAndPrivacyViewLight_6_en","",20350,],
+["features.roomdetails.impl.securityandprivacy_SecurityAndPrivacyViewLight_7_en","",20350,],
+["features.roomdetails.impl.securityandprivacy_SecurityAndPrivacyViewLight_8_en","",20350,],
["libraries.designsystem.atomic.atoms_SelectedIndicatorAtom_Day_0_en","libraries.designsystem.atomic.atoms_SelectedIndicatorAtom_Night_0_en",0,],
["libraries.matrix.ui.components_SelectedRoomRtl_Day_0_en","libraries.matrix.ui.components_SelectedRoomRtl_Night_0_en",0,],
["libraries.matrix.ui.components_SelectedRoomRtl_Day_1_en","libraries.matrix.ui.components_SelectedRoomRtl_Night_1_en",0,],
@@ -1202,11 +1204,11 @@ export const screenshots = [
["libraries.matrix.ui.components_SelectedUser_Day_1_en","libraries.matrix.ui.components_SelectedUser_Night_1_en",0,],
["libraries.matrix.ui.components_SelectedUsersRowList_Day_0_en","libraries.matrix.ui.components_SelectedUsersRowList_Night_0_en",0,],
["libraries.textcomposer.components_SendButton_Day_0_en","libraries.textcomposer.components_SendButton_Night_0_en",0,],
-["features.location.impl.send_SendLocationView_Day_0_en","features.location.impl.send_SendLocationView_Night_0_en",20336,],
-["features.location.impl.send_SendLocationView_Day_1_en","features.location.impl.send_SendLocationView_Night_1_en",20336,],
-["features.location.impl.send_SendLocationView_Day_2_en","features.location.impl.send_SendLocationView_Night_2_en",20336,],
-["features.location.impl.send_SendLocationView_Day_3_en","features.location.impl.send_SendLocationView_Night_3_en",20336,],
-["features.location.impl.send_SendLocationView_Day_4_en","features.location.impl.send_SendLocationView_Night_4_en",20336,],
+["features.location.impl.send_SendLocationView_Day_0_en","features.location.impl.send_SendLocationView_Night_0_en",20350,],
+["features.location.impl.send_SendLocationView_Day_1_en","features.location.impl.send_SendLocationView_Night_1_en",20350,],
+["features.location.impl.send_SendLocationView_Day_2_en","features.location.impl.send_SendLocationView_Night_2_en",20350,],
+["features.location.impl.send_SendLocationView_Day_3_en","features.location.impl.send_SendLocationView_Night_3_en",20350,],
+["features.location.impl.send_SendLocationView_Day_4_en","features.location.impl.send_SendLocationView_Night_4_en",20350,],
["libraries.matrix.ui.messages.sender_SenderName_Day_0_en","libraries.matrix.ui.messages.sender_SenderName_Night_0_en",0,],
["libraries.matrix.ui.messages.sender_SenderName_Day_1_en","libraries.matrix.ui.messages.sender_SenderName_Night_1_en",0,],
["libraries.matrix.ui.messages.sender_SenderName_Day_2_en","libraries.matrix.ui.messages.sender_SenderName_Night_2_en",0,],
@@ -1216,27 +1218,27 @@ export const screenshots = [
["libraries.matrix.ui.messages.sender_SenderName_Day_6_en","libraries.matrix.ui.messages.sender_SenderName_Night_6_en",0,],
["libraries.matrix.ui.messages.sender_SenderName_Day_7_en","libraries.matrix.ui.messages.sender_SenderName_Night_7_en",0,],
["libraries.matrix.ui.messages.sender_SenderName_Day_8_en","libraries.matrix.ui.messages.sender_SenderName_Night_8_en",0,],
-["features.verifysession.impl.incoming.ui_SessionDetailsView_Day_0_en","features.verifysession.impl.incoming.ui_SessionDetailsView_Night_0_en",20336,],
-["features.home.impl.components_SetUpRecoveryKeyBanner_Day_0_en","features.home.impl.components_SetUpRecoveryKeyBanner_Night_0_en",20336,],
-["features.lockscreen.impl.setup.biometric_SetupBiometricView_Day_0_en","features.lockscreen.impl.setup.biometric_SetupBiometricView_Night_0_en",20336,],
-["features.lockscreen.impl.setup.pin_SetupPinView_Day_0_en","features.lockscreen.impl.setup.pin_SetupPinView_Night_0_en",20336,],
-["features.lockscreen.impl.setup.pin_SetupPinView_Day_1_en","features.lockscreen.impl.setup.pin_SetupPinView_Night_1_en",20336,],
-["features.lockscreen.impl.setup.pin_SetupPinView_Day_2_en","features.lockscreen.impl.setup.pin_SetupPinView_Night_2_en",20336,],
-["features.lockscreen.impl.setup.pin_SetupPinView_Day_3_en","features.lockscreen.impl.setup.pin_SetupPinView_Night_3_en",20336,],
-["features.lockscreen.impl.setup.pin_SetupPinView_Day_4_en","features.lockscreen.impl.setup.pin_SetupPinView_Night_4_en",20336,],
+["features.verifysession.impl.incoming.ui_SessionDetailsView_Day_0_en","features.verifysession.impl.incoming.ui_SessionDetailsView_Night_0_en",20350,],
+["features.home.impl.components_SetUpRecoveryKeyBanner_Day_0_en","features.home.impl.components_SetUpRecoveryKeyBanner_Night_0_en",20350,],
+["features.lockscreen.impl.setup.biometric_SetupBiometricView_Day_0_en","features.lockscreen.impl.setup.biometric_SetupBiometricView_Night_0_en",20350,],
+["features.lockscreen.impl.setup.pin_SetupPinView_Day_0_en","features.lockscreen.impl.setup.pin_SetupPinView_Night_0_en",20350,],
+["features.lockscreen.impl.setup.pin_SetupPinView_Day_1_en","features.lockscreen.impl.setup.pin_SetupPinView_Night_1_en",20350,],
+["features.lockscreen.impl.setup.pin_SetupPinView_Day_2_en","features.lockscreen.impl.setup.pin_SetupPinView_Night_2_en",20350,],
+["features.lockscreen.impl.setup.pin_SetupPinView_Day_3_en","features.lockscreen.impl.setup.pin_SetupPinView_Night_3_en",20350,],
+["features.lockscreen.impl.setup.pin_SetupPinView_Day_4_en","features.lockscreen.impl.setup.pin_SetupPinView_Night_4_en",20350,],
["features.share.impl_ShareView_Day_0_en","features.share.impl_ShareView_Night_0_en",0,],
["features.share.impl_ShareView_Day_1_en","features.share.impl_ShareView_Night_1_en",0,],
["features.share.impl_ShareView_Day_2_en","features.share.impl_ShareView_Night_2_en",0,],
-["features.share.impl_ShareView_Day_3_en","features.share.impl_ShareView_Night_3_en",20336,],
-["features.location.impl.show_ShowLocationView_Day_0_en","features.location.impl.show_ShowLocationView_Night_0_en",20336,],
-["features.location.impl.show_ShowLocationView_Day_1_en","features.location.impl.show_ShowLocationView_Night_1_en",20336,],
-["features.location.impl.show_ShowLocationView_Day_2_en","features.location.impl.show_ShowLocationView_Night_2_en",20336,],
-["features.location.impl.show_ShowLocationView_Day_3_en","features.location.impl.show_ShowLocationView_Night_3_en",20336,],
-["features.location.impl.show_ShowLocationView_Day_4_en","features.location.impl.show_ShowLocationView_Night_4_en",20336,],
-["features.location.impl.show_ShowLocationView_Day_5_en","features.location.impl.show_ShowLocationView_Night_5_en",20336,],
-["features.location.impl.show_ShowLocationView_Day_6_en","features.location.impl.show_ShowLocationView_Night_6_en",20336,],
-["features.location.impl.show_ShowLocationView_Day_7_en","features.location.impl.show_ShowLocationView_Night_7_en",20336,],
-["features.signedout.impl_SignedOutView_Day_0_en","features.signedout.impl_SignedOutView_Night_0_en",20336,],
+["features.share.impl_ShareView_Day_3_en","features.share.impl_ShareView_Night_3_en",20350,],
+["features.location.impl.show_ShowLocationView_Day_0_en","features.location.impl.show_ShowLocationView_Night_0_en",20350,],
+["features.location.impl.show_ShowLocationView_Day_1_en","features.location.impl.show_ShowLocationView_Night_1_en",20350,],
+["features.location.impl.show_ShowLocationView_Day_2_en","features.location.impl.show_ShowLocationView_Night_2_en",20350,],
+["features.location.impl.show_ShowLocationView_Day_3_en","features.location.impl.show_ShowLocationView_Night_3_en",20350,],
+["features.location.impl.show_ShowLocationView_Day_4_en","features.location.impl.show_ShowLocationView_Night_4_en",20350,],
+["features.location.impl.show_ShowLocationView_Day_5_en","features.location.impl.show_ShowLocationView_Night_5_en",20350,],
+["features.location.impl.show_ShowLocationView_Day_6_en","features.location.impl.show_ShowLocationView_Night_6_en",20350,],
+["features.location.impl.show_ShowLocationView_Day_7_en","features.location.impl.show_ShowLocationView_Night_7_en",20350,],
+["features.signedout.impl_SignedOutView_Day_0_en","features.signedout.impl_SignedOutView_Night_0_en",20350,],
["libraries.designsystem.components.dialogs_SingleSelectionDialogContent_Dialogs_en","",0,],
["libraries.designsystem.components.dialogs_SingleSelectionDialog_Day_0_en","libraries.designsystem.components.dialogs_SingleSelectionDialog_Night_0_en",0,],
["libraries.designsystem.components.list_SingleSelectionListItemCustomFormattert_Single_selection_List_item_-_custom_formatter_List_items_en","",0,],
@@ -1245,82 +1247,86 @@ export const screenshots = [
["libraries.designsystem.components.list_SingleSelectionListItemUnselectedWithSupportingText_Single_selection_List_item_-_no_selection,_supporting_text_List_items_en","",0,],
["libraries.designsystem.components.list_SingleSelectionListItem_Single_selection_List_item_-_no_selection_List_items_en","",0,],
["libraries.designsystem.theme.components_Sliders_Sliders_en","",0,],
-["features.login.impl.dialogs_SlidingSyncNotSupportedDialog_Day_0_en","features.login.impl.dialogs_SlidingSyncNotSupportedDialog_Night_0_en",20336,],
+["features.login.impl.dialogs_SlidingSyncNotSupportedDialog_Day_0_en","features.login.impl.dialogs_SlidingSyncNotSupportedDialog_Night_0_en",20350,],
["libraries.designsystem.theme.components_SnackbarWithActionAndCloseButton_Snackbar_with_action_and_close_button_Snackbars_en","",0,],
["libraries.designsystem.theme.components_SnackbarWithActionOnNewLineAndCloseButton_Snackbar_with_action_and_close_button_on_new_line_Snackbars_en","",0,],
["libraries.designsystem.theme.components_SnackbarWithActionOnNewLine_Snackbar_with_action_on_new_line_Snackbars_en","",0,],
["libraries.designsystem.theme.components_SnackbarWithAction_Snackbar_with_action_Snackbars_en","",0,],
["libraries.designsystem.theme.components_Snackbar_Snackbar_Snackbars_en","",0,],
["libraries.designsystem.components.avatar.internal_SpaceAvatar_Avatars_en","",0,],
-["libraries.matrix.ui.components_SpaceHeaderRootView_Day_0_en","libraries.matrix.ui.components_SpaceHeaderRootView_Night_0_en",20339,],
-["libraries.matrix.ui.components_SpaceHeaderView_Day_0_en","libraries.matrix.ui.components_SpaceHeaderView_Night_0_en",20336,],
-["libraries.matrix.ui.components_SpaceInfoRow_Day_0_en","libraries.matrix.ui.components_SpaceInfoRow_Night_0_en",20336,],
+["libraries.matrix.ui.components_SpaceHeaderRootView_Day_0_en","libraries.matrix.ui.components_SpaceHeaderRootView_Night_0_en",20350,],
+["libraries.matrix.ui.components_SpaceHeaderView_Day_0_en","libraries.matrix.ui.components_SpaceHeaderView_Night_0_en",20350,],
+["libraries.matrix.ui.components_SpaceInfoRow_Day_0_en","libraries.matrix.ui.components_SpaceInfoRow_Night_0_en",20350,],
["libraries.matrix.ui.components_SpaceMembersViewNoHeroes_Day_0_en","libraries.matrix.ui.components_SpaceMembersViewNoHeroes_Night_0_en",0,],
["libraries.matrix.ui.components_SpaceMembersView_Day_0_en","libraries.matrix.ui.components_SpaceMembersView_Night_0_en",0,],
+["features.space.impl_SpaceView_Day_0_en","features.space.impl_SpaceView_Night_0_en",0,],
+["features.space.impl_SpaceView_Day_1_en","features.space.impl_SpaceView_Night_1_en",0,],
+["features.space.impl_SpaceView_Day_2_en","features.space.impl_SpaceView_Night_2_en",20350,],
+["features.space.impl_SpaceView_Day_3_en","features.space.impl_SpaceView_Night_3_en",20350,],
["libraries.designsystem.modifiers_SquareSizeModifierInsideSquare_en","",0,],
["libraries.designsystem.modifiers_SquareSizeModifierLargeHeight_en","",0,],
["libraries.designsystem.modifiers_SquareSizeModifierLargeWidth_en","",0,],
-["features.startchat.impl.root_StartChatView_Day_0_en","features.startchat.impl.root_StartChatView_Night_0_en",20336,],
-["features.startchat.impl.root_StartChatView_Day_1_en","features.startchat.impl.root_StartChatView_Night_1_en",20336,],
-["features.startchat.impl.root_StartChatView_Day_2_en","features.startchat.impl.root_StartChatView_Night_2_en",20336,],
-["features.startchat.impl.root_StartChatView_Day_3_en","features.startchat.impl.root_StartChatView_Night_3_en",20336,],
-["features.startchat.impl.root_StartChatView_Day_4_en","features.startchat.impl.root_StartChatView_Night_4_en",20336,],
-["features.startchat.impl.root_StartChatView_Day_5_en","features.startchat.impl.root_StartChatView_Night_5_en",20336,],
-["features.location.api.internal_StaticMapPlaceholder_Day_0_en","features.location.api.internal_StaticMapPlaceholder_Night_0_en",20336,],
+["features.startchat.impl.root_StartChatView_Day_0_en","features.startchat.impl.root_StartChatView_Night_0_en",20350,],
+["features.startchat.impl.root_StartChatView_Day_1_en","features.startchat.impl.root_StartChatView_Night_1_en",20350,],
+["features.startchat.impl.root_StartChatView_Day_2_en","features.startchat.impl.root_StartChatView_Night_2_en",20350,],
+["features.startchat.impl.root_StartChatView_Day_3_en","features.startchat.impl.root_StartChatView_Night_3_en",20350,],
+["features.startchat.impl.root_StartChatView_Day_4_en","features.startchat.impl.root_StartChatView_Night_4_en",20350,],
+["features.startchat.impl.root_StartChatView_Day_5_en","features.startchat.impl.root_StartChatView_Night_5_en",20350,],
+["features.location.api.internal_StaticMapPlaceholder_Day_0_en","features.location.api.internal_StaticMapPlaceholder_Night_0_en",20350,],
["features.location.api_StaticMapView_Day_0_en","features.location.api_StaticMapView_Night_0_en",0,],
-["features.messages.impl.messagecomposer.suggestions_SuggestionsPickerView_Day_0_en","features.messages.impl.messagecomposer.suggestions_SuggestionsPickerView_Night_0_en",20336,],
+["features.messages.impl.messagecomposer.suggestions_SuggestionsPickerView_Day_0_en","features.messages.impl.messagecomposer.suggestions_SuggestionsPickerView_Night_0_en",20350,],
["libraries.designsystem.atomic.pages_SunsetPage_Day_0_en","libraries.designsystem.atomic.pages_SunsetPage_Night_0_en",0,],
["libraries.designsystem.components.button_SuperButton_Day_0_en","libraries.designsystem.components.button_SuperButton_Night_0_en",0,],
["libraries.designsystem.theme.components_Surface_en","",0,],
["libraries.designsystem.theme.components_Switch_Toggles_en","",0,],
-["appnav.loggedin_SyncStateView_Day_0_en","appnav.loggedin_SyncStateView_Night_0_en",20336,],
+["appnav.loggedin_SyncStateView_Day_0_en","appnav.loggedin_SyncStateView_Night_0_en",20350,],
["libraries.designsystem.components.avatar.internal_TextAvatar_Avatars_en","",0,],
["libraries.designsystem.theme.components_TextButtonLargeLowPadding_Buttons_en","",0,],
["libraries.designsystem.theme.components_TextButtonLarge_Buttons_en","",0,],
["libraries.designsystem.theme.components_TextButtonMediumLowPadding_Buttons_en","",0,],
["libraries.designsystem.theme.components_TextButtonMedium_Buttons_en","",0,],
["libraries.designsystem.theme.components_TextButtonSmall_Buttons_en","",0,],
-["libraries.textcomposer_TextComposerAddCaption_Day_0_en","libraries.textcomposer_TextComposerAddCaption_Night_0_en",20336,],
-["libraries.textcomposer_TextComposerCaption_Day_0_en","libraries.textcomposer_TextComposerCaption_Night_0_en",20336,],
-["libraries.textcomposer_TextComposerEditCaption_Day_0_en","libraries.textcomposer_TextComposerEditCaption_Night_0_en",20336,],
-["libraries.textcomposer_TextComposerEditNotEncrypted_Day_0_en","libraries.textcomposer_TextComposerEditNotEncrypted_Night_0_en",20336,],
-["libraries.textcomposer_TextComposerEdit_Day_0_en","libraries.textcomposer_TextComposerEdit_Night_0_en",20336,],
-["libraries.textcomposer_TextComposerFormattingNotEncrypted_Day_0_en","libraries.textcomposer_TextComposerFormattingNotEncrypted_Night_0_en",20336,],
-["libraries.textcomposer_TextComposerFormatting_Day_0_en","libraries.textcomposer_TextComposerFormatting_Night_0_en",20336,],
-["libraries.textcomposer_TextComposerLinkDialogCreateLinkWithoutText_Day_0_en","libraries.textcomposer_TextComposerLinkDialogCreateLinkWithoutText_Night_0_en",20336,],
-["libraries.textcomposer_TextComposerLinkDialogCreateLink_Day_0_en","libraries.textcomposer_TextComposerLinkDialogCreateLink_Night_0_en",20336,],
-["libraries.textcomposer_TextComposerLinkDialogEditLink_Day_0_en","libraries.textcomposer_TextComposerLinkDialogEditLink_Night_0_en",20336,],
-["libraries.textcomposer_TextComposerReplyNotEncrypted_Day_0_en","libraries.textcomposer_TextComposerReplyNotEncrypted_Night_0_en",20336,],
-["libraries.textcomposer_TextComposerReplyNotEncrypted_Day_10_en","libraries.textcomposer_TextComposerReplyNotEncrypted_Night_10_en",20336,],
-["libraries.textcomposer_TextComposerReplyNotEncrypted_Day_11_en","libraries.textcomposer_TextComposerReplyNotEncrypted_Night_11_en",20336,],
-["libraries.textcomposer_TextComposerReplyNotEncrypted_Day_1_en","libraries.textcomposer_TextComposerReplyNotEncrypted_Night_1_en",20336,],
-["libraries.textcomposer_TextComposerReplyNotEncrypted_Day_2_en","libraries.textcomposer_TextComposerReplyNotEncrypted_Night_2_en",20336,],
-["libraries.textcomposer_TextComposerReplyNotEncrypted_Day_3_en","libraries.textcomposer_TextComposerReplyNotEncrypted_Night_3_en",20336,],
-["libraries.textcomposer_TextComposerReplyNotEncrypted_Day_4_en","libraries.textcomposer_TextComposerReplyNotEncrypted_Night_4_en",20336,],
-["libraries.textcomposer_TextComposerReplyNotEncrypted_Day_5_en","libraries.textcomposer_TextComposerReplyNotEncrypted_Night_5_en",20336,],
-["libraries.textcomposer_TextComposerReplyNotEncrypted_Day_6_en","libraries.textcomposer_TextComposerReplyNotEncrypted_Night_6_en",20336,],
-["libraries.textcomposer_TextComposerReplyNotEncrypted_Day_7_en","libraries.textcomposer_TextComposerReplyNotEncrypted_Night_7_en",20336,],
-["libraries.textcomposer_TextComposerReplyNotEncrypted_Day_8_en","libraries.textcomposer_TextComposerReplyNotEncrypted_Night_8_en",20336,],
-["libraries.textcomposer_TextComposerReplyNotEncrypted_Day_9_en","libraries.textcomposer_TextComposerReplyNotEncrypted_Night_9_en",20336,],
-["libraries.textcomposer_TextComposerReply_Day_0_en","libraries.textcomposer_TextComposerReply_Night_0_en",20336,],
-["libraries.textcomposer_TextComposerReply_Day_10_en","libraries.textcomposer_TextComposerReply_Night_10_en",20336,],
-["libraries.textcomposer_TextComposerReply_Day_11_en","libraries.textcomposer_TextComposerReply_Night_11_en",20336,],
-["libraries.textcomposer_TextComposerReply_Day_1_en","libraries.textcomposer_TextComposerReply_Night_1_en",20336,],
-["libraries.textcomposer_TextComposerReply_Day_2_en","libraries.textcomposer_TextComposerReply_Night_2_en",20336,],
-["libraries.textcomposer_TextComposerReply_Day_3_en","libraries.textcomposer_TextComposerReply_Night_3_en",20336,],
-["libraries.textcomposer_TextComposerReply_Day_4_en","libraries.textcomposer_TextComposerReply_Night_4_en",20336,],
-["libraries.textcomposer_TextComposerReply_Day_5_en","libraries.textcomposer_TextComposerReply_Night_5_en",20336,],
-["libraries.textcomposer_TextComposerReply_Day_6_en","libraries.textcomposer_TextComposerReply_Night_6_en",20336,],
-["libraries.textcomposer_TextComposerReply_Day_7_en","libraries.textcomposer_TextComposerReply_Night_7_en",20336,],
-["libraries.textcomposer_TextComposerReply_Day_8_en","libraries.textcomposer_TextComposerReply_Night_8_en",20336,],
-["libraries.textcomposer_TextComposerReply_Day_9_en","libraries.textcomposer_TextComposerReply_Night_9_en",20336,],
-["libraries.textcomposer_TextComposerSimpleNotEncrypted_Day_0_en","libraries.textcomposer_TextComposerSimpleNotEncrypted_Night_0_en",20336,],
-["libraries.textcomposer_TextComposerSimple_Day_0_en","libraries.textcomposer_TextComposerSimple_Night_0_en",20336,],
-["libraries.textcomposer_TextComposerVoiceNotEncrypted_Day_0_en","libraries.textcomposer_TextComposerVoiceNotEncrypted_Night_0_en",20336,],
+["libraries.textcomposer_TextComposerAddCaption_Day_0_en","libraries.textcomposer_TextComposerAddCaption_Night_0_en",20350,],
+["libraries.textcomposer_TextComposerCaption_Day_0_en","libraries.textcomposer_TextComposerCaption_Night_0_en",20350,],
+["libraries.textcomposer_TextComposerEditCaption_Day_0_en","libraries.textcomposer_TextComposerEditCaption_Night_0_en",20350,],
+["libraries.textcomposer_TextComposerEditNotEncrypted_Day_0_en","libraries.textcomposer_TextComposerEditNotEncrypted_Night_0_en",20350,],
+["libraries.textcomposer_TextComposerEdit_Day_0_en","libraries.textcomposer_TextComposerEdit_Night_0_en",20350,],
+["libraries.textcomposer_TextComposerFormattingNotEncrypted_Day_0_en","libraries.textcomposer_TextComposerFormattingNotEncrypted_Night_0_en",20350,],
+["libraries.textcomposer_TextComposerFormatting_Day_0_en","libraries.textcomposer_TextComposerFormatting_Night_0_en",20350,],
+["libraries.textcomposer_TextComposerLinkDialogCreateLinkWithoutText_Day_0_en","libraries.textcomposer_TextComposerLinkDialogCreateLinkWithoutText_Night_0_en",20350,],
+["libraries.textcomposer_TextComposerLinkDialogCreateLink_Day_0_en","libraries.textcomposer_TextComposerLinkDialogCreateLink_Night_0_en",20350,],
+["libraries.textcomposer_TextComposerLinkDialogEditLink_Day_0_en","libraries.textcomposer_TextComposerLinkDialogEditLink_Night_0_en",20350,],
+["libraries.textcomposer_TextComposerReplyNotEncrypted_Day_0_en","libraries.textcomposer_TextComposerReplyNotEncrypted_Night_0_en",20350,],
+["libraries.textcomposer_TextComposerReplyNotEncrypted_Day_10_en","libraries.textcomposer_TextComposerReplyNotEncrypted_Night_10_en",20350,],
+["libraries.textcomposer_TextComposerReplyNotEncrypted_Day_11_en","libraries.textcomposer_TextComposerReplyNotEncrypted_Night_11_en",20350,],
+["libraries.textcomposer_TextComposerReplyNotEncrypted_Day_1_en","libraries.textcomposer_TextComposerReplyNotEncrypted_Night_1_en",20350,],
+["libraries.textcomposer_TextComposerReplyNotEncrypted_Day_2_en","libraries.textcomposer_TextComposerReplyNotEncrypted_Night_2_en",20350,],
+["libraries.textcomposer_TextComposerReplyNotEncrypted_Day_3_en","libraries.textcomposer_TextComposerReplyNotEncrypted_Night_3_en",20350,],
+["libraries.textcomposer_TextComposerReplyNotEncrypted_Day_4_en","libraries.textcomposer_TextComposerReplyNotEncrypted_Night_4_en",20350,],
+["libraries.textcomposer_TextComposerReplyNotEncrypted_Day_5_en","libraries.textcomposer_TextComposerReplyNotEncrypted_Night_5_en",20350,],
+["libraries.textcomposer_TextComposerReplyNotEncrypted_Day_6_en","libraries.textcomposer_TextComposerReplyNotEncrypted_Night_6_en",20350,],
+["libraries.textcomposer_TextComposerReplyNotEncrypted_Day_7_en","libraries.textcomposer_TextComposerReplyNotEncrypted_Night_7_en",20350,],
+["libraries.textcomposer_TextComposerReplyNotEncrypted_Day_8_en","libraries.textcomposer_TextComposerReplyNotEncrypted_Night_8_en",20350,],
+["libraries.textcomposer_TextComposerReplyNotEncrypted_Day_9_en","libraries.textcomposer_TextComposerReplyNotEncrypted_Night_9_en",20350,],
+["libraries.textcomposer_TextComposerReply_Day_0_en","libraries.textcomposer_TextComposerReply_Night_0_en",20350,],
+["libraries.textcomposer_TextComposerReply_Day_10_en","libraries.textcomposer_TextComposerReply_Night_10_en",20350,],
+["libraries.textcomposer_TextComposerReply_Day_11_en","libraries.textcomposer_TextComposerReply_Night_11_en",20350,],
+["libraries.textcomposer_TextComposerReply_Day_1_en","libraries.textcomposer_TextComposerReply_Night_1_en",20350,],
+["libraries.textcomposer_TextComposerReply_Day_2_en","libraries.textcomposer_TextComposerReply_Night_2_en",20350,],
+["libraries.textcomposer_TextComposerReply_Day_3_en","libraries.textcomposer_TextComposerReply_Night_3_en",20350,],
+["libraries.textcomposer_TextComposerReply_Day_4_en","libraries.textcomposer_TextComposerReply_Night_4_en",20350,],
+["libraries.textcomposer_TextComposerReply_Day_5_en","libraries.textcomposer_TextComposerReply_Night_5_en",20350,],
+["libraries.textcomposer_TextComposerReply_Day_6_en","libraries.textcomposer_TextComposerReply_Night_6_en",20350,],
+["libraries.textcomposer_TextComposerReply_Day_7_en","libraries.textcomposer_TextComposerReply_Night_7_en",20350,],
+["libraries.textcomposer_TextComposerReply_Day_8_en","libraries.textcomposer_TextComposerReply_Night_8_en",20350,],
+["libraries.textcomposer_TextComposerReply_Day_9_en","libraries.textcomposer_TextComposerReply_Night_9_en",20350,],
+["libraries.textcomposer_TextComposerSimpleNotEncrypted_Day_0_en","libraries.textcomposer_TextComposerSimpleNotEncrypted_Night_0_en",20350,],
+["libraries.textcomposer_TextComposerSimple_Day_0_en","libraries.textcomposer_TextComposerSimple_Night_0_en",20350,],
+["libraries.textcomposer_TextComposerVoiceNotEncrypted_Day_0_en","libraries.textcomposer_TextComposerVoiceNotEncrypted_Night_0_en",20350,],
["libraries.textcomposer_TextComposerVoice_Day_0_en","libraries.textcomposer_TextComposerVoice_Night_0_en",0,],
["libraries.designsystem.theme.components_TextDark_Text_en","",0,],
-["libraries.designsystem.components.dialogs_TextFieldDialogWithError_Day_0_en","libraries.designsystem.components.dialogs_TextFieldDialogWithError_Night_0_en",20336,],
-["libraries.designsystem.components.dialogs_TextFieldDialog_Day_0_en","libraries.designsystem.components.dialogs_TextFieldDialog_Night_0_en",20336,],
+["libraries.designsystem.components.dialogs_TextFieldDialogWithError_Day_0_en","libraries.designsystem.components.dialogs_TextFieldDialogWithError_Night_0_en",20350,],
+["libraries.designsystem.components.dialogs_TextFieldDialog_Day_0_en","libraries.designsystem.components.dialogs_TextFieldDialog_Night_0_en",20350,],
["libraries.designsystem.components.list_TextFieldListItemEmpty_Text_field_List_item_-_empty_List_items_en","",0,],
["libraries.designsystem.components.list_TextFieldListItemTextFieldValue_Text_field_List_item_-_textfieldvalue_List_items_en","",0,],
["libraries.designsystem.components.list_TextFieldListItem_Text_field_List_item_-_text_List_items_en","",0,],
@@ -1332,14 +1338,14 @@ export const screenshots = [
["libraries.mediaviewer.impl.local.txt_TextFileContentView_Day_3_en","libraries.mediaviewer.impl.local.txt_TextFileContentView_Night_3_en",0,],
["libraries.textcomposer.components_TextFormatting_Day_0_en","libraries.textcomposer.components_TextFormatting_Night_0_en",0,],
["libraries.designsystem.theme.components_TextLight_Text_en","",0,],
-["libraries.designsystem.theme.components.previews_TimePickerHorizontal_DateTime_pickers_en","",20336,],
-["libraries.designsystem.theme.components.previews_TimePickerVerticalDark_DateTime_pickers_en","",20336,],
-["libraries.designsystem.theme.components.previews_TimePickerVerticalLight_DateTime_pickers_en","",20336,],
+["libraries.designsystem.theme.components.previews_TimePickerHorizontal_DateTime_pickers_en","",20350,],
+["libraries.designsystem.theme.components.previews_TimePickerVerticalDark_DateTime_pickers_en","",20350,],
+["libraries.designsystem.theme.components.previews_TimePickerVerticalLight_DateTime_pickers_en","",20350,],
["features.messages.impl.timeline.components_TimelineEventTimestampView_Day_0_en","features.messages.impl.timeline.components_TimelineEventTimestampView_Night_0_en",0,],
["features.messages.impl.timeline.components_TimelineEventTimestampView_Day_1_en","features.messages.impl.timeline.components_TimelineEventTimestampView_Night_1_en",0,],
["features.messages.impl.timeline.components_TimelineEventTimestampView_Day_2_en","features.messages.impl.timeline.components_TimelineEventTimestampView_Night_2_en",0,],
-["features.messages.impl.timeline.components_TimelineEventTimestampView_Day_3_en","features.messages.impl.timeline.components_TimelineEventTimestampView_Night_3_en",20336,],
-["features.messages.impl.timeline.components_TimelineEventTimestampView_Day_4_en","features.messages.impl.timeline.components_TimelineEventTimestampView_Night_4_en",20336,],
+["features.messages.impl.timeline.components_TimelineEventTimestampView_Day_3_en","features.messages.impl.timeline.components_TimelineEventTimestampView_Night_3_en",20350,],
+["features.messages.impl.timeline.components_TimelineEventTimestampView_Day_4_en","features.messages.impl.timeline.components_TimelineEventTimestampView_Night_4_en",20350,],
["features.messages.impl.timeline.components_TimelineEventTimestampView_Day_5_en","features.messages.impl.timeline.components_TimelineEventTimestampView_Night_5_en",0,],
["features.messages.impl.timeline.components_TimelineEventTimestampView_Day_6_en","features.messages.impl.timeline.components_TimelineEventTimestampView_Night_6_en",0,],
["features.messages.impl.timeline.components_TimelineEventTimestampView_Day_7_en","features.messages.impl.timeline.components_TimelineEventTimestampView_Night_7_en",0,],
@@ -1349,18 +1355,18 @@ export const screenshots = [
["features.messages.impl.timeline.components.event_TimelineItemAudioView_Day_2_en","features.messages.impl.timeline.components.event_TimelineItemAudioView_Night_2_en",0,],
["features.messages.impl.timeline.components.event_TimelineItemAudioView_Day_3_en","features.messages.impl.timeline.components.event_TimelineItemAudioView_Night_3_en",0,],
["features.messages.impl.timeline.components.event_TimelineItemAudioView_Day_4_en","features.messages.impl.timeline.components.event_TimelineItemAudioView_Night_4_en",0,],
-["features.messages.impl.timeline.components_TimelineItemCallNotifyView_Day_0_en","features.messages.impl.timeline.components_TimelineItemCallNotifyView_Night_0_en",20336,],
+["features.messages.impl.timeline.components_TimelineItemCallNotifyView_Day_0_en","features.messages.impl.timeline.components_TimelineItemCallNotifyView_Night_0_en",20350,],
["features.messages.impl.timeline.components.virtual_TimelineItemDaySeparatorView_Day_0_en","features.messages.impl.timeline.components.virtual_TimelineItemDaySeparatorView_Night_0_en",0,],
["features.messages.impl.timeline.components.virtual_TimelineItemDaySeparatorView_Day_1_en","features.messages.impl.timeline.components.virtual_TimelineItemDaySeparatorView_Night_1_en",0,],
-["features.messages.impl.timeline.components.event_TimelineItemEncryptedView_Day_0_en","features.messages.impl.timeline.components.event_TimelineItemEncryptedView_Night_0_en",20336,],
-["features.messages.impl.timeline.components.event_TimelineItemEncryptedView_Day_1_en","features.messages.impl.timeline.components.event_TimelineItemEncryptedView_Night_1_en",20336,],
-["features.messages.impl.timeline.components.event_TimelineItemEncryptedView_Day_2_en","features.messages.impl.timeline.components.event_TimelineItemEncryptedView_Night_2_en",20336,],
-["features.messages.impl.timeline.components.event_TimelineItemEncryptedView_Day_3_en","features.messages.impl.timeline.components.event_TimelineItemEncryptedView_Night_3_en",20336,],
-["features.messages.impl.timeline.components.event_TimelineItemEncryptedView_Day_4_en","features.messages.impl.timeline.components.event_TimelineItemEncryptedView_Night_4_en",20336,],
-["features.messages.impl.timeline.components.event_TimelineItemEncryptedView_Day_5_en","features.messages.impl.timeline.components.event_TimelineItemEncryptedView_Night_5_en",20336,],
-["features.messages.impl.timeline.components.event_TimelineItemEncryptedView_Day_6_en","features.messages.impl.timeline.components.event_TimelineItemEncryptedView_Night_6_en",20336,],
-["features.messages.impl.timeline.components.event_TimelineItemEncryptedView_Day_7_en","features.messages.impl.timeline.components.event_TimelineItemEncryptedView_Night_7_en",20336,],
-["features.messages.impl.timeline.components.event_TimelineItemEncryptedView_Day_8_en","features.messages.impl.timeline.components.event_TimelineItemEncryptedView_Night_8_en",20336,],
+["features.messages.impl.timeline.components.event_TimelineItemEncryptedView_Day_0_en","features.messages.impl.timeline.components.event_TimelineItemEncryptedView_Night_0_en",20350,],
+["features.messages.impl.timeline.components.event_TimelineItemEncryptedView_Day_1_en","features.messages.impl.timeline.components.event_TimelineItemEncryptedView_Night_1_en",20350,],
+["features.messages.impl.timeline.components.event_TimelineItemEncryptedView_Day_2_en","features.messages.impl.timeline.components.event_TimelineItemEncryptedView_Night_2_en",20350,],
+["features.messages.impl.timeline.components.event_TimelineItemEncryptedView_Day_3_en","features.messages.impl.timeline.components.event_TimelineItemEncryptedView_Night_3_en",20350,],
+["features.messages.impl.timeline.components.event_TimelineItemEncryptedView_Day_4_en","features.messages.impl.timeline.components.event_TimelineItemEncryptedView_Night_4_en",20350,],
+["features.messages.impl.timeline.components.event_TimelineItemEncryptedView_Day_5_en","features.messages.impl.timeline.components.event_TimelineItemEncryptedView_Night_5_en",20350,],
+["features.messages.impl.timeline.components.event_TimelineItemEncryptedView_Day_6_en","features.messages.impl.timeline.components.event_TimelineItemEncryptedView_Night_6_en",20350,],
+["features.messages.impl.timeline.components.event_TimelineItemEncryptedView_Day_7_en","features.messages.impl.timeline.components.event_TimelineItemEncryptedView_Night_7_en",20350,],
+["features.messages.impl.timeline.components.event_TimelineItemEncryptedView_Day_8_en","features.messages.impl.timeline.components.event_TimelineItemEncryptedView_Night_8_en",20350,],
["features.messages.impl.timeline.components_TimelineItemEventRowDisambiguated_Day_0_en","features.messages.impl.timeline.components_TimelineItemEventRowDisambiguated_Night_0_en",0,],
["features.messages.impl.timeline.components_TimelineItemEventRowForDirectRoom_Day_0_en","features.messages.impl.timeline.components_TimelineItemEventRowForDirectRoom_Night_0_en",0,],
["features.messages.impl.timeline.components_TimelineItemEventRowLongSenderName_en","",0,],
@@ -1368,18 +1374,18 @@ export const screenshots = [
["features.messages.impl.timeline.components_TimelineItemEventRowTimestamp_Day_0_en","features.messages.impl.timeline.components_TimelineItemEventRowTimestamp_Night_0_en",0,],
["features.messages.impl.timeline.components_TimelineItemEventRowTimestamp_Day_1_en","features.messages.impl.timeline.components_TimelineItemEventRowTimestamp_Night_1_en",0,],
["features.messages.impl.timeline.components_TimelineItemEventRowTimestamp_Day_2_en","features.messages.impl.timeline.components_TimelineItemEventRowTimestamp_Night_2_en",0,],
-["features.messages.impl.timeline.components_TimelineItemEventRowTimestamp_Day_3_en","features.messages.impl.timeline.components_TimelineItemEventRowTimestamp_Night_3_en",20336,],
-["features.messages.impl.timeline.components_TimelineItemEventRowTimestamp_Day_4_en","features.messages.impl.timeline.components_TimelineItemEventRowTimestamp_Night_4_en",20336,],
+["features.messages.impl.timeline.components_TimelineItemEventRowTimestamp_Day_3_en","features.messages.impl.timeline.components_TimelineItemEventRowTimestamp_Night_3_en",20350,],
+["features.messages.impl.timeline.components_TimelineItemEventRowTimestamp_Day_4_en","features.messages.impl.timeline.components_TimelineItemEventRowTimestamp_Night_4_en",20350,],
["features.messages.impl.timeline.components_TimelineItemEventRowTimestamp_Day_5_en","features.messages.impl.timeline.components_TimelineItemEventRowTimestamp_Night_5_en",0,],
["features.messages.impl.timeline.components_TimelineItemEventRowTimestamp_Day_6_en","features.messages.impl.timeline.components_TimelineItemEventRowTimestamp_Night_6_en",0,],
-["features.messages.impl.timeline.components_TimelineItemEventRowTimestamp_Day_7_en","features.messages.impl.timeline.components_TimelineItemEventRowTimestamp_Night_7_en",20336,],
-["features.messages.impl.timeline.components_TimelineItemEventRowUtd_Day_0_en","features.messages.impl.timeline.components_TimelineItemEventRowUtd_Night_0_en",20336,],
-["features.messages.impl.timeline.components_TimelineItemEventRowWithManyReactions_Day_0_en","features.messages.impl.timeline.components_TimelineItemEventRowWithManyReactions_Night_0_en",20336,],
+["features.messages.impl.timeline.components_TimelineItemEventRowTimestamp_Day_7_en","features.messages.impl.timeline.components_TimelineItemEventRowTimestamp_Night_7_en",20350,],
+["features.messages.impl.timeline.components_TimelineItemEventRowUtd_Day_0_en","features.messages.impl.timeline.components_TimelineItemEventRowUtd_Night_0_en",20350,],
+["features.messages.impl.timeline.components_TimelineItemEventRowWithManyReactions_Day_0_en","features.messages.impl.timeline.components_TimelineItemEventRowWithManyReactions_Night_0_en",20350,],
["features.messages.impl.timeline.components_TimelineItemEventRowWithRR_Day_0_en","features.messages.impl.timeline.components_TimelineItemEventRowWithRR_Night_0_en",0,],
["features.messages.impl.timeline.components_TimelineItemEventRowWithRR_Day_1_en","features.messages.impl.timeline.components_TimelineItemEventRowWithRR_Night_1_en",0,],
["features.messages.impl.timeline.components_TimelineItemEventRowWithRR_Day_2_en","features.messages.impl.timeline.components_TimelineItemEventRowWithRR_Night_2_en",0,],
-["features.messages.impl.timeline.components_TimelineItemEventRowWithReplyInformative_Day_0_en","features.messages.impl.timeline.components_TimelineItemEventRowWithReplyInformative_Night_0_en",20336,],
-["features.messages.impl.timeline.components_TimelineItemEventRowWithReplyInformative_Day_1_en","features.messages.impl.timeline.components_TimelineItemEventRowWithReplyInformative_Night_1_en",20336,],
+["features.messages.impl.timeline.components_TimelineItemEventRowWithReplyInformative_Day_0_en","features.messages.impl.timeline.components_TimelineItemEventRowWithReplyInformative_Night_0_en",20350,],
+["features.messages.impl.timeline.components_TimelineItemEventRowWithReplyInformative_Day_1_en","features.messages.impl.timeline.components_TimelineItemEventRowWithReplyInformative_Night_1_en",20350,],
["features.messages.impl.timeline.components_TimelineItemEventRowWithReplyOther_Day_0_en","features.messages.impl.timeline.components_TimelineItemEventRowWithReplyOther_Night_0_en",0,],
["features.messages.impl.timeline.components_TimelineItemEventRowWithReplyOther_Day_1_en","features.messages.impl.timeline.components_TimelineItemEventRowWithReplyOther_Night_1_en",0,],
["features.messages.impl.timeline.components_TimelineItemEventRowWithReply_Day_0_en","features.messages.impl.timeline.components_TimelineItemEventRowWithReply_Night_0_en",0,],
@@ -1388,41 +1394,41 @@ export const screenshots = [
["features.messages.impl.timeline.components_TimelineItemEventRowWithReply_Day_1_en","features.messages.impl.timeline.components_TimelineItemEventRowWithReply_Night_1_en",0,],
["features.messages.impl.timeline.components_TimelineItemEventRowWithReply_Day_2_en","features.messages.impl.timeline.components_TimelineItemEventRowWithReply_Night_2_en",0,],
["features.messages.impl.timeline.components_TimelineItemEventRowWithReply_Day_3_en","features.messages.impl.timeline.components_TimelineItemEventRowWithReply_Night_3_en",0,],
-["features.messages.impl.timeline.components_TimelineItemEventRowWithReply_Day_4_en","features.messages.impl.timeline.components_TimelineItemEventRowWithReply_Night_4_en",20336,],
+["features.messages.impl.timeline.components_TimelineItemEventRowWithReply_Day_4_en","features.messages.impl.timeline.components_TimelineItemEventRowWithReply_Night_4_en",20350,],
["features.messages.impl.timeline.components_TimelineItemEventRowWithReply_Day_5_en","features.messages.impl.timeline.components_TimelineItemEventRowWithReply_Night_5_en",0,],
["features.messages.impl.timeline.components_TimelineItemEventRowWithReply_Day_6_en","features.messages.impl.timeline.components_TimelineItemEventRowWithReply_Night_6_en",0,],
["features.messages.impl.timeline.components_TimelineItemEventRowWithReply_Day_7_en","features.messages.impl.timeline.components_TimelineItemEventRowWithReply_Night_7_en",0,],
-["features.messages.impl.timeline.components_TimelineItemEventRowWithReply_Day_8_en","features.messages.impl.timeline.components_TimelineItemEventRowWithReply_Night_8_en",20336,],
+["features.messages.impl.timeline.components_TimelineItemEventRowWithReply_Day_8_en","features.messages.impl.timeline.components_TimelineItemEventRowWithReply_Night_8_en",20350,],
["features.messages.impl.timeline.components_TimelineItemEventRowWithReply_Day_9_en","features.messages.impl.timeline.components_TimelineItemEventRowWithReply_Night_9_en",0,],
-["features.messages.impl.timeline.components_TimelineItemEventRowWithThreadSummary_Day_0_en","features.messages.impl.timeline.components_TimelineItemEventRowWithThreadSummary_Night_0_en",20336,],
+["features.messages.impl.timeline.components_TimelineItemEventRowWithThreadSummary_Day_0_en","features.messages.impl.timeline.components_TimelineItemEventRowWithThreadSummary_Night_0_en",20350,],
["features.messages.impl.timeline.components_TimelineItemEventRow_Day_0_en","features.messages.impl.timeline.components_TimelineItemEventRow_Night_0_en",0,],
-["features.messages.impl.timeline.components_TimelineItemEventTimestampBelow_en","",20336,],
+["features.messages.impl.timeline.components_TimelineItemEventTimestampBelow_en","",20350,],
["features.messages.impl.timeline.components.event_TimelineItemFileView_Day_0_en","features.messages.impl.timeline.components.event_TimelineItemFileView_Night_0_en",0,],
["features.messages.impl.timeline.components.event_TimelineItemFileView_Day_1_en","features.messages.impl.timeline.components.event_TimelineItemFileView_Night_1_en",0,],
["features.messages.impl.timeline.components.event_TimelineItemFileView_Day_2_en","features.messages.impl.timeline.components.event_TimelineItemFileView_Night_2_en",0,],
["features.messages.impl.timeline.components.event_TimelineItemFileView_Day_3_en","features.messages.impl.timeline.components.event_TimelineItemFileView_Night_3_en",0,],
["features.messages.impl.timeline.components.event_TimelineItemFileView_Day_4_en","features.messages.impl.timeline.components.event_TimelineItemFileView_Night_4_en",0,],
-["features.messages.impl.timeline.components_TimelineItemGroupedEventsRowContentCollapse_Day_0_en","features.messages.impl.timeline.components_TimelineItemGroupedEventsRowContentCollapse_Night_0_en",20336,],
-["features.messages.impl.timeline.components_TimelineItemGroupedEventsRowContentExpanded_Day_0_en","features.messages.impl.timeline.components_TimelineItemGroupedEventsRowContentExpanded_Night_0_en",20336,],
-["features.messages.impl.timeline.components.event_TimelineItemImageViewHideMediaContent_Day_0_en","features.messages.impl.timeline.components.event_TimelineItemImageViewHideMediaContent_Night_0_en",20336,],
+["features.messages.impl.timeline.components_TimelineItemGroupedEventsRowContentCollapse_Day_0_en","features.messages.impl.timeline.components_TimelineItemGroupedEventsRowContentCollapse_Night_0_en",20350,],
+["features.messages.impl.timeline.components_TimelineItemGroupedEventsRowContentExpanded_Day_0_en","features.messages.impl.timeline.components_TimelineItemGroupedEventsRowContentExpanded_Night_0_en",20350,],
+["features.messages.impl.timeline.components.event_TimelineItemImageViewHideMediaContent_Day_0_en","features.messages.impl.timeline.components.event_TimelineItemImageViewHideMediaContent_Night_0_en",20350,],
["features.messages.impl.timeline.components.event_TimelineItemImageView_Day_0_en","features.messages.impl.timeline.components.event_TimelineItemImageView_Night_0_en",0,],
["features.messages.impl.timeline.components.event_TimelineItemImageView_Day_1_en","features.messages.impl.timeline.components.event_TimelineItemImageView_Night_1_en",0,],
["features.messages.impl.timeline.components.event_TimelineItemImageView_Day_2_en","features.messages.impl.timeline.components.event_TimelineItemImageView_Night_2_en",0,],
["features.messages.impl.timeline.components.event_TimelineItemImageView_Day_3_en","features.messages.impl.timeline.components.event_TimelineItemImageView_Night_3_en",0,],
["features.messages.impl.timeline.components.event_TimelineItemInformativeView_Day_0_en","features.messages.impl.timeline.components.event_TimelineItemInformativeView_Night_0_en",0,],
-["features.messages.impl.timeline.components.event_TimelineItemLegacyCallInviteView_Day_0_en","features.messages.impl.timeline.components.event_TimelineItemLegacyCallInviteView_Night_0_en",20336,],
+["features.messages.impl.timeline.components.event_TimelineItemLegacyCallInviteView_Day_0_en","features.messages.impl.timeline.components.event_TimelineItemLegacyCallInviteView_Night_0_en",20350,],
["features.messages.impl.timeline.components.event_TimelineItemLocationView_Day_0_en","features.messages.impl.timeline.components.event_TimelineItemLocationView_Night_0_en",0,],
["features.messages.impl.timeline.components.event_TimelineItemLocationView_Day_1_en","features.messages.impl.timeline.components.event_TimelineItemLocationView_Night_1_en",0,],
-["features.messages.impl.timeline.components.event_TimelineItemPollView_Day_0_en","features.messages.impl.timeline.components.event_TimelineItemPollView_Night_0_en",20336,],
-["features.messages.impl.timeline.components.event_TimelineItemPollView_Day_1_en","features.messages.impl.timeline.components.event_TimelineItemPollView_Night_1_en",20336,],
-["features.messages.impl.timeline.components.event_TimelineItemPollView_Day_2_en","features.messages.impl.timeline.components.event_TimelineItemPollView_Night_2_en",20336,],
-["features.messages.impl.timeline.components.event_TimelineItemPollView_Day_3_en","features.messages.impl.timeline.components.event_TimelineItemPollView_Night_3_en",20336,],
-["features.messages.impl.timeline.components_TimelineItemReactionsLayout_Day_0_en","features.messages.impl.timeline.components_TimelineItemReactionsLayout_Night_0_en",20336,],
+["features.messages.impl.timeline.components.event_TimelineItemPollView_Day_0_en","features.messages.impl.timeline.components.event_TimelineItemPollView_Night_0_en",20350,],
+["features.messages.impl.timeline.components.event_TimelineItemPollView_Day_1_en","features.messages.impl.timeline.components.event_TimelineItemPollView_Night_1_en",20350,],
+["features.messages.impl.timeline.components.event_TimelineItemPollView_Day_2_en","features.messages.impl.timeline.components.event_TimelineItemPollView_Night_2_en",20350,],
+["features.messages.impl.timeline.components.event_TimelineItemPollView_Day_3_en","features.messages.impl.timeline.components.event_TimelineItemPollView_Night_3_en",20350,],
+["features.messages.impl.timeline.components_TimelineItemReactionsLayout_Day_0_en","features.messages.impl.timeline.components_TimelineItemReactionsLayout_Night_0_en",20350,],
["features.messages.impl.timeline.components_TimelineItemReactionsViewFew_Day_0_en","features.messages.impl.timeline.components_TimelineItemReactionsViewFew_Night_0_en",0,],
-["features.messages.impl.timeline.components_TimelineItemReactionsViewIncoming_Day_0_en","features.messages.impl.timeline.components_TimelineItemReactionsViewIncoming_Night_0_en",20336,],
-["features.messages.impl.timeline.components_TimelineItemReactionsViewOutgoing_Day_0_en","features.messages.impl.timeline.components_TimelineItemReactionsViewOutgoing_Night_0_en",20336,],
+["features.messages.impl.timeline.components_TimelineItemReactionsViewIncoming_Day_0_en","features.messages.impl.timeline.components_TimelineItemReactionsViewIncoming_Night_0_en",20350,],
+["features.messages.impl.timeline.components_TimelineItemReactionsViewOutgoing_Day_0_en","features.messages.impl.timeline.components_TimelineItemReactionsViewOutgoing_Night_0_en",20350,],
["features.messages.impl.timeline.components_TimelineItemReactionsView_Day_0_en","features.messages.impl.timeline.components_TimelineItemReactionsView_Night_0_en",0,],
-["features.messages.impl.timeline.components.virtual_TimelineItemReadMarkerView_Day_0_en","features.messages.impl.timeline.components.virtual_TimelineItemReadMarkerView_Night_0_en",20336,],
+["features.messages.impl.timeline.components.virtual_TimelineItemReadMarkerView_Day_0_en","features.messages.impl.timeline.components.virtual_TimelineItemReadMarkerView_Night_0_en",20350,],
["features.messages.impl.timeline.components.receipt_TimelineItemReadReceiptView_Day_0_en","features.messages.impl.timeline.components.receipt_TimelineItemReadReceiptView_Night_0_en",0,],
["features.messages.impl.timeline.components.receipt_TimelineItemReadReceiptView_Day_1_en","features.messages.impl.timeline.components.receipt_TimelineItemReadReceiptView_Night_1_en",0,],
["features.messages.impl.timeline.components.receipt_TimelineItemReadReceiptView_Day_2_en","features.messages.impl.timeline.components.receipt_TimelineItemReadReceiptView_Night_2_en",0,],
@@ -1431,8 +1437,8 @@ export const screenshots = [
["features.messages.impl.timeline.components.receipt_TimelineItemReadReceiptView_Day_5_en","features.messages.impl.timeline.components.receipt_TimelineItemReadReceiptView_Night_5_en",0,],
["features.messages.impl.timeline.components.receipt_TimelineItemReadReceiptView_Day_6_en","features.messages.impl.timeline.components.receipt_TimelineItemReadReceiptView_Night_6_en",0,],
["features.messages.impl.timeline.components.receipt_TimelineItemReadReceiptView_Day_7_en","features.messages.impl.timeline.components.receipt_TimelineItemReadReceiptView_Night_7_en",0,],
-["features.messages.impl.timeline.components.event_TimelineItemRedactedView_Day_0_en","features.messages.impl.timeline.components.event_TimelineItemRedactedView_Night_0_en",20336,],
-["features.messages.impl.timeline.components.virtual_TimelineItemRoomBeginningView_Day_0_en","features.messages.impl.timeline.components.virtual_TimelineItemRoomBeginningView_Night_0_en",20336,],
+["features.messages.impl.timeline.components.event_TimelineItemRedactedView_Day_0_en","features.messages.impl.timeline.components.event_TimelineItemRedactedView_Night_0_en",20350,],
+["features.messages.impl.timeline.components.virtual_TimelineItemRoomBeginningView_Day_0_en","features.messages.impl.timeline.components.virtual_TimelineItemRoomBeginningView_Night_0_en",20350,],
["features.messages.impl.timeline.components_TimelineItemStateEventRow_Day_0_en","features.messages.impl.timeline.components_TimelineItemStateEventRow_Night_0_en",0,],
["features.messages.impl.timeline.components.event_TimelineItemStateView_Day_0_en","features.messages.impl.timeline.components.event_TimelineItemStateView_Night_0_en",0,],
["features.messages.impl.timeline.components.event_TimelineItemStickerView_Day_0_en","features.messages.impl.timeline.components.event_TimelineItemStickerView_Night_0_en",0,],
@@ -1447,8 +1453,8 @@ export const screenshots = [
["features.messages.impl.timeline.components.event_TimelineItemTextView_Day_3_en","features.messages.impl.timeline.components.event_TimelineItemTextView_Night_3_en",0,],
["features.messages.impl.timeline.components.event_TimelineItemTextView_Day_4_en","features.messages.impl.timeline.components.event_TimelineItemTextView_Night_4_en",0,],
["features.messages.impl.timeline.components.event_TimelineItemTextView_Day_5_en","features.messages.impl.timeline.components.event_TimelineItemTextView_Night_5_en",0,],
-["features.messages.impl.timeline.components.event_TimelineItemUnknownView_Day_0_en","features.messages.impl.timeline.components.event_TimelineItemUnknownView_Night_0_en",20336,],
-["features.messages.impl.timeline.components.event_TimelineItemVideoViewHideMediaContent_Day_0_en","features.messages.impl.timeline.components.event_TimelineItemVideoViewHideMediaContent_Night_0_en",20336,],
+["features.messages.impl.timeline.components.event_TimelineItemUnknownView_Day_0_en","features.messages.impl.timeline.components.event_TimelineItemUnknownView_Night_0_en",20350,],
+["features.messages.impl.timeline.components.event_TimelineItemVideoViewHideMediaContent_Day_0_en","features.messages.impl.timeline.components.event_TimelineItemVideoViewHideMediaContent_Night_0_en",20350,],
["features.messages.impl.timeline.components.event_TimelineItemVideoView_Day_0_en","features.messages.impl.timeline.components.event_TimelineItemVideoView_Night_0_en",0,],
["features.messages.impl.timeline.components.event_TimelineItemVideoView_Day_1_en","features.messages.impl.timeline.components.event_TimelineItemVideoView_Night_1_en",0,],
["features.messages.impl.timeline.components.event_TimelineItemVideoView_Day_2_en","features.messages.impl.timeline.components.event_TimelineItemVideoView_Night_2_en",0,],
@@ -1471,85 +1477,85 @@ export const screenshots = [
["features.messages.impl.timeline.components.event_TimelineItemVoiceView_Day_9_en","features.messages.impl.timeline.components.event_TimelineItemVoiceView_Night_9_en",0,],
["features.messages.impl.timeline.components.virtual_TimelineLoadingMoreIndicator_Day_0_en","features.messages.impl.timeline.components.virtual_TimelineLoadingMoreIndicator_Night_0_en",0,],
["features.messages.impl.timeline.components.event_TimelineVideoWithCaptionRow_Day_0_en","features.messages.impl.timeline.components.event_TimelineVideoWithCaptionRow_Night_0_en",0,],
-["features.messages.impl.timeline_TimelineViewMessageShield_Day_0_en","features.messages.impl.timeline_TimelineViewMessageShield_Night_0_en",20336,],
-["features.messages.impl.timeline_TimelineView_Day_0_en","features.messages.impl.timeline_TimelineView_Night_0_en",20336,],
+["features.messages.impl.timeline_TimelineViewMessageShield_Day_0_en","features.messages.impl.timeline_TimelineViewMessageShield_Night_0_en",20350,],
+["features.messages.impl.timeline_TimelineView_Day_0_en","features.messages.impl.timeline_TimelineView_Night_0_en",20350,],
["features.messages.impl.timeline_TimelineView_Day_10_en","features.messages.impl.timeline_TimelineView_Night_10_en",0,],
-["features.messages.impl.timeline_TimelineView_Day_11_en","features.messages.impl.timeline_TimelineView_Night_11_en",20336,],
-["features.messages.impl.timeline_TimelineView_Day_12_en","features.messages.impl.timeline_TimelineView_Night_12_en",20336,],
-["features.messages.impl.timeline_TimelineView_Day_13_en","features.messages.impl.timeline_TimelineView_Night_13_en",20336,],
-["features.messages.impl.timeline_TimelineView_Day_14_en","features.messages.impl.timeline_TimelineView_Night_14_en",20336,],
-["features.messages.impl.timeline_TimelineView_Day_15_en","features.messages.impl.timeline_TimelineView_Night_15_en",20336,],
-["features.messages.impl.timeline_TimelineView_Day_16_en","features.messages.impl.timeline_TimelineView_Night_16_en",20336,],
-["features.messages.impl.timeline_TimelineView_Day_17_en","features.messages.impl.timeline_TimelineView_Night_17_en",20336,],
-["features.messages.impl.timeline_TimelineView_Day_1_en","features.messages.impl.timeline_TimelineView_Night_1_en",20336,],
+["features.messages.impl.timeline_TimelineView_Day_11_en","features.messages.impl.timeline_TimelineView_Night_11_en",20350,],
+["features.messages.impl.timeline_TimelineView_Day_12_en","features.messages.impl.timeline_TimelineView_Night_12_en",20350,],
+["features.messages.impl.timeline_TimelineView_Day_13_en","features.messages.impl.timeline_TimelineView_Night_13_en",20350,],
+["features.messages.impl.timeline_TimelineView_Day_14_en","features.messages.impl.timeline_TimelineView_Night_14_en",20350,],
+["features.messages.impl.timeline_TimelineView_Day_15_en","features.messages.impl.timeline_TimelineView_Night_15_en",20350,],
+["features.messages.impl.timeline_TimelineView_Day_16_en","features.messages.impl.timeline_TimelineView_Night_16_en",20350,],
+["features.messages.impl.timeline_TimelineView_Day_17_en","features.messages.impl.timeline_TimelineView_Night_17_en",20350,],
+["features.messages.impl.timeline_TimelineView_Day_1_en","features.messages.impl.timeline_TimelineView_Night_1_en",20350,],
["features.messages.impl.timeline_TimelineView_Day_2_en","features.messages.impl.timeline_TimelineView_Night_2_en",0,],
["features.messages.impl.timeline_TimelineView_Day_3_en","features.messages.impl.timeline_TimelineView_Night_3_en",0,],
-["features.messages.impl.timeline_TimelineView_Day_4_en","features.messages.impl.timeline_TimelineView_Night_4_en",20336,],
+["features.messages.impl.timeline_TimelineView_Day_4_en","features.messages.impl.timeline_TimelineView_Night_4_en",20350,],
["features.messages.impl.timeline_TimelineView_Day_5_en","features.messages.impl.timeline_TimelineView_Night_5_en",0,],
-["features.messages.impl.timeline_TimelineView_Day_6_en","features.messages.impl.timeline_TimelineView_Night_6_en",20336,],
+["features.messages.impl.timeline_TimelineView_Day_6_en","features.messages.impl.timeline_TimelineView_Night_6_en",20350,],
["features.messages.impl.timeline_TimelineView_Day_7_en","features.messages.impl.timeline_TimelineView_Night_7_en",0,],
-["features.messages.impl.timeline_TimelineView_Day_8_en","features.messages.impl.timeline_TimelineView_Night_8_en",20336,],
+["features.messages.impl.timeline_TimelineView_Day_8_en","features.messages.impl.timeline_TimelineView_Night_8_en",20350,],
["features.messages.impl.timeline_TimelineView_Day_9_en","features.messages.impl.timeline_TimelineView_Night_9_en",0,],
["libraries.designsystem.components.avatar.internal_TombstonedRoomAvatar_Avatars_en","",0,],
["libraries.designsystem.theme.components_TopAppBarStr_App_Bars_en","",0,],
["libraries.designsystem.theme.components_TopAppBar_App_Bars_en","",0,],
-["libraries.troubleshoot.impl_TroubleshootNotificationsView_Day_0_en","libraries.troubleshoot.impl_TroubleshootNotificationsView_Night_0_en",20336,],
-["libraries.troubleshoot.impl_TroubleshootNotificationsView_Day_1_en","libraries.troubleshoot.impl_TroubleshootNotificationsView_Night_1_en",20336,],
-["libraries.troubleshoot.impl_TroubleshootNotificationsView_Day_2_en","libraries.troubleshoot.impl_TroubleshootNotificationsView_Night_2_en",20336,],
-["libraries.troubleshoot.impl_TroubleshootNotificationsView_Day_3_en","libraries.troubleshoot.impl_TroubleshootNotificationsView_Night_3_en",20336,],
-["libraries.troubleshoot.impl_TroubleshootNotificationsView_Day_4_en","libraries.troubleshoot.impl_TroubleshootNotificationsView_Night_4_en",20336,],
-["libraries.troubleshoot.impl_TroubleshootNotificationsView_Day_5_en","libraries.troubleshoot.impl_TroubleshootNotificationsView_Night_5_en",20336,],
-["libraries.troubleshoot.impl_TroubleshootNotificationsView_Day_6_en","libraries.troubleshoot.impl_TroubleshootNotificationsView_Night_6_en",20336,],
-["libraries.troubleshoot.impl_TroubleshootNotificationsView_Day_7_en","libraries.troubleshoot.impl_TroubleshootNotificationsView_Night_7_en",20336,],
+["libraries.troubleshoot.impl_TroubleshootNotificationsView_Day_0_en","libraries.troubleshoot.impl_TroubleshootNotificationsView_Night_0_en",20350,],
+["libraries.troubleshoot.impl_TroubleshootNotificationsView_Day_1_en","libraries.troubleshoot.impl_TroubleshootNotificationsView_Night_1_en",20350,],
+["libraries.troubleshoot.impl_TroubleshootNotificationsView_Day_2_en","libraries.troubleshoot.impl_TroubleshootNotificationsView_Night_2_en",20350,],
+["libraries.troubleshoot.impl_TroubleshootNotificationsView_Day_3_en","libraries.troubleshoot.impl_TroubleshootNotificationsView_Night_3_en",20350,],
+["libraries.troubleshoot.impl_TroubleshootNotificationsView_Day_4_en","libraries.troubleshoot.impl_TroubleshootNotificationsView_Night_4_en",20350,],
+["libraries.troubleshoot.impl_TroubleshootNotificationsView_Day_5_en","libraries.troubleshoot.impl_TroubleshootNotificationsView_Night_5_en",20350,],
+["libraries.troubleshoot.impl_TroubleshootNotificationsView_Day_6_en","libraries.troubleshoot.impl_TroubleshootNotificationsView_Night_6_en",20350,],
+["libraries.troubleshoot.impl_TroubleshootNotificationsView_Day_7_en","libraries.troubleshoot.impl_TroubleshootNotificationsView_Night_7_en",20350,],
["features.messages.impl.typing_TypingNotificationView_Day_0_en","features.messages.impl.typing_TypingNotificationView_Night_0_en",0,],
-["features.messages.impl.typing_TypingNotificationView_Day_1_en","features.messages.impl.typing_TypingNotificationView_Night_1_en",20336,],
-["features.messages.impl.typing_TypingNotificationView_Day_2_en","features.messages.impl.typing_TypingNotificationView_Night_2_en",20336,],
-["features.messages.impl.typing_TypingNotificationView_Day_3_en","features.messages.impl.typing_TypingNotificationView_Night_3_en",20336,],
-["features.messages.impl.typing_TypingNotificationView_Day_4_en","features.messages.impl.typing_TypingNotificationView_Night_4_en",20336,],
-["features.messages.impl.typing_TypingNotificationView_Day_5_en","features.messages.impl.typing_TypingNotificationView_Night_5_en",20336,],
-["features.messages.impl.typing_TypingNotificationView_Day_6_en","features.messages.impl.typing_TypingNotificationView_Night_6_en",20336,],
+["features.messages.impl.typing_TypingNotificationView_Day_1_en","features.messages.impl.typing_TypingNotificationView_Night_1_en",20350,],
+["features.messages.impl.typing_TypingNotificationView_Day_2_en","features.messages.impl.typing_TypingNotificationView_Night_2_en",20350,],
+["features.messages.impl.typing_TypingNotificationView_Day_3_en","features.messages.impl.typing_TypingNotificationView_Night_3_en",20350,],
+["features.messages.impl.typing_TypingNotificationView_Day_4_en","features.messages.impl.typing_TypingNotificationView_Night_4_en",20350,],
+["features.messages.impl.typing_TypingNotificationView_Day_5_en","features.messages.impl.typing_TypingNotificationView_Night_5_en",20350,],
+["features.messages.impl.typing_TypingNotificationView_Day_6_en","features.messages.impl.typing_TypingNotificationView_Night_6_en",20350,],
["features.messages.impl.typing_TypingNotificationView_Day_7_en","features.messages.impl.typing_TypingNotificationView_Night_7_en",0,],
["features.messages.impl.typing_TypingNotificationView_Day_8_en","features.messages.impl.typing_TypingNotificationView_Night_8_en",0,],
["libraries.designsystem.atomic.atoms_UnreadIndicatorAtom_Day_0_en","libraries.designsystem.atomic.atoms_UnreadIndicatorAtom_Night_0_en",0,],
-["libraries.matrix.ui.components_UnresolvedUserRow_en","",20336,],
+["libraries.matrix.ui.components_UnresolvedUserRow_en","",20350,],
["libraries.matrix.ui.components_UnsavedAvatar_Day_0_en","libraries.matrix.ui.components_UnsavedAvatar_Night_0_en",0,],
["libraries.designsystem.components.avatar.internal_UserAvatarColors_Day_0_en","libraries.designsystem.components.avatar.internal_UserAvatarColors_Night_0_en",0,],
-["features.roomdetails.impl.notificationsettings_UserDefinedRoomNotificationSettingsView_Day_0_en","features.roomdetails.impl.notificationsettings_UserDefinedRoomNotificationSettingsView_Night_0_en",20336,],
-["features.startchat.impl.components_UserListView_Day_0_en","features.startchat.impl.components_UserListView_Night_0_en",20336,],
-["features.startchat.impl.components_UserListView_Day_1_en","features.startchat.impl.components_UserListView_Night_1_en",20336,],
-["features.startchat.impl.components_UserListView_Day_2_en","features.startchat.impl.components_UserListView_Night_2_en",20336,],
+["features.roomdetails.impl.notificationsettings_UserDefinedRoomNotificationSettingsView_Day_0_en","features.roomdetails.impl.notificationsettings_UserDefinedRoomNotificationSettingsView_Night_0_en",20350,],
+["features.startchat.impl.components_UserListView_Day_0_en","features.startchat.impl.components_UserListView_Night_0_en",20350,],
+["features.startchat.impl.components_UserListView_Day_1_en","features.startchat.impl.components_UserListView_Night_1_en",20350,],
+["features.startchat.impl.components_UserListView_Day_2_en","features.startchat.impl.components_UserListView_Night_2_en",20350,],
["features.startchat.impl.components_UserListView_Day_3_en","features.startchat.impl.components_UserListView_Night_3_en",0,],
["features.startchat.impl.components_UserListView_Day_4_en","features.startchat.impl.components_UserListView_Night_4_en",0,],
["features.startchat.impl.components_UserListView_Day_5_en","features.startchat.impl.components_UserListView_Night_5_en",0,],
["features.startchat.impl.components_UserListView_Day_6_en","features.startchat.impl.components_UserListView_Night_6_en",0,],
-["features.startchat.impl.components_UserListView_Day_7_en","features.startchat.impl.components_UserListView_Night_7_en",20336,],
+["features.startchat.impl.components_UserListView_Day_7_en","features.startchat.impl.components_UserListView_Night_7_en",20350,],
["features.startchat.impl.components_UserListView_Day_8_en","features.startchat.impl.components_UserListView_Night_8_en",0,],
-["features.startchat.impl.components_UserListView_Day_9_en","features.startchat.impl.components_UserListView_Night_9_en",20336,],
+["features.startchat.impl.components_UserListView_Day_9_en","features.startchat.impl.components_UserListView_Night_9_en",20350,],
["features.preferences.impl.user_UserPreferences_Day_0_en","features.preferences.impl.user_UserPreferences_Night_0_en",0,],
["features.preferences.impl.user_UserPreferences_Day_1_en","features.preferences.impl.user_UserPreferences_Night_1_en",0,],
["features.preferences.impl.user_UserPreferences_Day_2_en","features.preferences.impl.user_UserPreferences_Night_2_en",0,],
-["features.userprofile.shared_UserProfileHeaderSectionWithVerificationViolation_Day_0_en","features.userprofile.shared_UserProfileHeaderSectionWithVerificationViolation_Night_0_en",20336,],
-["features.userprofile.shared_UserProfileHeaderSection_Day_0_en","features.userprofile.shared_UserProfileHeaderSection_Night_0_en",20336,],
-["features.userprofile.shared_UserProfileView_Day_0_en","features.userprofile.shared_UserProfileView_Night_0_en",20336,],
-["features.userprofile.shared_UserProfileView_Day_1_en","features.userprofile.shared_UserProfileView_Night_1_en",20336,],
-["features.userprofile.shared_UserProfileView_Day_2_en","features.userprofile.shared_UserProfileView_Night_2_en",20336,],
-["features.userprofile.shared_UserProfileView_Day_3_en","features.userprofile.shared_UserProfileView_Night_3_en",20336,],
-["features.userprofile.shared_UserProfileView_Day_4_en","features.userprofile.shared_UserProfileView_Night_4_en",20336,],
-["features.userprofile.shared_UserProfileView_Day_5_en","features.userprofile.shared_UserProfileView_Night_5_en",20336,],
-["features.userprofile.shared_UserProfileView_Day_6_en","features.userprofile.shared_UserProfileView_Night_6_en",20336,],
-["features.userprofile.shared_UserProfileView_Day_7_en","features.userprofile.shared_UserProfileView_Night_7_en",20336,],
-["features.userprofile.shared_UserProfileView_Day_8_en","features.userprofile.shared_UserProfileView_Night_8_en",20336,],
-["features.userprofile.shared_UserProfileView_Day_9_en","features.userprofile.shared_UserProfileView_Night_9_en",20336,],
+["features.userprofile.shared_UserProfileHeaderSectionWithVerificationViolation_Day_0_en","features.userprofile.shared_UserProfileHeaderSectionWithVerificationViolation_Night_0_en",20350,],
+["features.userprofile.shared_UserProfileHeaderSection_Day_0_en","features.userprofile.shared_UserProfileHeaderSection_Night_0_en",20350,],
+["features.userprofile.shared_UserProfileView_Day_0_en","features.userprofile.shared_UserProfileView_Night_0_en",20350,],
+["features.userprofile.shared_UserProfileView_Day_1_en","features.userprofile.shared_UserProfileView_Night_1_en",20350,],
+["features.userprofile.shared_UserProfileView_Day_2_en","features.userprofile.shared_UserProfileView_Night_2_en",20350,],
+["features.userprofile.shared_UserProfileView_Day_3_en","features.userprofile.shared_UserProfileView_Night_3_en",20350,],
+["features.userprofile.shared_UserProfileView_Day_4_en","features.userprofile.shared_UserProfileView_Night_4_en",20350,],
+["features.userprofile.shared_UserProfileView_Day_5_en","features.userprofile.shared_UserProfileView_Night_5_en",20350,],
+["features.userprofile.shared_UserProfileView_Day_6_en","features.userprofile.shared_UserProfileView_Night_6_en",20350,],
+["features.userprofile.shared_UserProfileView_Day_7_en","features.userprofile.shared_UserProfileView_Night_7_en",20350,],
+["features.userprofile.shared_UserProfileView_Day_8_en","features.userprofile.shared_UserProfileView_Night_8_en",20350,],
+["features.userprofile.shared_UserProfileView_Day_9_en","features.userprofile.shared_UserProfileView_Night_9_en",20350,],
["features.verifysession.impl.ui_VerificationUserProfileContent_Day_0_en","features.verifysession.impl.ui_VerificationUserProfileContent_Night_0_en",0,],
["libraries.designsystem.ruler_VerticalRuler_Day_0_en","libraries.designsystem.ruler_VerticalRuler_Night_0_en",0,],
["libraries.mediaviewer.impl.gallery.ui_VideoItemView_Day_0_en","libraries.mediaviewer.impl.gallery.ui_VideoItemView_Night_0_en",0,],
["libraries.mediaviewer.impl.gallery.ui_VideoItemView_Day_1_en","libraries.mediaviewer.impl.gallery.ui_VideoItemView_Night_1_en",0,],
-["features.preferences.impl.advanced_VideoQualitySelectorDialog_Day_0_en","features.preferences.impl.advanced_VideoQualitySelectorDialog_Night_0_en",20336,],
-["features.messages.impl.attachments.preview_VideoQualitySelectorDialog_Day_0_en","features.messages.impl.attachments.preview_VideoQualitySelectorDialog_Night_0_en",20336,],
+["features.preferences.impl.advanced_VideoQualitySelectorDialog_Day_0_en","features.preferences.impl.advanced_VideoQualitySelectorDialog_Night_0_en",20350,],
+["features.messages.impl.attachments.preview_VideoQualitySelectorDialog_Day_0_en","features.messages.impl.attachments.preview_VideoQualitySelectorDialog_Night_0_en",20350,],
["features.viewfolder.impl.file_ViewFileView_Day_0_en","features.viewfolder.impl.file_ViewFileView_Night_0_en",0,],
["features.viewfolder.impl.file_ViewFileView_Day_1_en","features.viewfolder.impl.file_ViewFileView_Night_1_en",0,],
["features.viewfolder.impl.file_ViewFileView_Day_2_en","features.viewfolder.impl.file_ViewFileView_Night_2_en",0,],
-["features.viewfolder.impl.file_ViewFileView_Day_3_en","features.viewfolder.impl.file_ViewFileView_Night_3_en",20336,],
+["features.viewfolder.impl.file_ViewFileView_Day_3_en","features.viewfolder.impl.file_ViewFileView_Night_3_en",20350,],
["features.viewfolder.impl.file_ViewFileView_Day_4_en","features.viewfolder.impl.file_ViewFileView_Night_4_en",0,],
["features.viewfolder.impl.file_ViewFileView_Day_5_en","features.viewfolder.impl.file_ViewFileView_Night_5_en",0,],
["features.viewfolder.impl.folder_ViewFolderView_Day_0_en","features.viewfolder.impl.folder_ViewFolderView_Night_0_en",0,],
diff --git a/services/analytics/api/src/main/kotlin/io/element/android/services/analytics/api/AnalyticsService.kt b/services/analytics/api/src/main/kotlin/io/element/android/services/analytics/api/AnalyticsService.kt
index 750a6d1d17..589abf28fe 100644
--- a/services/analytics/api/src/main/kotlin/io/element/android/services/analytics/api/AnalyticsService.kt
+++ b/services/analytics/api/src/main/kotlin/io/element/android/services/analytics/api/AnalyticsService.kt
@@ -47,9 +47,4 @@ interface AnalyticsService : AnalyticsTracker, ErrorTracker {
* Update analyticsId from the AccountData.
*/
suspend fun setAnalyticsId(analyticsId: String)
-
- /**
- * Reset the analytics service (will ask for user consent again).
- */
- suspend fun reset()
}
diff --git a/services/analytics/impl/build.gradle.kts b/services/analytics/impl/build.gradle.kts
index 45b5d0a9f4..83eebead5d 100644
--- a/services/analytics/impl/build.gradle.kts
+++ b/services/analytics/impl/build.gradle.kts
@@ -1,4 +1,5 @@
import extension.setupDependencyInjection
+import extension.testCommonDependencies
/*
* Copyright 2023, 2024 New Vector Ltd.
@@ -30,10 +31,7 @@ dependencies {
api(projects.services.analytics.api)
implementation(libs.androidx.datastore.preferences)
- testImplementation(libs.coroutines.test)
- testImplementation(libs.test.junit)
- testImplementation(libs.test.truth)
+ testCommonDependencies(libs)
testImplementation(projects.libraries.sessionStorage.test)
testImplementation(projects.services.analyticsproviders.test)
- testImplementation(projects.tests.testutils)
}
diff --git a/services/analytics/impl/src/main/kotlin/io/element/android/services/analytics/impl/DefaultAnalyticsService.kt b/services/analytics/impl/src/main/kotlin/io/element/android/services/analytics/impl/DefaultAnalyticsService.kt
index 1df6c3ca6a..d80a8288ad 100644
--- a/services/analytics/impl/src/main/kotlin/io/element/android/services/analytics/impl/DefaultAnalyticsService.kt
+++ b/services/analytics/impl/src/main/kotlin/io/element/android/services/analytics/impl/DefaultAnalyticsService.kt
@@ -70,10 +70,6 @@ class DefaultAnalyticsService(
analyticsStore.setDidAskUserConsent()
}
- override suspend fun reset() {
- analyticsStore.setDidAskUserConsent(false)
- }
-
override suspend fun setAnalyticsId(analyticsId: String) {
Timber.tag(analyticsTag.value).d("setAnalyticsId($analyticsId)")
analyticsStore.setAnalyticsId(analyticsId)
diff --git a/services/analytics/impl/src/test/kotlin/io/element/android/services/analytics/impl/DefaultAnalyticsServiceTest.kt b/services/analytics/impl/src/test/kotlin/io/element/android/services/analytics/impl/DefaultAnalyticsServiceTest.kt
index e05a6e4208..6e65303761 100644
--- a/services/analytics/impl/src/test/kotlin/io/element/android/services/analytics/impl/DefaultAnalyticsServiceTest.kt
+++ b/services/analytics/impl/src/test/kotlin/io/element/android/services/analytics/impl/DefaultAnalyticsServiceTest.kt
@@ -180,20 +180,6 @@ class DefaultAnalyticsServiceTest {
resetLambda.assertions().isCalledOnce()
}
- @Test
- fun `when reset is invoked, the user consent is reset`() = runTest {
- val store = FakeAnalyticsStore(
- defaultDidAskUserConsent = true,
- )
- val sut = createDefaultAnalyticsService(
- coroutineScope = backgroundScope,
- analyticsStore = store,
- )
- assertThat(store.didAskUserConsentFlow.first()).isTrue()
- sut.reset()
- assertThat(store.didAskUserConsentFlow.first()).isFalse()
- }
-
@Test
fun `when a session is added, nothing happen`() = runTest {
val sut = createDefaultAnalyticsService(
diff --git a/services/analytics/noop/src/main/kotlin/io/element/android/services/analytics/noop/NoopAnalyticsService.kt b/services/analytics/noop/src/main/kotlin/io/element/android/services/analytics/noop/NoopAnalyticsService.kt
index f43367c66a..db03ca5553 100644
--- a/services/analytics/noop/src/main/kotlin/io/element/android/services/analytics/noop/NoopAnalyticsService.kt
+++ b/services/analytics/noop/src/main/kotlin/io/element/android/services/analytics/noop/NoopAnalyticsService.kt
@@ -31,7 +31,6 @@ class NoopAnalyticsService : AnalyticsService {
override suspend fun setDidAskUserConsent() = Unit
override val analyticsIdFlow: Flow = flowOf("")
override suspend fun setAnalyticsId(analyticsId: String) = Unit
- override suspend fun reset() = Unit
override fun capture(event: VectorAnalyticsEvent) = Unit
override fun screen(screen: VectorAnalyticsScreen) = Unit
override fun updateUserProperties(userProperties: UserProperties) = Unit
diff --git a/services/analytics/test/src/main/kotlin/io/element/android/services/analytics/test/FakeAnalyticsService.kt b/services/analytics/test/src/main/kotlin/io/element/android/services/analytics/test/FakeAnalyticsService.kt
index 081f66d4e6..f8b250e37b 100644
--- a/services/analytics/test/src/main/kotlin/io/element/android/services/analytics/test/FakeAnalyticsService.kt
+++ b/services/analytics/test/src/main/kotlin/io/element/android/services/analytics/test/FakeAnalyticsService.kt
@@ -20,7 +20,6 @@ import kotlinx.coroutines.flow.asStateFlow
class FakeAnalyticsService(
isEnabled: Boolean = false,
didAskUserConsent: Boolean = false,
- private val resetLambda: () -> Unit = {},
) : AnalyticsService {
private val isEnabledFlow = MutableStateFlow(isEnabled)
override val didAskUserConsentFlow = MutableStateFlow(didAskUserConsent)
@@ -65,9 +64,4 @@ class FakeAnalyticsService(
override fun updateSuperProperties(updatedProperties: SuperProperties) {
// No op
}
-
- override suspend fun reset() {
- didAskUserConsentFlow.value = false
- resetLambda()
- }
}
diff --git a/services/analyticsproviders/posthog/build.gradle.kts b/services/analyticsproviders/posthog/build.gradle.kts
index b364552fb1..ffcb2ba590 100644
--- a/services/analyticsproviders/posthog/build.gradle.kts
+++ b/services/analyticsproviders/posthog/build.gradle.kts
@@ -1,6 +1,7 @@
import config.BuildTimeConfig
import extension.buildConfigFieldStr
import extension.setupDependencyInjection
+import extension.testCommonDependencies
/*
* Copyright 2023, 2024 New Vector Ltd.
@@ -42,9 +43,5 @@ dependencies {
implementation(projects.libraries.di)
implementation(projects.services.analyticsproviders.api)
- testImplementation(libs.coroutines.test)
- testImplementation(libs.test.truth)
- testImplementation(libs.test.junit)
- testImplementation(projects.tests.testutils)
- testImplementation(libs.test.mockk)
+ testCommonDependencies(libs)
}
diff --git a/services/apperror/impl/build.gradle.kts b/services/apperror/impl/build.gradle.kts
index 606c9a3d64..673468e99a 100644
--- a/services/apperror/impl/build.gradle.kts
+++ b/services/apperror/impl/build.gradle.kts
@@ -1,4 +1,5 @@
import extension.setupDependencyInjection
+import extension.testCommonDependencies
/*
* Copyright 2022-2024 New Vector Ltd.
@@ -29,9 +30,6 @@ dependencies {
api(projects.services.apperror.api)
- testImplementation(libs.test.junit)
- testImplementation(libs.coroutines.test)
- testImplementation(libs.test.turbine)
- testImplementation(libs.test.truth)
+ testCommonDependencies(libs)
testImplementation(projects.services.toolbox.test)
}
diff --git a/services/appnavstate/impl/build.gradle.kts b/services/appnavstate/impl/build.gradle.kts
index 13a7cdfe1c..ba58e96f69 100644
--- a/services/appnavstate/impl/build.gradle.kts
+++ b/services/appnavstate/impl/build.gradle.kts
@@ -1,4 +1,5 @@
import extension.setupDependencyInjection
+import extension.testCommonDependencies
/*
* Copyright 2022-2024 New Vector Ltd.
@@ -28,10 +29,7 @@ dependencies {
api(projects.services.appnavstate.api)
- testImplementation(libs.test.junit)
- testImplementation(libs.coroutines.test)
- testImplementation(libs.test.truth)
+ testCommonDependencies(libs)
testImplementation(projects.libraries.matrix.test)
- testImplementation(projects.tests.testutils)
testImplementation(projects.services.appnavstate.test)
}
diff --git a/tests/konsist/src/test/kotlin/io/element/android/tests/konsist/KonsistClassNameTest.kt b/tests/konsist/src/test/kotlin/io/element/android/tests/konsist/KonsistClassNameTest.kt
index d24a489c6a..8a0e6d0966 100644
--- a/tests/konsist/src/test/kotlin/io/element/android/tests/konsist/KonsistClassNameTest.kt
+++ b/tests/konsist/src/test/kotlin/io/element/android/tests/konsist/KonsistClassNameTest.kt
@@ -20,6 +20,7 @@ import com.lemonappdev.konsist.api.ext.list.withoutName
import com.lemonappdev.konsist.api.ext.list.withoutNameStartingWith
import com.lemonappdev.konsist.api.verify.assertEmpty
import com.lemonappdev.konsist.api.verify.assertTrue
+import io.element.android.libraries.architecture.BaseFlowNode
import io.element.android.libraries.architecture.Presenter
import org.junit.Test
@@ -44,6 +45,16 @@ class KonsistClassNameTest {
}
}
+ @Test
+ fun `Classes extending 'BaseFlowNode' should have 'FlowNode' suffix`() {
+ Konsist.scopeFromProject()
+ .classes()
+ .withAllParentsOf(BaseFlowNode::class)
+ .assertTrue {
+ it.name.endsWith("FlowNode")
+ }
+ }
+
@Test
fun `Classes extending 'PreviewParameterProvider' name MUST end with 'Provider' and MUST contain provided class name`() {
Konsist.scopeFromProduction()
diff --git a/tests/konsist/src/test/kotlin/io/element/android/tests/konsist/KonsistPreviewTest.kt b/tests/konsist/src/test/kotlin/io/element/android/tests/konsist/KonsistPreviewTest.kt
index d0408fb61a..9cbd2efdc4 100644
--- a/tests/konsist/src/test/kotlin/io/element/android/tests/konsist/KonsistPreviewTest.kt
+++ b/tests/konsist/src/test/kotlin/io/element/android/tests/konsist/KonsistPreviewTest.kt
@@ -114,6 +114,8 @@ class KonsistPreviewTest {
"PollContentViewDisclosedPreview",
"PollContentViewEndedPreview",
"PollContentViewUndisclosedPreview",
+ "ProgressDialogWithContentPreview",
+ "ProgressDialogWithTextAndContentPreview",
"ReadReceiptBottomSheetPreview",
"RoomMemberListViewBannedPreview",
"SasEmojisPreview",
diff --git a/tests/testutils/src/main/kotlin/io/element/android/tests/testutils/Timber.kt b/tests/testutils/src/main/kotlin/io/element/android/tests/testutils/Timber.kt
new file mode 100644
index 0000000000..2aad499698
--- /dev/null
+++ b/tests/testutils/src/main/kotlin/io/element/android/tests/testutils/Timber.kt
@@ -0,0 +1,18 @@
+/*
+ * Copyright 2025 New Vector Ltd.
+ *
+ * SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial
+ * Please see LICENSE files in the repository root for full details.
+ */
+
+package io.element.android.tests.testutils
+
+import timber.log.Timber
+
+fun plantTestTimber() {
+ Timber.plant(object : Timber.Tree() {
+ override fun log(priority: Int, tag: String?, message: String, t: Throwable?) {
+ println("$tag: $message")
+ }
+ })
+}
diff --git a/tests/testutils/src/main/kotlin/io/element/android/tests/testutils/node/TestParentNode.kt b/tests/testutils/src/main/kotlin/io/element/android/tests/testutils/node/TestParentNode.kt
new file mode 100644
index 0000000000..79def028f7
--- /dev/null
+++ b/tests/testutils/src/main/kotlin/io/element/android/tests/testutils/node/TestParentNode.kt
@@ -0,0 +1,49 @@
+/*
+ * Copyright 2025 New Vector Ltd.
+ *
+ * SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial
+ * Please see LICENSE files in the repository root for full details.
+ */
+
+package io.element.android.tests.testutils.node
+
+import com.bumble.appyx.core.modality.BuildContext
+import com.bumble.appyx.core.node.EmptyNodeView
+import com.bumble.appyx.core.node.Node
+import com.bumble.appyx.core.plugin.Plugin
+import io.element.android.libraries.architecture.AssistedNodeFactory
+import io.element.android.libraries.architecture.NodeFactoriesBindings
+import io.element.android.libraries.di.DependencyInjectionGraphOwner
+import kotlin.reflect.KClass
+
+/**
+ * A parent Node that can create a single type of child Node using the provided factory.
+ * This is useful to test a Feature entry point, by providing a fake parent that can create a
+ * child Node.
+ */
+class TestParentNode(
+ private val childNodeClass: KClass,
+ private val childNodeFactory: (buildContext: BuildContext, plugins: List) -> Child,
+) : DependencyInjectionGraphOwner,
+ Node(
+ buildContext = BuildContext.Companion.root(savedStateMap = null),
+ plugins = emptyList(),
+ view = EmptyNodeView,
+ ) {
+ override val graph: NodeFactoriesBindings = NodeFactoriesBindings {
+ mapOf(
+ childNodeClass to AssistedNodeFactory { buildContext, plugins ->
+ childNodeFactory(buildContext, plugins)
+ }
+ )
+ }
+
+ companion object {
+ // Inline factory function with reified type parameter
+ inline fun create(
+ noinline childNodeFactory: (buildContext: BuildContext, plugins: List) -> Child,
+ ): TestParentNode {
+ return TestParentNode(Child::class, childNodeFactory)
+ }
+ }
+}
diff --git a/tests/uitests/src/test/snapshots/images/appnav.root_RootView_Day_2_en.png b/tests/uitests/src/test/snapshots/images/appnav.root_RootView_Day_2_en.png
index 3e22d6f5d9..6ed1ff9038 100644
--- a/tests/uitests/src/test/snapshots/images/appnav.root_RootView_Day_2_en.png
+++ b/tests/uitests/src/test/snapshots/images/appnav.root_RootView_Day_2_en.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:fa7b667e43c0c85a2e4774549d1dbadd5c58049733cc51d9160ad5b245825cd9
-size 21844
+oid sha256:9d27f8fbaed8cdbb6ad03414cf6f8c2d38b3269731ee72f5fe9eab1ad6afe9df
+size 21819
diff --git a/tests/uitests/src/test/snapshots/images/appnav.root_RootView_Night_2_en.png b/tests/uitests/src/test/snapshots/images/appnav.root_RootView_Night_2_en.png
index c52172b489..d213d6846f 100644
--- a/tests/uitests/src/test/snapshots/images/appnav.root_RootView_Night_2_en.png
+++ b/tests/uitests/src/test/snapshots/images/appnav.root_RootView_Night_2_en.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:345f0bbff65c752f0bc3295f58befff79cf681d00b0a476e1ea5c9b625b81087
-size 19977
+oid sha256:4227570b201034be916a714dcf27c9ab4d17d6cc3d47a8eab9ffae3b9b61bb4a
+size 19967
diff --git a/tests/uitests/src/test/snapshots/images/features.changeroommemberroles.impl_ChangeRolesView_Day_6_en.png b/tests/uitests/src/test/snapshots/images/features.changeroommemberroles.impl_ChangeRolesView_Day_6_en.png
index 4041cbc7ed..af622b1d7a 100644
--- a/tests/uitests/src/test/snapshots/images/features.changeroommemberroles.impl_ChangeRolesView_Day_6_en.png
+++ b/tests/uitests/src/test/snapshots/images/features.changeroommemberroles.impl_ChangeRolesView_Day_6_en.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:623941550c734147c294ec2294840d9353ac756b054b402b365060602ff614b0
-size 58961
+oid sha256:3c08f5d276bdf222ec98929baa53275e40a76282c9bd15bbf3dce231223ea863
+size 59021
diff --git a/tests/uitests/src/test/snapshots/images/features.changeroommemberroles.impl_ChangeRolesView_Night_6_en.png b/tests/uitests/src/test/snapshots/images/features.changeroommemberroles.impl_ChangeRolesView_Night_6_en.png
index 55506783c0..91bcf2c395 100644
--- a/tests/uitests/src/test/snapshots/images/features.changeroommemberroles.impl_ChangeRolesView_Night_6_en.png
+++ b/tests/uitests/src/test/snapshots/images/features.changeroommemberroles.impl_ChangeRolesView_Night_6_en.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:17ca777cfd4e056078519282f928799dcb2e9aac1ab2757b7cb4cbb1fe93c573
-size 56855
+oid sha256:ded460697c44b23c47534b786d5f259d2ee87bbb6cffb8c6cbd6777bd40090c4
+size 56849
diff --git a/tests/uitests/src/test/snapshots/images/features.createroom.impl.addpeople_AddPeopleView_Day_3_en.png b/tests/uitests/src/test/snapshots/images/features.createroom.impl.addpeople_AddPeopleView_Day_3_en.png
new file mode 100644
index 0000000000..338eb8d3f6
--- /dev/null
+++ b/tests/uitests/src/test/snapshots/images/features.createroom.impl.addpeople_AddPeopleView_Day_3_en.png
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:7415b3286707130c0218a8d1e82a9d9c61c8eec8df346653dd67626d0dd7709c
+size 10038
diff --git a/tests/uitests/src/test/snapshots/images/features.createroom.impl.addpeople_AddPeopleView_Night_3_en.png b/tests/uitests/src/test/snapshots/images/features.createroom.impl.addpeople_AddPeopleView_Night_3_en.png
new file mode 100644
index 0000000000..5bd1590652
--- /dev/null
+++ b/tests/uitests/src/test/snapshots/images/features.createroom.impl.addpeople_AddPeopleView_Night_3_en.png
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:39c67413ca997982b0fcd32831ccedee1d7a0763619784b8758b194df6c7ff81
+size 9639
diff --git a/tests/uitests/src/test/snapshots/images/features.home.impl.spaces_HomeSpaceItemView_Day_0_en.png b/tests/uitests/src/test/snapshots/images/features.home.impl.spaces_HomeSpaceItemView_Day_0_en.png
deleted file mode 100644
index 4dc4712e67..0000000000
--- a/tests/uitests/src/test/snapshots/images/features.home.impl.spaces_HomeSpaceItemView_Day_0_en.png
+++ /dev/null
@@ -1,3 +0,0 @@
-version https://git-lfs.github.com/spec/v1
-oid sha256:a241e70cffe61158784ac75425e13cd8d2695406f6e52a93ca7dddfdc9f99caa
-size 14164
diff --git a/tests/uitests/src/test/snapshots/images/features.home.impl.spaces_HomeSpaceItemView_Day_1_en.png b/tests/uitests/src/test/snapshots/images/features.home.impl.spaces_HomeSpaceItemView_Day_1_en.png
deleted file mode 100644
index dc4f56f39b..0000000000
--- a/tests/uitests/src/test/snapshots/images/features.home.impl.spaces_HomeSpaceItemView_Day_1_en.png
+++ /dev/null
@@ -1,3 +0,0 @@
-version https://git-lfs.github.com/spec/v1
-oid sha256:864ab3319f7074643b58d2dd6da22a4c5493bae25502c89bf2c3503bc57cfe91
-size 11628
diff --git a/tests/uitests/src/test/snapshots/images/features.home.impl.spaces_HomeSpaceItemView_Day_2_en.png b/tests/uitests/src/test/snapshots/images/features.home.impl.spaces_HomeSpaceItemView_Day_2_en.png
deleted file mode 100644
index 403a96cbad..0000000000
--- a/tests/uitests/src/test/snapshots/images/features.home.impl.spaces_HomeSpaceItemView_Day_2_en.png
+++ /dev/null
@@ -1,3 +0,0 @@
-version https://git-lfs.github.com/spec/v1
-oid sha256:ba93e44b8732d7bf78b25200a5db6e8a329f970aa1fb6a002033c9ebfd09b805
-size 11723
diff --git a/tests/uitests/src/test/snapshots/images/features.home.impl.spaces_HomeSpaceItemView_Day_3_en.png b/tests/uitests/src/test/snapshots/images/features.home.impl.spaces_HomeSpaceItemView_Day_3_en.png
deleted file mode 100644
index f12b559ded..0000000000
--- a/tests/uitests/src/test/snapshots/images/features.home.impl.spaces_HomeSpaceItemView_Day_3_en.png
+++ /dev/null
@@ -1,3 +0,0 @@
-version https://git-lfs.github.com/spec/v1
-oid sha256:59b6f98dc65ae4be92b7cdfde9778b390b6474205f75d48061d6345eece53675
-size 19034
diff --git a/tests/uitests/src/test/snapshots/images/features.home.impl.spaces_HomeSpaceItemView_Day_4_en.png b/tests/uitests/src/test/snapshots/images/features.home.impl.spaces_HomeSpaceItemView_Day_4_en.png
deleted file mode 100644
index 833415fba7..0000000000
--- a/tests/uitests/src/test/snapshots/images/features.home.impl.spaces_HomeSpaceItemView_Day_4_en.png
+++ /dev/null
@@ -1,3 +0,0 @@
-version https://git-lfs.github.com/spec/v1
-oid sha256:b4a8cef8dc61dd71458d7518548e83f5e4484fd9dc740fefc690769ffbf6bd80
-size 18949
diff --git a/tests/uitests/src/test/snapshots/images/features.home.impl.spaces_HomeSpaceItemView_Night_0_en.png b/tests/uitests/src/test/snapshots/images/features.home.impl.spaces_HomeSpaceItemView_Night_0_en.png
deleted file mode 100644
index 175a0f0151..0000000000
--- a/tests/uitests/src/test/snapshots/images/features.home.impl.spaces_HomeSpaceItemView_Night_0_en.png
+++ /dev/null
@@ -1,3 +0,0 @@
-version https://git-lfs.github.com/spec/v1
-oid sha256:7ce65c4dd01458194792d0a14eafc66e6e6f0a0e0f59259e4661322d0cf9a46d
-size 13819
diff --git a/tests/uitests/src/test/snapshots/images/features.home.impl.spaces_HomeSpaceItemView_Night_1_en.png b/tests/uitests/src/test/snapshots/images/features.home.impl.spaces_HomeSpaceItemView_Night_1_en.png
deleted file mode 100644
index 443230a159..0000000000
--- a/tests/uitests/src/test/snapshots/images/features.home.impl.spaces_HomeSpaceItemView_Night_1_en.png
+++ /dev/null
@@ -1,3 +0,0 @@
-version https://git-lfs.github.com/spec/v1
-oid sha256:3e3765e543cce879b97a35b8c3e1cdef4b6c9ce4b1739b9d9a544d6a56118399
-size 11414
diff --git a/tests/uitests/src/test/snapshots/images/features.home.impl.spaces_HomeSpaceItemView_Night_2_en.png b/tests/uitests/src/test/snapshots/images/features.home.impl.spaces_HomeSpaceItemView_Night_2_en.png
deleted file mode 100644
index 9ad249a00f..0000000000
--- a/tests/uitests/src/test/snapshots/images/features.home.impl.spaces_HomeSpaceItemView_Night_2_en.png
+++ /dev/null
@@ -1,3 +0,0 @@
-version https://git-lfs.github.com/spec/v1
-oid sha256:51b283fb8e976c8717abeef61dcf294f3efd52b7291fdf023c09759e6df6513d
-size 11337
diff --git a/tests/uitests/src/test/snapshots/images/features.home.impl.spaces_HomeSpaceItemView_Night_3_en.png b/tests/uitests/src/test/snapshots/images/features.home.impl.spaces_HomeSpaceItemView_Night_3_en.png
deleted file mode 100644
index ceafbe6d6a..0000000000
--- a/tests/uitests/src/test/snapshots/images/features.home.impl.spaces_HomeSpaceItemView_Night_3_en.png
+++ /dev/null
@@ -1,3 +0,0 @@
-version https://git-lfs.github.com/spec/v1
-oid sha256:c440b9628b8105b73f5f576c1b99269a74a89ab07f56080ad53cc888aca24da3
-size 18111
diff --git a/tests/uitests/src/test/snapshots/images/features.home.impl.spaces_HomeSpaceItemView_Night_4_en.png b/tests/uitests/src/test/snapshots/images/features.home.impl.spaces_HomeSpaceItemView_Night_4_en.png
deleted file mode 100644
index 3cf9c17cda..0000000000
--- a/tests/uitests/src/test/snapshots/images/features.home.impl.spaces_HomeSpaceItemView_Night_4_en.png
+++ /dev/null
@@ -1,3 +0,0 @@
-version https://git-lfs.github.com/spec/v1
-oid sha256:9ddecc15d26dbdd648ec7abbff51718da03326ebf32a2d675563110c096a198b
-size 18141
diff --git a/tests/uitests/src/test/snapshots/images/features.home.impl.spaces_HomeSpacesView_Day_0_en.png b/tests/uitests/src/test/snapshots/images/features.home.impl.spaces_HomeSpacesView_Day_0_en.png
index bd804824f9..df4bd9bbc2 100644
--- a/tests/uitests/src/test/snapshots/images/features.home.impl.spaces_HomeSpacesView_Day_0_en.png
+++ b/tests/uitests/src/test/snapshots/images/features.home.impl.spaces_HomeSpacesView_Day_0_en.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:dff393d500d855842d84d311b3bb5cb60bab6fc2e8e9efe3b593d675218d5024
-size 123012
+oid sha256:fbdebc1c9361339dd0db1051e59162ed62fa2787c46457848da5ee6a30474588
+size 106570
diff --git a/tests/uitests/src/test/snapshots/images/features.home.impl.spaces_HomeSpacesView_Day_1_en.png b/tests/uitests/src/test/snapshots/images/features.home.impl.spaces_HomeSpacesView_Day_1_en.png
index a715ddb59f..60ab311cdc 100644
--- a/tests/uitests/src/test/snapshots/images/features.home.impl.spaces_HomeSpacesView_Day_1_en.png
+++ b/tests/uitests/src/test/snapshots/images/features.home.impl.spaces_HomeSpacesView_Day_1_en.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:04ec1bd0bd667d5319843f480f2b7ca4b1b4364db4fbe22d85c10d291891642a
-size 42696
+oid sha256:7a6d3be47ab7d9234657d4d088389c8aadb4d9e073d8c91f4f81dded1b6662a6
+size 42160
diff --git a/tests/uitests/src/test/snapshots/images/features.home.impl.spaces_HomeSpacesView_Night_0_en.png b/tests/uitests/src/test/snapshots/images/features.home.impl.spaces_HomeSpacesView_Night_0_en.png
index 6159775dd0..66babf5423 100644
--- a/tests/uitests/src/test/snapshots/images/features.home.impl.spaces_HomeSpacesView_Night_0_en.png
+++ b/tests/uitests/src/test/snapshots/images/features.home.impl.spaces_HomeSpacesView_Night_0_en.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:9993c1937c780b4b7e3a47bfb53fa5735ac7bc20f29559281384ca32eb7c13ae
-size 120701
+oid sha256:7bb7d1c08f5b2551117aa1aff8a3afbabd0f4100e0fae11cf415bd8e851c0307
+size 103835
diff --git a/tests/uitests/src/test/snapshots/images/features.home.impl.spaces_HomeSpacesView_Night_1_en.png b/tests/uitests/src/test/snapshots/images/features.home.impl.spaces_HomeSpacesView_Night_1_en.png
index b814fce01e..2b50f7350b 100644
--- a/tests/uitests/src/test/snapshots/images/features.home.impl.spaces_HomeSpacesView_Night_1_en.png
+++ b/tests/uitests/src/test/snapshots/images/features.home.impl.spaces_HomeSpacesView_Night_1_en.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:0d00883e68471491d8edf06eee394e4310707dbd03782f57bb7f783822790b61
-size 41372
+oid sha256:b3f70a15def31e67e84afe7f9545d280bdbca01c6dd63864662f19976df3bf33
+size 40960
diff --git a/tests/uitests/src/test/snapshots/images/features.invite.impl.acceptdecline_AcceptDeclineInviteView_Day_3_en.png b/tests/uitests/src/test/snapshots/images/features.invite.impl.acceptdecline_AcceptDeclineInviteView_Day_3_en.png
index 76ec1f565b..c4e9be12cc 100644
--- a/tests/uitests/src/test/snapshots/images/features.invite.impl.acceptdecline_AcceptDeclineInviteView_Day_3_en.png
+++ b/tests/uitests/src/test/snapshots/images/features.invite.impl.acceptdecline_AcceptDeclineInviteView_Day_3_en.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:24e40ff9b3ba80d0c00cd6b5a4e29b5b36f0e9ed92e4e6c123f49d88e661fe15
-size 18467
+oid sha256:44c81c89875c5159190cdb40c7d49849eabd8388d54db4bb1f6352b558e79ca0
+size 18626
diff --git a/tests/uitests/src/test/snapshots/images/features.invite.impl.acceptdecline_AcceptDeclineInviteView_Day_4_en.png b/tests/uitests/src/test/snapshots/images/features.invite.impl.acceptdecline_AcceptDeclineInviteView_Day_4_en.png
index f7cf9ecd24..5474393374 100644
--- a/tests/uitests/src/test/snapshots/images/features.invite.impl.acceptdecline_AcceptDeclineInviteView_Day_4_en.png
+++ b/tests/uitests/src/test/snapshots/images/features.invite.impl.acceptdecline_AcceptDeclineInviteView_Day_4_en.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:31fafcdd786b34313af790c5d9111e6f4787bc55587715357f7959b5554149bb
-size 19772
+oid sha256:ebf4e51dee36793583638d31128421caee4166e86dd7007a6342729c28e7058c
+size 19945
diff --git a/tests/uitests/src/test/snapshots/images/features.invite.impl.acceptdecline_AcceptDeclineInviteView_Day_5_en.png b/tests/uitests/src/test/snapshots/images/features.invite.impl.acceptdecline_AcceptDeclineInviteView_Day_5_en.png
index 76ec1f565b..c4e9be12cc 100644
--- a/tests/uitests/src/test/snapshots/images/features.invite.impl.acceptdecline_AcceptDeclineInviteView_Day_5_en.png
+++ b/tests/uitests/src/test/snapshots/images/features.invite.impl.acceptdecline_AcceptDeclineInviteView_Day_5_en.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:24e40ff9b3ba80d0c00cd6b5a4e29b5b36f0e9ed92e4e6c123f49d88e661fe15
-size 18467
+oid sha256:44c81c89875c5159190cdb40c7d49849eabd8388d54db4bb1f6352b558e79ca0
+size 18626
diff --git a/tests/uitests/src/test/snapshots/images/features.invite.impl.acceptdecline_AcceptDeclineInviteView_Night_3_en.png b/tests/uitests/src/test/snapshots/images/features.invite.impl.acceptdecline_AcceptDeclineInviteView_Night_3_en.png
index 5d7460384c..bab506a7de 100644
--- a/tests/uitests/src/test/snapshots/images/features.invite.impl.acceptdecline_AcceptDeclineInviteView_Night_3_en.png
+++ b/tests/uitests/src/test/snapshots/images/features.invite.impl.acceptdecline_AcceptDeclineInviteView_Night_3_en.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:7346cb947c370f125c23604c39c499a4300334e12d34a8777a9538a2eea2e72d
-size 17157
+oid sha256:5825ff69bffd527601323f52f2ba033cb7b9d754b5113d851dd68a0e5c09e45a
+size 17308
diff --git a/tests/uitests/src/test/snapshots/images/features.invite.impl.acceptdecline_AcceptDeclineInviteView_Night_4_en.png b/tests/uitests/src/test/snapshots/images/features.invite.impl.acceptdecline_AcceptDeclineInviteView_Night_4_en.png
index 698b15df00..d0fd29ba04 100644
--- a/tests/uitests/src/test/snapshots/images/features.invite.impl.acceptdecline_AcceptDeclineInviteView_Night_4_en.png
+++ b/tests/uitests/src/test/snapshots/images/features.invite.impl.acceptdecline_AcceptDeclineInviteView_Night_4_en.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:81070899b4d7fa3f0620e3d135d85c09746cefa80189ce9a9c8115311c6dd0e3
-size 18293
+oid sha256:06ce5a60d11da9217ba3f70f794df6d51e1c319052bc063f26466c9b9c31e838
+size 18448
diff --git a/tests/uitests/src/test/snapshots/images/features.invite.impl.acceptdecline_AcceptDeclineInviteView_Night_5_en.png b/tests/uitests/src/test/snapshots/images/features.invite.impl.acceptdecline_AcceptDeclineInviteView_Night_5_en.png
index 5d7460384c..bab506a7de 100644
--- a/tests/uitests/src/test/snapshots/images/features.invite.impl.acceptdecline_AcceptDeclineInviteView_Night_5_en.png
+++ b/tests/uitests/src/test/snapshots/images/features.invite.impl.acceptdecline_AcceptDeclineInviteView_Night_5_en.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:7346cb947c370f125c23604c39c499a4300334e12d34a8777a9538a2eea2e72d
-size 17157
+oid sha256:5825ff69bffd527601323f52f2ba033cb7b9d754b5113d851dd68a0e5c09e45a
+size 17308
diff --git a/tests/uitests/src/test/snapshots/images/features.invitepeople.impl_InvitePeopleView_Day_9_en.png b/tests/uitests/src/test/snapshots/images/features.invitepeople.impl_InvitePeopleView_Day_9_en.png
new file mode 100644
index 0000000000..1e3446160f
--- /dev/null
+++ b/tests/uitests/src/test/snapshots/images/features.invitepeople.impl_InvitePeopleView_Day_9_en.png
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:94341fe8aa52b4551ef8a73cf298aaa1c4352ae0d4c83990c04c4c6e491b64e8
+size 21444
diff --git a/tests/uitests/src/test/snapshots/images/features.invitepeople.impl_InvitePeopleView_Night_9_en.png b/tests/uitests/src/test/snapshots/images/features.invitepeople.impl_InvitePeopleView_Night_9_en.png
new file mode 100644
index 0000000000..2de946c312
--- /dev/null
+++ b/tests/uitests/src/test/snapshots/images/features.invitepeople.impl_InvitePeopleView_Night_9_en.png
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:00a961c76598dc98a0d9c7a45781865984c51bb440bb1605c381e9496ca1789f
+size 21971
diff --git a/tests/uitests/src/test/snapshots/images/features.joinroom.impl_JoinRoomView_Day_0_en.png b/tests/uitests/src/test/snapshots/images/features.joinroom.impl_JoinRoomView_Day_0_en.png
index 41c9460979..fc843bc4f5 100644
--- a/tests/uitests/src/test/snapshots/images/features.joinroom.impl_JoinRoomView_Day_0_en.png
+++ b/tests/uitests/src/test/snapshots/images/features.joinroom.impl_JoinRoomView_Day_0_en.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:7423c3f11ec8661d7fb3f57d7d78459e784221644229515080e0b0dc6ce59b6e
-size 10129
+oid sha256:8c88f9a3ecbcf7db13846a6074c75fca2ce6bdbe0edd850bfc139e01a4fdc0c8
+size 9956
diff --git a/tests/uitests/src/test/snapshots/images/features.joinroom.impl_JoinRoomView_Day_10_en.png b/tests/uitests/src/test/snapshots/images/features.joinroom.impl_JoinRoomView_Day_10_en.png
index bb3bc2a09c..4f172d6a06 100644
--- a/tests/uitests/src/test/snapshots/images/features.joinroom.impl_JoinRoomView_Day_10_en.png
+++ b/tests/uitests/src/test/snapshots/images/features.joinroom.impl_JoinRoomView_Day_10_en.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:08ed98b594a6730d52ab344aff6bea8a38216a609549be267f9046dd69858903
-size 38478
+oid sha256:7fdd74d6df903a0cedfbfc2f30430b5802e4f0bc7b2711e20ae47d297066b056
+size 40297
diff --git a/tests/uitests/src/test/snapshots/images/features.joinroom.impl_JoinRoomView_Day_11_en.png b/tests/uitests/src/test/snapshots/images/features.joinroom.impl_JoinRoomView_Day_11_en.png
index 97af44e438..ce1e584d59 100644
--- a/tests/uitests/src/test/snapshots/images/features.joinroom.impl_JoinRoomView_Day_11_en.png
+++ b/tests/uitests/src/test/snapshots/images/features.joinroom.impl_JoinRoomView_Day_11_en.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:bf0a1c9fea2a067d6156985cce2fd2a2551f6111e7739206f7bd70a563a97fcf
-size 45333
+oid sha256:ed26457abf2a6d89d61e911944b4e9f62de248c1939f997d0f8764e4c1ae08e9
+size 43088
diff --git a/tests/uitests/src/test/snapshots/images/features.joinroom.impl_JoinRoomView_Day_12_en.png b/tests/uitests/src/test/snapshots/images/features.joinroom.impl_JoinRoomView_Day_12_en.png
index 4176533a78..ad220df759 100644
--- a/tests/uitests/src/test/snapshots/images/features.joinroom.impl_JoinRoomView_Day_12_en.png
+++ b/tests/uitests/src/test/snapshots/images/features.joinroom.impl_JoinRoomView_Day_12_en.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:24d9f9b2a63773f5bc49b7f8f8b85d1dd13e8e62175b61bca534b04626d19b0f
-size 46336
+oid sha256:46b410cba77b24d8657031f5fde29d4f25a639300862641ce0f8ad0de8ff99cb
+size 44076
diff --git a/tests/uitests/src/test/snapshots/images/features.joinroom.impl_JoinRoomView_Day_13_en.png b/tests/uitests/src/test/snapshots/images/features.joinroom.impl_JoinRoomView_Day_13_en.png
index c737e362de..af3739d987 100644
--- a/tests/uitests/src/test/snapshots/images/features.joinroom.impl_JoinRoomView_Day_13_en.png
+++ b/tests/uitests/src/test/snapshots/images/features.joinroom.impl_JoinRoomView_Day_13_en.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:ca5217bba4fe65af4ac2a0aaaefa941a5a5ed0735dbd9bd69a648a157ca0c51b
-size 29343
+oid sha256:950e90b7c2c67fc95c9d6698dc7436885ee80dcf9da7d8467b0027c04c03c8f5
+size 29243
diff --git a/tests/uitests/src/test/snapshots/images/features.joinroom.impl_JoinRoomView_Day_14_en.png b/tests/uitests/src/test/snapshots/images/features.joinroom.impl_JoinRoomView_Day_14_en.png
index f3ad94a6a5..0834071308 100644
--- a/tests/uitests/src/test/snapshots/images/features.joinroom.impl_JoinRoomView_Day_14_en.png
+++ b/tests/uitests/src/test/snapshots/images/features.joinroom.impl_JoinRoomView_Day_14_en.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:41a3c9cbec371b6aacabcb954315a65939b579c5963db63fc11789326ad2fc1b
-size 29068
+oid sha256:37ac3a032e758c4abf9ac8a87e887c7e015f2d35160d59a7e263963300bd0941
+size 31558
diff --git a/tests/uitests/src/test/snapshots/images/features.joinroom.impl_JoinRoomView_Day_15_en.png b/tests/uitests/src/test/snapshots/images/features.joinroom.impl_JoinRoomView_Day_15_en.png
index 70d7d9d00e..330bd7edc7 100644
--- a/tests/uitests/src/test/snapshots/images/features.joinroom.impl_JoinRoomView_Day_15_en.png
+++ b/tests/uitests/src/test/snapshots/images/features.joinroom.impl_JoinRoomView_Day_15_en.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:0249fb4df9e88abaa28cc3a10e2cadc23b3b84581d74893d525076683f0a5588
-size 36386
+oid sha256:44b9c4608696c6a690e7f00f661b3cb55d03826b11569b6e8ce0a48f9754dd39
+size 38547
diff --git a/tests/uitests/src/test/snapshots/images/features.joinroom.impl_JoinRoomView_Day_16_en.png b/tests/uitests/src/test/snapshots/images/features.joinroom.impl_JoinRoomView_Day_16_en.png
index 52411087a2..e9ce885cd8 100644
--- a/tests/uitests/src/test/snapshots/images/features.joinroom.impl_JoinRoomView_Day_16_en.png
+++ b/tests/uitests/src/test/snapshots/images/features.joinroom.impl_JoinRoomView_Day_16_en.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:e1c6c00bca10e0bf725ab5debe3cd9dbb14be89f29872ca70df8f3886d1cec19
-size 40928
+oid sha256:f92065e3de67f39ce27ae3e321f59fa2d18b5927752dc760450ec275935b1959
+size 43405
diff --git a/tests/uitests/src/test/snapshots/images/features.joinroom.impl_JoinRoomView_Day_1_en.png b/tests/uitests/src/test/snapshots/images/features.joinroom.impl_JoinRoomView_Day_1_en.png
index 66639e1bc2..c127d5b02f 100644
--- a/tests/uitests/src/test/snapshots/images/features.joinroom.impl_JoinRoomView_Day_1_en.png
+++ b/tests/uitests/src/test/snapshots/images/features.joinroom.impl_JoinRoomView_Day_1_en.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:96ecb81ebfc7545eca7931538a443b7190b7903d8ebf5bf70bb95eb3b42e6a38
-size 30092
+oid sha256:919101bfd215af97a098bdfae4980445bd1d0560f96fe9ce13a870e2d8817fff
+size 34247
diff --git a/tests/uitests/src/test/snapshots/images/features.joinroom.impl_JoinRoomView_Day_2_en.png b/tests/uitests/src/test/snapshots/images/features.joinroom.impl_JoinRoomView_Day_2_en.png
index b28d9d527d..a902aef055 100644
--- a/tests/uitests/src/test/snapshots/images/features.joinroom.impl_JoinRoomView_Day_2_en.png
+++ b/tests/uitests/src/test/snapshots/images/features.joinroom.impl_JoinRoomView_Day_2_en.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:09e79f148754898125af4972bbfecfb1e3fc8f2de918ba9dd12d9766ef09e4f1
-size 31417
+oid sha256:2f9707b754041c871c408e12613faa186fa4f4f760ca793caf20c62bae07246b
+size 32021
diff --git a/tests/uitests/src/test/snapshots/images/features.joinroom.impl_JoinRoomView_Day_3_en.png b/tests/uitests/src/test/snapshots/images/features.joinroom.impl_JoinRoomView_Day_3_en.png
index 461aaa3497..16ac399dbf 100644
--- a/tests/uitests/src/test/snapshots/images/features.joinroom.impl_JoinRoomView_Day_3_en.png
+++ b/tests/uitests/src/test/snapshots/images/features.joinroom.impl_JoinRoomView_Day_3_en.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:6c87682ca77c0ee163e437dae9f177e52937c6099e1d3583f2138735fd5ecc8f
-size 26669
+oid sha256:5ad9105ca2659f51b16b41f9317812590f38adb8431a64a139bb47f54fdf9eff
+size 29754
diff --git a/tests/uitests/src/test/snapshots/images/features.joinroom.impl_JoinRoomView_Day_4_en.png b/tests/uitests/src/test/snapshots/images/features.joinroom.impl_JoinRoomView_Day_4_en.png
index 488b2ef5d5..78b8500823 100644
--- a/tests/uitests/src/test/snapshots/images/features.joinroom.impl_JoinRoomView_Day_4_en.png
+++ b/tests/uitests/src/test/snapshots/images/features.joinroom.impl_JoinRoomView_Day_4_en.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:8319fdce8ae47fd6dc7aea8f6c98e9e4de7322f0b9adc4262695ff3990a63052
-size 39520
+oid sha256:04180611d2a959d07bbbd051c4386f6428d841c5ea74e197a80149370db76e04
+size 41830
diff --git a/tests/uitests/src/test/snapshots/images/features.joinroom.impl_JoinRoomView_Day_5_en.png b/tests/uitests/src/test/snapshots/images/features.joinroom.impl_JoinRoomView_Day_5_en.png
index 64d8d932d7..644110ef6d 100644
--- a/tests/uitests/src/test/snapshots/images/features.joinroom.impl_JoinRoomView_Day_5_en.png
+++ b/tests/uitests/src/test/snapshots/images/features.joinroom.impl_JoinRoomView_Day_5_en.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:c444dbd6815dcb6362b3a595c9a052e81629c09f90cae08cb42f2053ee06d129
-size 27689
+oid sha256:7c4a828b9aa4e4963e3cb39e6f65f82ff5e595fdccb4dc5b48db532eeac1fb00
+size 31388
diff --git a/tests/uitests/src/test/snapshots/images/features.joinroom.impl_JoinRoomView_Day_6_en.png b/tests/uitests/src/test/snapshots/images/features.joinroom.impl_JoinRoomView_Day_6_en.png
index ce70cfc15f..c7d05de034 100644
--- a/tests/uitests/src/test/snapshots/images/features.joinroom.impl_JoinRoomView_Day_6_en.png
+++ b/tests/uitests/src/test/snapshots/images/features.joinroom.impl_JoinRoomView_Day_6_en.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:484657673c4ae676b330320ba213485a16c6f31ea025b16b4f2c3a53053eaf7a
-size 29860
+oid sha256:bdc24799de625f9826fcf87a624e76b530e7f0e44c294d49f842ed2de7a9c085
+size 32981
diff --git a/tests/uitests/src/test/snapshots/images/features.joinroom.impl_JoinRoomView_Day_7_en.png b/tests/uitests/src/test/snapshots/images/features.joinroom.impl_JoinRoomView_Day_7_en.png
index 1484121044..3d78e94953 100644
--- a/tests/uitests/src/test/snapshots/images/features.joinroom.impl_JoinRoomView_Day_7_en.png
+++ b/tests/uitests/src/test/snapshots/images/features.joinroom.impl_JoinRoomView_Day_7_en.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:a239f4f8003693097fee6e9dddc31ed1ce7a53f7c2b9dab9db55059ca51df64f
-size 37645
+oid sha256:247a1cec9f0729ef1b23dc5ad730521bb7bfc117b4e9cc901ec922ee946f942e
+size 39401
diff --git a/tests/uitests/src/test/snapshots/images/features.joinroom.impl_JoinRoomView_Day_8_en.png b/tests/uitests/src/test/snapshots/images/features.joinroom.impl_JoinRoomView_Day_8_en.png
index 979b3141be..c6f8b658a3 100644
--- a/tests/uitests/src/test/snapshots/images/features.joinroom.impl_JoinRoomView_Day_8_en.png
+++ b/tests/uitests/src/test/snapshots/images/features.joinroom.impl_JoinRoomView_Day_8_en.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:8e23c1347af06b2fa6f1982159cdb92b2bed278ab1b4caf782c3916520681d75
-size 26616
+oid sha256:bcc00accf1fa84c48831378faa27558d5ba24961dd3ba0c5f0587329cdbaa9bf
+size 29110
diff --git a/tests/uitests/src/test/snapshots/images/features.joinroom.impl_JoinRoomView_Day_9_en.png b/tests/uitests/src/test/snapshots/images/features.joinroom.impl_JoinRoomView_Day_9_en.png
index 74638ec5ac..cc08744b50 100644
--- a/tests/uitests/src/test/snapshots/images/features.joinroom.impl_JoinRoomView_Day_9_en.png
+++ b/tests/uitests/src/test/snapshots/images/features.joinroom.impl_JoinRoomView_Day_9_en.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:657dfa3cd260803b3386ae6c3d44f6cc4277c2ef2572680145c419dfd9690e7a
-size 33276
+oid sha256:da07e3041ec5814feb0d14e8478d0c817d1496155db2daa612048b94530df20b
+size 38200
diff --git a/tests/uitests/src/test/snapshots/images/features.joinroom.impl_JoinRoomView_Night_0_en.png b/tests/uitests/src/test/snapshots/images/features.joinroom.impl_JoinRoomView_Night_0_en.png
index 37396ce4d7..636b7ba0e6 100644
--- a/tests/uitests/src/test/snapshots/images/features.joinroom.impl_JoinRoomView_Night_0_en.png
+++ b/tests/uitests/src/test/snapshots/images/features.joinroom.impl_JoinRoomView_Night_0_en.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:58776319728d3367a347d62cf120803582b05c564f9cd76b2c8f406e70673821
-size 9949
+oid sha256:c91724171606aa0c36987908af0abce5c05b3311469a08e532532307d1224c60
+size 9842
diff --git a/tests/uitests/src/test/snapshots/images/features.joinroom.impl_JoinRoomView_Night_10_en.png b/tests/uitests/src/test/snapshots/images/features.joinroom.impl_JoinRoomView_Night_10_en.png
index 7d9743ada7..edc2a732b6 100644
--- a/tests/uitests/src/test/snapshots/images/features.joinroom.impl_JoinRoomView_Night_10_en.png
+++ b/tests/uitests/src/test/snapshots/images/features.joinroom.impl_JoinRoomView_Night_10_en.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:4ae699d09bc1287d12d9974a6801f6b1648f0d6bd63eb9ac10302be37cae5383
-size 38181
+oid sha256:f5a6da57cc5659ba3f3705cba41fd23c7628ba2477fcfc427b8e26bde37ed812
+size 39960
diff --git a/tests/uitests/src/test/snapshots/images/features.joinroom.impl_JoinRoomView_Night_11_en.png b/tests/uitests/src/test/snapshots/images/features.joinroom.impl_JoinRoomView_Night_11_en.png
index 6cdda44336..5f8961f485 100644
--- a/tests/uitests/src/test/snapshots/images/features.joinroom.impl_JoinRoomView_Night_11_en.png
+++ b/tests/uitests/src/test/snapshots/images/features.joinroom.impl_JoinRoomView_Night_11_en.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:511985d79fe13467eec62772dbe6cc69dec1f1c9f9a3e66428fe9b22ce279d1f
-size 44937
+oid sha256:5b9cf46f0039e0f91e8372cd5f9a15b7b54b75c80e0a38f9ebc2548315d57c9f
+size 42657
diff --git a/tests/uitests/src/test/snapshots/images/features.joinroom.impl_JoinRoomView_Night_12_en.png b/tests/uitests/src/test/snapshots/images/features.joinroom.impl_JoinRoomView_Night_12_en.png
index a1fd91d0a7..c25392b215 100644
--- a/tests/uitests/src/test/snapshots/images/features.joinroom.impl_JoinRoomView_Night_12_en.png
+++ b/tests/uitests/src/test/snapshots/images/features.joinroom.impl_JoinRoomView_Night_12_en.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:a084ed7657a2f263283a477e700df9fb6219e8268380f764c2e5e4055465044d
-size 45898
+oid sha256:5a4f65342c0e84179aceadc5d75fc763ed45c23f4db44bc16441c50990b193ed
+size 43582
diff --git a/tests/uitests/src/test/snapshots/images/features.joinroom.impl_JoinRoomView_Night_13_en.png b/tests/uitests/src/test/snapshots/images/features.joinroom.impl_JoinRoomView_Night_13_en.png
index f2c3b773b4..9c134bf310 100644
--- a/tests/uitests/src/test/snapshots/images/features.joinroom.impl_JoinRoomView_Night_13_en.png
+++ b/tests/uitests/src/test/snapshots/images/features.joinroom.impl_JoinRoomView_Night_13_en.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:51680be3eede0c4a53683b298415a07f3e9ea688ac39fe29373e1e80b0f4540b
-size 28778
+oid sha256:e2ef8069be91c6e20263da790c0b8b777515f46bdc4769532b321ae86c9152b8
+size 28701
diff --git a/tests/uitests/src/test/snapshots/images/features.joinroom.impl_JoinRoomView_Night_14_en.png b/tests/uitests/src/test/snapshots/images/features.joinroom.impl_JoinRoomView_Night_14_en.png
index 485ba35c62..867ef2ea72 100644
--- a/tests/uitests/src/test/snapshots/images/features.joinroom.impl_JoinRoomView_Night_14_en.png
+++ b/tests/uitests/src/test/snapshots/images/features.joinroom.impl_JoinRoomView_Night_14_en.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:7172438656b08d5c244fc570fd25dc074562b7599f15eda8241ddb7c9b275fcd
-size 28765
+oid sha256:5f47c18fda5c4839e1098955f57c4a3e5b9856203c6a84c31903aa5e0b2da46b
+size 30971
diff --git a/tests/uitests/src/test/snapshots/images/features.joinroom.impl_JoinRoomView_Night_15_en.png b/tests/uitests/src/test/snapshots/images/features.joinroom.impl_JoinRoomView_Night_15_en.png
index 4ab802917f..40257d2267 100644
--- a/tests/uitests/src/test/snapshots/images/features.joinroom.impl_JoinRoomView_Night_15_en.png
+++ b/tests/uitests/src/test/snapshots/images/features.joinroom.impl_JoinRoomView_Night_15_en.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:9aaf1721d3b8c3a000402eb605b7ba742560fae7297514a15f74fd97c2f838a1
-size 35406
+oid sha256:112286f6a18865db2333a68cb804e930eb873bb04596bada2f825e2223b4f537
+size 37362
diff --git a/tests/uitests/src/test/snapshots/images/features.joinroom.impl_JoinRoomView_Night_16_en.png b/tests/uitests/src/test/snapshots/images/features.joinroom.impl_JoinRoomView_Night_16_en.png
index 40682697ef..abc81a0d58 100644
--- a/tests/uitests/src/test/snapshots/images/features.joinroom.impl_JoinRoomView_Night_16_en.png
+++ b/tests/uitests/src/test/snapshots/images/features.joinroom.impl_JoinRoomView_Night_16_en.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:b7b113b174727ce08ed2b23f320d49b556e869249302c0b84c1b5916ae8864ac
-size 40563
+oid sha256:ff86f906357d0bf611bfc9cd235e66e0247dd7bb66903cb0e5730224d5dc897c
+size 43008
diff --git a/tests/uitests/src/test/snapshots/images/features.joinroom.impl_JoinRoomView_Night_1_en.png b/tests/uitests/src/test/snapshots/images/features.joinroom.impl_JoinRoomView_Night_1_en.png
index 251f240e62..b480466344 100644
--- a/tests/uitests/src/test/snapshots/images/features.joinroom.impl_JoinRoomView_Night_1_en.png
+++ b/tests/uitests/src/test/snapshots/images/features.joinroom.impl_JoinRoomView_Night_1_en.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:444f717f986b154297294df6ba731befc3e2049f89a3294e26fd6d90f0831996
-size 29353
+oid sha256:cc849f3158de5cd3cdc64a57e613f3b3a5cd70794e7984d7cfa1f8f425184592
+size 33440
diff --git a/tests/uitests/src/test/snapshots/images/features.joinroom.impl_JoinRoomView_Night_2_en.png b/tests/uitests/src/test/snapshots/images/features.joinroom.impl_JoinRoomView_Night_2_en.png
index 2126595abd..9869f158e6 100644
--- a/tests/uitests/src/test/snapshots/images/features.joinroom.impl_JoinRoomView_Night_2_en.png
+++ b/tests/uitests/src/test/snapshots/images/features.joinroom.impl_JoinRoomView_Night_2_en.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:f9bd6d13f3c4f7a715e9e8698db252bc33823fe180e6d279eabcc9de618dcaee
-size 31182
+oid sha256:ed211c9bc258185de6ea4cc414fd214f256ad1649c26a8a28f25fd1b29c34783
+size 31630
diff --git a/tests/uitests/src/test/snapshots/images/features.joinroom.impl_JoinRoomView_Night_3_en.png b/tests/uitests/src/test/snapshots/images/features.joinroom.impl_JoinRoomView_Night_3_en.png
index be61677a61..42619d6321 100644
--- a/tests/uitests/src/test/snapshots/images/features.joinroom.impl_JoinRoomView_Night_3_en.png
+++ b/tests/uitests/src/test/snapshots/images/features.joinroom.impl_JoinRoomView_Night_3_en.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:acdd2cd73f2a37190bbbeb829af68a28dae8d73f5462396db4c6238ee8319351
-size 26733
+oid sha256:6a88ffdfd4259a2e85b3a8375591eab3b0f12e927eb83f9c6820995acf44d79e
+size 29607
diff --git a/tests/uitests/src/test/snapshots/images/features.joinroom.impl_JoinRoomView_Night_4_en.png b/tests/uitests/src/test/snapshots/images/features.joinroom.impl_JoinRoomView_Night_4_en.png
index c484f2aeff..1b95755ca6 100644
--- a/tests/uitests/src/test/snapshots/images/features.joinroom.impl_JoinRoomView_Night_4_en.png
+++ b/tests/uitests/src/test/snapshots/images/features.joinroom.impl_JoinRoomView_Night_4_en.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:731f81d6ca0d4677dc56b58316c7396a7ad1ee08c785aecbb9eea4a0dea6b77a
-size 38428
+oid sha256:7fbe20a3d4e0c3706ce81c1f52c65ff4f749b0afd6bdd3efb4100ee1019afc51
+size 40580
diff --git a/tests/uitests/src/test/snapshots/images/features.joinroom.impl_JoinRoomView_Night_5_en.png b/tests/uitests/src/test/snapshots/images/features.joinroom.impl_JoinRoomView_Night_5_en.png
index 7c8b6e4d8a..0211928122 100644
--- a/tests/uitests/src/test/snapshots/images/features.joinroom.impl_JoinRoomView_Night_5_en.png
+++ b/tests/uitests/src/test/snapshots/images/features.joinroom.impl_JoinRoomView_Night_5_en.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:4889f91529fddf07ddccb9d1b31f4af4278245d9916694d2197798318fb9469b
-size 26163
+oid sha256:cff1f0a8a34cfd4eb55487540a02c70e629d7f6123355c95380498817053eb78
+size 29575
diff --git a/tests/uitests/src/test/snapshots/images/features.joinroom.impl_JoinRoomView_Night_6_en.png b/tests/uitests/src/test/snapshots/images/features.joinroom.impl_JoinRoomView_Night_6_en.png
index 76d730668b..f599f084b6 100644
--- a/tests/uitests/src/test/snapshots/images/features.joinroom.impl_JoinRoomView_Night_6_en.png
+++ b/tests/uitests/src/test/snapshots/images/features.joinroom.impl_JoinRoomView_Night_6_en.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:e0d60be4104d5f124e49e8a7434204bd0593b46fca838e787aefa40769ac1778
-size 29202
+oid sha256:71e56b906decbea31fcf5581dc92dcbb6be79f6a6962595786e9533cc62254ad
+size 32045
diff --git a/tests/uitests/src/test/snapshots/images/features.joinroom.impl_JoinRoomView_Night_7_en.png b/tests/uitests/src/test/snapshots/images/features.joinroom.impl_JoinRoomView_Night_7_en.png
index 799003fe8e..4f8d2856a4 100644
--- a/tests/uitests/src/test/snapshots/images/features.joinroom.impl_JoinRoomView_Night_7_en.png
+++ b/tests/uitests/src/test/snapshots/images/features.joinroom.impl_JoinRoomView_Night_7_en.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:7129f65572d7b4f6b302fa803f878b269f2ee7b11a684c3e1ec051f9192fc8fa
-size 36927
+oid sha256:18e36242d664e1f2179bb3aef3f77a5bbbf5cd44aece2d2c9a3d7d70d2356b92
+size 38769
diff --git a/tests/uitests/src/test/snapshots/images/features.joinroom.impl_JoinRoomView_Night_8_en.png b/tests/uitests/src/test/snapshots/images/features.joinroom.impl_JoinRoomView_Night_8_en.png
index 7c9d79d83e..b595df5d84 100644
--- a/tests/uitests/src/test/snapshots/images/features.joinroom.impl_JoinRoomView_Night_8_en.png
+++ b/tests/uitests/src/test/snapshots/images/features.joinroom.impl_JoinRoomView_Night_8_en.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:809913705eb237bdd8575a92be89cf616d27c7d54a32894378f693dbf1969d0a
-size 24731
+oid sha256:37270eed539ed52a113375dbfa516f443838530ef7995bb6372764afbc25e75d
+size 26787
diff --git a/tests/uitests/src/test/snapshots/images/features.joinroom.impl_JoinRoomView_Night_9_en.png b/tests/uitests/src/test/snapshots/images/features.joinroom.impl_JoinRoomView_Night_9_en.png
index 5098ca7b17..8af0e7e350 100644
--- a/tests/uitests/src/test/snapshots/images/features.joinroom.impl_JoinRoomView_Night_9_en.png
+++ b/tests/uitests/src/test/snapshots/images/features.joinroom.impl_JoinRoomView_Night_9_en.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:8c862dd75be71248752d53cc605860c55fe4eecce75eba545ab4471a13585296
-size 32951
+oid sha256:0b73e8a2429db6324f471908f46ccd2f6723d59caf4acc738c07d6e402a19285
+size 37752
diff --git a/tests/uitests/src/test/snapshots/images/features.knockrequests.impl.list_KnockRequestsListView_Day_5_en.png b/tests/uitests/src/test/snapshots/images/features.knockrequests.impl.list_KnockRequestsListView_Day_5_en.png
index aa391725b3..22f56c4da8 100644
--- a/tests/uitests/src/test/snapshots/images/features.knockrequests.impl.list_KnockRequestsListView_Day_5_en.png
+++ b/tests/uitests/src/test/snapshots/images/features.knockrequests.impl.list_KnockRequestsListView_Day_5_en.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:8c06f9cadc81daeee0925d8684ad70f7f1bf2dac56c30dd4067c223683e5cbde
-size 45382
+oid sha256:c6e13b1e5c43efab5cc40daa0118566aea330552075e5409564c496b86db4564
+size 45402
diff --git a/tests/uitests/src/test/snapshots/images/features.knockrequests.impl.list_KnockRequestsListView_Night_5_en.png b/tests/uitests/src/test/snapshots/images/features.knockrequests.impl.list_KnockRequestsListView_Night_5_en.png
index b7b132a64c..4312dcda4b 100644
--- a/tests/uitests/src/test/snapshots/images/features.knockrequests.impl.list_KnockRequestsListView_Night_5_en.png
+++ b/tests/uitests/src/test/snapshots/images/features.knockrequests.impl.list_KnockRequestsListView_Night_5_en.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:0b4f3e43f6f01dcf53f27aca683733015781a1b46b9f2db2fa8f3500f5ce802c
-size 43246
+oid sha256:d4ae8ce188cf5d380117fef6f98c73285486970267db88b0823409e75fdf1c1b
+size 43250
diff --git a/tests/uitests/src/test/snapshots/images/features.leaveroom.impl_LeaveRoomView_Day_5_en.png b/tests/uitests/src/test/snapshots/images/features.leaveroom.impl_LeaveRoomView_Day_5_en.png
index aa695c8d55..c0d747d0ad 100644
--- a/tests/uitests/src/test/snapshots/images/features.leaveroom.impl_LeaveRoomView_Day_5_en.png
+++ b/tests/uitests/src/test/snapshots/images/features.leaveroom.impl_LeaveRoomView_Day_5_en.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:e409ac134f70890d14c31fe0939eb73f1aa010915981b344d9466e9c2450b94b
-size 31954
+oid sha256:3f5e1530d78162b77a2d8c79142887f28677aba2acaef31c684231202974b3ad
+size 31890
diff --git a/tests/uitests/src/test/snapshots/images/features.leaveroom.impl_LeaveRoomView_Day_7_en.png b/tests/uitests/src/test/snapshots/images/features.leaveroom.impl_LeaveRoomView_Day_7_en.png
index 5a1e48d6a2..f5483d0828 100644
--- a/tests/uitests/src/test/snapshots/images/features.leaveroom.impl_LeaveRoomView_Day_7_en.png
+++ b/tests/uitests/src/test/snapshots/images/features.leaveroom.impl_LeaveRoomView_Day_7_en.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:7a6a89b15219084b3daeec9cbac6304ece498156ead77a003d8043a85660bf2a
-size 19286
+oid sha256:ea9f384fe887976aafe2c3f37f077bce21d2234408992a5ea9865594e405a8b8
+size 19451
diff --git a/tests/uitests/src/test/snapshots/images/features.leaveroom.impl_LeaveRoomView_Night_5_en.png b/tests/uitests/src/test/snapshots/images/features.leaveroom.impl_LeaveRoomView_Night_5_en.png
index e843f51690..ac82f69973 100644
--- a/tests/uitests/src/test/snapshots/images/features.leaveroom.impl_LeaveRoomView_Night_5_en.png
+++ b/tests/uitests/src/test/snapshots/images/features.leaveroom.impl_LeaveRoomView_Night_5_en.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:a416901c2228c2aee4f8a925bdb87a64dc36ed7727e8897c04205cc4d4147840
-size 30096
+oid sha256:2ec0da2e0489ae016f1cde361aa556ea7b74de12dfa41134fb8306521dd6d14a
+size 30137
diff --git a/tests/uitests/src/test/snapshots/images/features.leaveroom.impl_LeaveRoomView_Night_7_en.png b/tests/uitests/src/test/snapshots/images/features.leaveroom.impl_LeaveRoomView_Night_7_en.png
index 27afcc195a..a90b8327e5 100644
--- a/tests/uitests/src/test/snapshots/images/features.leaveroom.impl_LeaveRoomView_Night_7_en.png
+++ b/tests/uitests/src/test/snapshots/images/features.leaveroom.impl_LeaveRoomView_Night_7_en.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:b5e028a3770cf87ebdd9d44c012bbad6c409b7edfaccf5607ab5d7a6e6c3194c
-size 17713
+oid sha256:40737bdbc9d264e7e1ea43c7c79463f88de844f518f45e0e4c856d78a0e9d6c7
+size 17868
diff --git a/tests/uitests/src/test/snapshots/images/features.lockscreen.impl.settings_LockScreenSettingsView_Day_2_en.png b/tests/uitests/src/test/snapshots/images/features.lockscreen.impl.settings_LockScreenSettingsView_Day_2_en.png
index 3cc5e9735e..defcb90471 100644
--- a/tests/uitests/src/test/snapshots/images/features.lockscreen.impl.settings_LockScreenSettingsView_Day_2_en.png
+++ b/tests/uitests/src/test/snapshots/images/features.lockscreen.impl.settings_LockScreenSettingsView_Day_2_en.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:a3d870d023b29f46e356184fc45a2dc6010a088b1b32a690d0d98b43c7bd3eb2
-size 28845
+oid sha256:aa15f390927a533cdff4d42751e19942b0386473301cdb8cd800b37428ca2179
+size 28851
diff --git a/tests/uitests/src/test/snapshots/images/features.lockscreen.impl.settings_LockScreenSettingsView_Night_2_en.png b/tests/uitests/src/test/snapshots/images/features.lockscreen.impl.settings_LockScreenSettingsView_Night_2_en.png
index ddae20fe60..c2dbf39b83 100644
--- a/tests/uitests/src/test/snapshots/images/features.lockscreen.impl.settings_LockScreenSettingsView_Night_2_en.png
+++ b/tests/uitests/src/test/snapshots/images/features.lockscreen.impl.settings_LockScreenSettingsView_Night_2_en.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:4e636767998635b6abb3dbe29af0d42346c7b249125865f5b5a559abffb28ce5
-size 26963
+oid sha256:91251a1871095a734f70d335b3f514d266a5486b1fc57cbd130214f268525f1f
+size 26957
diff --git a/tests/uitests/src/test/snapshots/images/features.lockscreen.impl.setup.pin_SetupPinView_Day_3_en.png b/tests/uitests/src/test/snapshots/images/features.lockscreen.impl.setup.pin_SetupPinView_Day_3_en.png
index 035cebd446..085c34f992 100644
--- a/tests/uitests/src/test/snapshots/images/features.lockscreen.impl.setup.pin_SetupPinView_Day_3_en.png
+++ b/tests/uitests/src/test/snapshots/images/features.lockscreen.impl.setup.pin_SetupPinView_Day_3_en.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:ed0200ed72e0d5551e28c90eea2ea3cef40cbcd5fc738839700d42373322ac4b
-size 25139
+oid sha256:dbf3b090b0e3b4a00f5ddd86b7b2a62baa62e9cb6d1c24c36191620124dd6d12
+size 25210
diff --git a/tests/uitests/src/test/snapshots/images/features.lockscreen.impl.setup.pin_SetupPinView_Day_4_en.png b/tests/uitests/src/test/snapshots/images/features.lockscreen.impl.setup.pin_SetupPinView_Day_4_en.png
index d66517b825..a50a3c140a 100644
--- a/tests/uitests/src/test/snapshots/images/features.lockscreen.impl.setup.pin_SetupPinView_Day_4_en.png
+++ b/tests/uitests/src/test/snapshots/images/features.lockscreen.impl.setup.pin_SetupPinView_Day_4_en.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:6411ff6829376d545081c2b66db42e7ce8bafbf72d2809d884f81a56864e0aab
-size 29732
+oid sha256:53187c4901a528f5ea59fff3def64197eb0664ebffe85f48635c5cf1720c977a
+size 29700
diff --git a/tests/uitests/src/test/snapshots/images/features.lockscreen.impl.setup.pin_SetupPinView_Night_3_en.png b/tests/uitests/src/test/snapshots/images/features.lockscreen.impl.setup.pin_SetupPinView_Night_3_en.png
index 7b92e39b10..78f23cecd5 100644
--- a/tests/uitests/src/test/snapshots/images/features.lockscreen.impl.setup.pin_SetupPinView_Night_3_en.png
+++ b/tests/uitests/src/test/snapshots/images/features.lockscreen.impl.setup.pin_SetupPinView_Night_3_en.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:8f5fb7a9c99700b05fe90af1ae17428202e4a2d4c0e5c1f246825160e3a42b15
-size 23148
+oid sha256:5a430db03a543cf4517f9086e3bdf43cae72ac544f5fa1b5994bf62aa3151463
+size 23228
diff --git a/tests/uitests/src/test/snapshots/images/features.lockscreen.impl.setup.pin_SetupPinView_Night_4_en.png b/tests/uitests/src/test/snapshots/images/features.lockscreen.impl.setup.pin_SetupPinView_Night_4_en.png
index 727473d6a6..ca9ce8c967 100644
--- a/tests/uitests/src/test/snapshots/images/features.lockscreen.impl.setup.pin_SetupPinView_Night_4_en.png
+++ b/tests/uitests/src/test/snapshots/images/features.lockscreen.impl.setup.pin_SetupPinView_Night_4_en.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:6e90c76587699c68a30a788ed8fdacfa7a53f49e7bfeea0c7a2809d5b4b5e662
-size 27622
+oid sha256:0870a37c29bd5b62b559e47c0eb2dfd7ae94ed38efd62d3fa91eb0d646923373
+size 27565
diff --git a/tests/uitests/src/test/snapshots/images/features.login.impl.changeserver_ChangeServerView_Day_4_en.png b/tests/uitests/src/test/snapshots/images/features.login.impl.changeserver_ChangeServerView_Day_4_en.png
index dcfebea1ec..4b0e30affb 100644
--- a/tests/uitests/src/test/snapshots/images/features.login.impl.changeserver_ChangeServerView_Day_4_en.png
+++ b/tests/uitests/src/test/snapshots/images/features.login.impl.changeserver_ChangeServerView_Day_4_en.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:41280716b1e864b904e073171ab0f3aaec6fdc8917481259924db581196fd1ed
-size 26115
+oid sha256:50002e3a2f804fd2be0953fdb751ca73582a542346e0b854e256264e4f3ab77f
+size 26047
diff --git a/tests/uitests/src/test/snapshots/images/features.login.impl.changeserver_ChangeServerView_Night_4_en.png b/tests/uitests/src/test/snapshots/images/features.login.impl.changeserver_ChangeServerView_Night_4_en.png
index 8984aa75d5..a0af69b135 100644
--- a/tests/uitests/src/test/snapshots/images/features.login.impl.changeserver_ChangeServerView_Night_4_en.png
+++ b/tests/uitests/src/test/snapshots/images/features.login.impl.changeserver_ChangeServerView_Night_4_en.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:d52037a99c6094a488c3fe097a83a01b9de75c43ac3ead61f0c1e451783bbcf7
-size 24912
+oid sha256:48469fbca8f0b6c4c1fae05db27c1117ce6284bd6167a5f27dc06dd7d3c02a19
+size 24862
diff --git a/tests/uitests/src/test/snapshots/images/features.login.impl.login_LoginModeView_Day_2_en.png b/tests/uitests/src/test/snapshots/images/features.login.impl.login_LoginModeView_Day_2_en.png
index 8f1e86273e..e448af41a9 100644
--- a/tests/uitests/src/test/snapshots/images/features.login.impl.login_LoginModeView_Day_2_en.png
+++ b/tests/uitests/src/test/snapshots/images/features.login.impl.login_LoginModeView_Day_2_en.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:65bffac39daeea85b38ef1379cb3ec35bbe5bf0a230dd5b66f342a58c12d6e0a
-size 25701
+oid sha256:bc0fb8588ecf00b34d52da98594ee1aa841eef98cf5825fbea535e1fa871a2ef
+size 25646
diff --git a/tests/uitests/src/test/snapshots/images/features.login.impl.login_LoginModeView_Night_2_en.png b/tests/uitests/src/test/snapshots/images/features.login.impl.login_LoginModeView_Night_2_en.png
index 0a32ebc655..4aa9046ed9 100644
--- a/tests/uitests/src/test/snapshots/images/features.login.impl.login_LoginModeView_Night_2_en.png
+++ b/tests/uitests/src/test/snapshots/images/features.login.impl.login_LoginModeView_Night_2_en.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:20263696842e1790bae3bcbceb6268f9d960de48e1a32b2459ab5abeaf5d20d6
-size 24506
+oid sha256:0c60a197c679eda6323efacad6a33acc6f0175ebd0af7928609313c2189d6b9a
+size 24455
diff --git a/tests/uitests/src/test/snapshots/images/features.logout.impl_AccountDeactivationView_Day_2_en.png b/tests/uitests/src/test/snapshots/images/features.logout.impl_AccountDeactivationView_Day_2_en.png
index 8dfb060ca6..0314ca1c8f 100644
--- a/tests/uitests/src/test/snapshots/images/features.logout.impl_AccountDeactivationView_Day_2_en.png
+++ b/tests/uitests/src/test/snapshots/images/features.logout.impl_AccountDeactivationView_Day_2_en.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:e2ecb0a9f48a2c43c700dab7b21497d5bebdb63ad87a63d15525f596374b6748
-size 61650
+oid sha256:d81131943b6ff08a8c52827e956a9cf8d830b8523c192e645b116733aff2f8e5
+size 61663
diff --git a/tests/uitests/src/test/snapshots/images/features.logout.impl_AccountDeactivationView_Night_2_en.png b/tests/uitests/src/test/snapshots/images/features.logout.impl_AccountDeactivationView_Night_2_en.png
index ba552634c9..7b590a03ac 100644
--- a/tests/uitests/src/test/snapshots/images/features.logout.impl_AccountDeactivationView_Night_2_en.png
+++ b/tests/uitests/src/test/snapshots/images/features.logout.impl_AccountDeactivationView_Night_2_en.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:cbb1c1dc96055d4fe6aa792363abc00fb72bd8af758b9e8597f45725a983111d
-size 57951
+oid sha256:5204b189cf02f8f0145427df1c412e597cea106bcb87ac259b28e41ba55f2f0c
+size 58053
diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.attachments.preview_AttachmentsView_6_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.attachments.preview_AttachmentsView_6_en.png
index 8cb89ad06b..41a7341afa 100644
--- a/tests/uitests/src/test/snapshots/images/features.messages.impl.attachments.preview_AttachmentsView_6_en.png
+++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.attachments.preview_AttachmentsView_6_en.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:9368b86a0b2c5f73e97837019327e2f3c7898ded80de259a7c03e58f2ccf2b64
-size 72852
+oid sha256:a4214287ce64b1083c0be5227fd6e16066f3932c48ce7a8953d47999a5924fbf
+size 72848
diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.pinned.list_PinnedMessagesListView_Day_0_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.pinned.list_PinnedMessagesListView_Day_0_en.png
index 8d0c6973de..345ce9fe34 100644
--- a/tests/uitests/src/test/snapshots/images/features.messages.impl.pinned.list_PinnedMessagesListView_Day_0_en.png
+++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.pinned.list_PinnedMessagesListView_Day_0_en.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:b4559bcfab614255a51b2f73869d5ffc91fbc9fa53ef61c2ae02bd28c88bd838
-size 20773
+oid sha256:1d194ea0d68d15d8950277eb747047b7ac3c809eecfc12877296b7eb67d67b02
+size 20707
diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.pinned.list_PinnedMessagesListView_Night_0_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.pinned.list_PinnedMessagesListView_Night_0_en.png
index 760ee954e9..25a06027ed 100644
--- a/tests/uitests/src/test/snapshots/images/features.messages.impl.pinned.list_PinnedMessagesListView_Night_0_en.png
+++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.pinned.list_PinnedMessagesListView_Night_0_en.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:29c5b7ad11fdc97564ce4be236f3b89785029ed65d75be23ba97f5267438739d
-size 18932
+oid sha256:4dc9805c2f2d910491da944f1cf91430bcc5a8a91137eaaf301f65955d0d350e
+size 18798
diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_ThreadSummaryView_Day_0_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_ThreadSummaryView_Day_0_en.png
new file mode 100644
index 0000000000..32733b09b6
--- /dev/null
+++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_ThreadSummaryView_Day_0_en.png
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:2cb3989055cf63e3ee14d8e2d8b2cdcd67b3af1addae78b38ab13ddcf93a232d
+size 9740
diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_ThreadSummaryView_Night_0_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_ThreadSummaryView_Night_0_en.png
new file mode 100644
index 0000000000..9b9901528b
--- /dev/null
+++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_ThreadSummaryView_Night_0_en.png
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:8e206a2485736baa2ac8c6dae6847ef381bfa1f36a5b7bda14a7f93a55069f41
+size 9666
diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowWithThreadSummary_Day_0_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowWithThreadSummary_Day_0_en.png
index 4f8761e4dd..5695ab7dc3 100644
--- a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowWithThreadSummary_Day_0_en.png
+++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowWithThreadSummary_Day_0_en.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:ddaa247eea635d7e8c079ae128983fd25c1aeba96a48b08ae71218ef52e88d5b
-size 69475
+oid sha256:b51cd7375e0d9be97786632eb1dfc16b5023784ed0de616f029d782ca56aa07b
+size 68221
diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowWithThreadSummary_Night_0_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowWithThreadSummary_Night_0_en.png
index f17dbbe01e..a9b8b7cfc5 100644
--- a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowWithThreadSummary_Night_0_en.png
+++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowWithThreadSummary_Night_0_en.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:647365688fd0c542d4be6dae570b33fbb7bab6261dc57791db85966808d440bb
-size 67563
+oid sha256:1cb184afd2b1afff7b2f5f24f555e8278e20bbc98fe8b67a25a005771c7105b0
+size 66908
diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.topbars_MessagesViewTopBar_Day_0_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.topbars_MessagesViewTopBar_Day_0_en.png
new file mode 100644
index 0000000000..571661e434
--- /dev/null
+++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.topbars_MessagesViewTopBar_Day_0_en.png
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:065466dc414d77a58f2d22c26fc9d5e9b7afe5d5206cdbcc2bbdc6e8ea192d15
+size 40479
diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.topbars_MessagesViewTopBar_Night_0_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.topbars_MessagesViewTopBar_Night_0_en.png
new file mode 100644
index 0000000000..958d12766d
--- /dev/null
+++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.topbars_MessagesViewTopBar_Night_0_en.png
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:3c34b8c47d89231b8e5660726d63b94e3e8b97a2fc7e0b615f8f9e2d61066470
+size 39172
diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.topbars_ThreadTopBar_Day_0_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.topbars_ThreadTopBar_Day_0_en.png
new file mode 100644
index 0000000000..079ac780f8
--- /dev/null
+++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.topbars_ThreadTopBar_Day_0_en.png
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:617a819de3cd223323b0fa1853185ceb26ffb97a22d79524acec0f4d5b3a634b
+size 33550
diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.topbars_ThreadTopBar_Night_0_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.topbars_ThreadTopBar_Night_0_en.png
new file mode 100644
index 0000000000..b3f0e9c13e
--- /dev/null
+++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.topbars_ThreadTopBar_Night_0_en.png
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:6e146eee5e94e29a2b87b3d4a9bf248445e08dc6eb68c2268b6f263533675c78
+size 33050
diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Day_10_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Day_10_en.png
index 94548f50d8..11b3313094 100644
--- a/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Day_10_en.png
+++ b/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Day_10_en.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:e1ffac0c95378fa7778a4d5b3e5af5a47eef44757f13dbe0032d30b30f96561b
-size 58549
+oid sha256:9571176fb73b9871b6db3c30679a46c776badb56d4e1919ea882b391d893b8c4
+size 53144
diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Day_11_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Day_11_en.png
deleted file mode 100644
index 4ab2179c6b..0000000000
--- a/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Day_11_en.png
+++ /dev/null
@@ -1,3 +0,0 @@
-version https://git-lfs.github.com/spec/v1
-oid sha256:983db5846ee050f682b895ef0ce54362b1214c5bee48ef94139ef825e0ecbab6
-size 61678
diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Day_12_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Day_12_en.png
deleted file mode 100644
index 788ff1abe6..0000000000
--- a/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Day_12_en.png
+++ /dev/null
@@ -1,3 +0,0 @@
-version https://git-lfs.github.com/spec/v1
-oid sha256:501b8bc5c6163c85d1aaee4c9b81c56610931b6d693421d87b5107b3389170ea
-size 60829
diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Day_13_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Day_13_en.png
deleted file mode 100644
index 25a8d03e4a..0000000000
--- a/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Day_13_en.png
+++ /dev/null
@@ -1,3 +0,0 @@
-version https://git-lfs.github.com/spec/v1
-oid sha256:b116183b02d89b112d35ae86d68fdfcec0cb63e5ded20c611a152836090b19b2
-size 60755
diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Day_14_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Day_14_en.png
deleted file mode 100644
index 22fda1dd27..0000000000
--- a/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Day_14_en.png
+++ /dev/null
@@ -1,3 +0,0 @@
-version https://git-lfs.github.com/spec/v1
-oid sha256:0fd783aa6c219e5bdc3c03579bd823a286e6048581728a6786ee724ef458050c
-size 63807
diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Day_15_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Day_15_en.png
deleted file mode 100644
index ff317ac8ad..0000000000
--- a/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Day_15_en.png
+++ /dev/null
@@ -1,3 +0,0 @@
-version https://git-lfs.github.com/spec/v1
-oid sha256:045e0d9605be905e4bbc5d88fc5cfa3bd4a109164709ce5276dedc3dbcf2da80
-size 51119
diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Day_5_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Day_5_en.png
index abd6861f7e..657dc6d2ac 100644
--- a/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Day_5_en.png
+++ b/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Day_5_en.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:373b60146f1fe215eea0c559fbe9810bfe9b714f021e3dddbb649dd6105c5f43
-size 59547
+oid sha256:f6a08f9b69ec278f8706c8de459fd6d2747cef7ed51da32eb7239667d0805e58
+size 55311
diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Day_6_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Day_6_en.png
index 657dc6d2ac..3d2d2949ab 100644
--- a/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Day_6_en.png
+++ b/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Day_6_en.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:f6a08f9b69ec278f8706c8de459fd6d2747cef7ed51da32eb7239667d0805e58
-size 55311
+oid sha256:1b298a6432190f54fdb824c7edc2f8cda30a746d2a13322793c84a5a3d42f5ea
+size 59985
diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Day_7_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Day_7_en.png
index 3d2d2949ab..e3b8e08ac7 100644
--- a/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Day_7_en.png
+++ b/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Day_7_en.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:1b298a6432190f54fdb824c7edc2f8cda30a746d2a13322793c84a5a3d42f5ea
-size 59985
+oid sha256:61add48c03d1f4df4bc9010826c4a6f5adaa312ef5f910bc0b3a77211a377f66
+size 50651
diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Day_8_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Day_8_en.png
index 8c8344673d..4ab2179c6b 100644
--- a/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Day_8_en.png
+++ b/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Day_8_en.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:34a70e62b687f5726073a2339a4246f0e6bf31c187483829082612be69938087
-size 60107
+oid sha256:983db5846ee050f682b895ef0ce54362b1214c5bee48ef94139ef825e0ecbab6
+size 61678
diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Day_9_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Day_9_en.png
index e3b8e08ac7..22fda1dd27 100644
--- a/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Day_9_en.png
+++ b/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Day_9_en.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:61add48c03d1f4df4bc9010826c4a6f5adaa312ef5f910bc0b3a77211a377f66
-size 50651
+oid sha256:0fd783aa6c219e5bdc3c03579bd823a286e6048581728a6786ee724ef458050c
+size 63807
diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Night_10_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Night_10_en.png
index 68918896b2..7d33111f68 100644
--- a/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Night_10_en.png
+++ b/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Night_10_en.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:edc830108c2dd54d594a383020c2e73dba6b6fdff44e279b87889f3dc84ea546
-size 56308
+oid sha256:d6ea6d7eb98c546dbee109d160e2adbbbd4d22d4844835667bfbab1de2060115
+size 52351
diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Night_11_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Night_11_en.png
deleted file mode 100644
index 0ef6da37c9..0000000000
--- a/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Night_11_en.png
+++ /dev/null
@@ -1,3 +0,0 @@
-version https://git-lfs.github.com/spec/v1
-oid sha256:bf12305ee99f199905e94e325743b1589f11d36815e16e86558691400e2991e3
-size 59022
diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Night_12_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Night_12_en.png
deleted file mode 100644
index 98512acaa5..0000000000
--- a/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Night_12_en.png
+++ /dev/null
@@ -1,3 +0,0 @@
-version https://git-lfs.github.com/spec/v1
-oid sha256:e1b50937116f9d14103a1753199686f959371b8fe6ad006cadf1c3fb121fb72a
-size 58491
diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Night_13_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Night_13_en.png
deleted file mode 100644
index 9ed7763072..0000000000
--- a/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Night_13_en.png
+++ /dev/null
@@ -1,3 +0,0 @@
-version https://git-lfs.github.com/spec/v1
-oid sha256:8f5c6283d080341dd600f723329355447fa190c8b36aa4241536c4993ce55b76
-size 58466
diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Night_14_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Night_14_en.png
deleted file mode 100644
index 998c5ab138..0000000000
--- a/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Night_14_en.png
+++ /dev/null
@@ -1,3 +0,0 @@
-version https://git-lfs.github.com/spec/v1
-oid sha256:01ea3893df495012f2e417e81d2223696ee11efe2499c0c2a112f015c1f72f7a
-size 64610
diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Night_15_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Night_15_en.png
deleted file mode 100644
index 7fb660b0fb..0000000000
--- a/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Night_15_en.png
+++ /dev/null
@@ -1,3 +0,0 @@
-version https://git-lfs.github.com/spec/v1
-oid sha256:fdb2ca59f48d38d8fa7ebeb9d5768b44f216266a27f6cec9d518b729ecece253
-size 50253
diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Night_5_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Night_5_en.png
index 06f314231c..c041fd7d11 100644
--- a/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Night_5_en.png
+++ b/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Night_5_en.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:21ef350495865cd55510b9dd59ffcb7fa3600369df3077322c352e47cc8d93b1
-size 57291
+oid sha256:c1534b9c3b6952c290ca20a2853e56be023e5c8129a10b9f3fd63c290c7ba9fb
+size 52977
diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Night_6_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Night_6_en.png
index c041fd7d11..7a6efabb58 100644
--- a/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Night_6_en.png
+++ b/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Night_6_en.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:c1534b9c3b6952c290ca20a2853e56be023e5c8129a10b9f3fd63c290c7ba9fb
-size 52977
+oid sha256:7b50e874595cfcb65cf2a4f7146ed7c99ee06899d6512024b900a64439748a6f
+size 54078
diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Night_7_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Night_7_en.png
index 7a6efabb58..21888106d2 100644
--- a/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Night_7_en.png
+++ b/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Night_7_en.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:7b50e874595cfcb65cf2a4f7146ed7c99ee06899d6512024b900a64439748a6f
-size 54078
+oid sha256:aafdc477f090674d0473076071049bba77bc57025c602cb6bc1cdfada03a1937
+size 44740
diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Night_8_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Night_8_en.png
index 2745c0ff60..0ef6da37c9 100644
--- a/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Night_8_en.png
+++ b/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Night_8_en.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:b5052598f1d095bb854522a2b0e880a6a88c070e372e1a2fd73b487611f8f733
-size 57716
+oid sha256:bf12305ee99f199905e94e325743b1589f11d36815e16e86558691400e2991e3
+size 59022
diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Night_9_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Night_9_en.png
index 21888106d2..998c5ab138 100644
--- a/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Night_9_en.png
+++ b/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Night_9_en.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:aafdc477f090674d0473076071049bba77bc57025c602cb6bc1cdfada03a1937
-size 44740
+oid sha256:01ea3893df495012f2e417e81d2223696ee11efe2499c0c2a112f015c1f72f7a
+size 64610
diff --git a/tests/uitests/src/test/snapshots/images/features.preferences.impl.notifications_NotificationSettingsView_Day_6_en.png b/tests/uitests/src/test/snapshots/images/features.preferences.impl.notifications_NotificationSettingsView_Day_6_en.png
index 43bcd29a9b..d79f995fa3 100644
--- a/tests/uitests/src/test/snapshots/images/features.preferences.impl.notifications_NotificationSettingsView_Day_6_en.png
+++ b/tests/uitests/src/test/snapshots/images/features.preferences.impl.notifications_NotificationSettingsView_Day_6_en.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:3028295864a6990944ec3485d8b7c1aa1688005f34b7519e66176c6d945aff2c
-size 39907
+oid sha256:a049311411b2e8bb777d2fefc74c06e943c36931e24419c1b9155472643a6f90
+size 39868
diff --git a/tests/uitests/src/test/snapshots/images/features.preferences.impl.notifications_NotificationSettingsView_Day_7_en.png b/tests/uitests/src/test/snapshots/images/features.preferences.impl.notifications_NotificationSettingsView_Day_7_en.png
index 4ea3d6f1fe..ab1af1559f 100644
--- a/tests/uitests/src/test/snapshots/images/features.preferences.impl.notifications_NotificationSettingsView_Day_7_en.png
+++ b/tests/uitests/src/test/snapshots/images/features.preferences.impl.notifications_NotificationSettingsView_Day_7_en.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:d3ae8baf10cc1adb8bb3dbf4bfcd2653876dd9c902b07d33bd4f5690d18ec263
-size 44378
+oid sha256:f6a577b1e7047237c485fbcf49d238478f638e471e5f637721c7766eacc89799
+size 44275
diff --git a/tests/uitests/src/test/snapshots/images/features.preferences.impl.notifications_NotificationSettingsView_Night_6_en.png b/tests/uitests/src/test/snapshots/images/features.preferences.impl.notifications_NotificationSettingsView_Night_6_en.png
index 83bfb6b921..b515219e5c 100644
--- a/tests/uitests/src/test/snapshots/images/features.preferences.impl.notifications_NotificationSettingsView_Night_6_en.png
+++ b/tests/uitests/src/test/snapshots/images/features.preferences.impl.notifications_NotificationSettingsView_Night_6_en.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:d8c02eaac714aff002eb259579a33e576fabd4442c2c4528df36ef5c910a9efb
-size 37262
+oid sha256:5d1b3e8eabbbd4ebfb3dd14e67aa0944d7d291688d458423c4bb45c47056c028
+size 37280
diff --git a/tests/uitests/src/test/snapshots/images/features.preferences.impl.notifications_NotificationSettingsView_Night_7_en.png b/tests/uitests/src/test/snapshots/images/features.preferences.impl.notifications_NotificationSettingsView_Night_7_en.png
index a6c7b2d4d7..0c6d1d86c3 100644
--- a/tests/uitests/src/test/snapshots/images/features.preferences.impl.notifications_NotificationSettingsView_Night_7_en.png
+++ b/tests/uitests/src/test/snapshots/images/features.preferences.impl.notifications_NotificationSettingsView_Night_7_en.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:0637ff1ee39762445cc8c5498680152c2e2e8012108231fcc2974326a1d8cdb7
-size 41466
+oid sha256:ff548b1c9c9d4fc8b376ae12be6c8468483715726bc0deecf4fc4f5854d727ad
+size 41418
diff --git a/tests/uitests/src/test/snapshots/images/features.preferences.impl.root_PreferencesRootViewDark_0_en.png b/tests/uitests/src/test/snapshots/images/features.preferences.impl.root_PreferencesRootViewDark_0_en.png
index 3024f2cff8..782a8aba82 100644
--- a/tests/uitests/src/test/snapshots/images/features.preferences.impl.root_PreferencesRootViewDark_0_en.png
+++ b/tests/uitests/src/test/snapshots/images/features.preferences.impl.root_PreferencesRootViewDark_0_en.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:a3329563aa6c438335aaadb18cc2767d78eb16c34b616c5e9b14f0d8b66fb032
-size 38106
+oid sha256:b5c95596f8a3e78692c7fa13b95a3491d320e4a89273c61cc22595817bf4e846
+size 38104
diff --git a/tests/uitests/src/test/snapshots/images/features.preferences.impl.root_PreferencesRootViewDark_1_en.png b/tests/uitests/src/test/snapshots/images/features.preferences.impl.root_PreferencesRootViewDark_1_en.png
index a23da63542..d12ebf79be 100644
--- a/tests/uitests/src/test/snapshots/images/features.preferences.impl.root_PreferencesRootViewDark_1_en.png
+++ b/tests/uitests/src/test/snapshots/images/features.preferences.impl.root_PreferencesRootViewDark_1_en.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:a7b3d3f464858c9a298461aad3d3a329ac894fbd6206cbc73ec0de16d20e69e3
-size 37946
+oid sha256:7cfb090fcb56f52c935f72ec52659f574aa088a663a991c7cd49688d42001388
+size 37944
diff --git a/tests/uitests/src/test/snapshots/images/features.preferences.impl.root_PreferencesRootViewLight_0_en.png b/tests/uitests/src/test/snapshots/images/features.preferences.impl.root_PreferencesRootViewLight_0_en.png
index fe9ddfe32f..3f96c2234e 100644
--- a/tests/uitests/src/test/snapshots/images/features.preferences.impl.root_PreferencesRootViewLight_0_en.png
+++ b/tests/uitests/src/test/snapshots/images/features.preferences.impl.root_PreferencesRootViewLight_0_en.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:f0ba38204b90b53b0b03efabc5dd69200089327c22250e9416d8ee2fd2b94537
-size 38915
+oid sha256:b092653f3c1192c3c2e0f0eb8803d20a0879af6bdcde2d51f6f6d4894ccc7c52
+size 38914
diff --git a/tests/uitests/src/test/snapshots/images/features.preferences.impl.root_PreferencesRootViewLight_1_en.png b/tests/uitests/src/test/snapshots/images/features.preferences.impl.root_PreferencesRootViewLight_1_en.png
index 694ad9d65e..499340fa1e 100644
--- a/tests/uitests/src/test/snapshots/images/features.preferences.impl.root_PreferencesRootViewLight_1_en.png
+++ b/tests/uitests/src/test/snapshots/images/features.preferences.impl.root_PreferencesRootViewLight_1_en.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:cb9b09711d4538aa350d9c072b31becb223cd2b842d606f405b208e3cc13b77c
+oid sha256:78411c84878a5f97b2208b7d688094148fbf88660b1b8fbc0e5fa7b2aebbbf5b
size 38968
diff --git a/tests/uitests/src/test/snapshots/images/features.roomaliasresolver.impl_RoomAliasResolverView_Day_0_en.png b/tests/uitests/src/test/snapshots/images/features.roomaliasresolver.impl_RoomAliasResolverView_Day_0_en.png
index 8cb0a46709..31eb958563 100644
--- a/tests/uitests/src/test/snapshots/images/features.roomaliasresolver.impl_RoomAliasResolverView_Day_0_en.png
+++ b/tests/uitests/src/test/snapshots/images/features.roomaliasresolver.impl_RoomAliasResolverView_Day_0_en.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:1b0c1728d598c5bf307a2b9a193c2746831c83de892fc53ccb7da1bb183b8297
-size 8475
+oid sha256:6d4663e9c2c439b05d6d1abe7ae7098539f5263461e9051b0b97305a31b5aa33
+size 8395
diff --git a/tests/uitests/src/test/snapshots/images/features.roomaliasresolver.impl_RoomAliasResolverView_Day_1_en.png b/tests/uitests/src/test/snapshots/images/features.roomaliasresolver.impl_RoomAliasResolverView_Day_1_en.png
index 979b3141be..947b0607e5 100644
--- a/tests/uitests/src/test/snapshots/images/features.roomaliasresolver.impl_RoomAliasResolverView_Day_1_en.png
+++ b/tests/uitests/src/test/snapshots/images/features.roomaliasresolver.impl_RoomAliasResolverView_Day_1_en.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:8e23c1347af06b2fa6f1982159cdb92b2bed278ab1b4caf782c3916520681d75
-size 26616
+oid sha256:5365eb3dd7e10fde8591e6d5ee6dfadef88a9fa25339309ce08445f89af88789
+size 29187
diff --git a/tests/uitests/src/test/snapshots/images/features.roomaliasresolver.impl_RoomAliasResolverView_Day_2_en.png b/tests/uitests/src/test/snapshots/images/features.roomaliasresolver.impl_RoomAliasResolverView_Day_2_en.png
index b8f30f125d..6faf40fe01 100644
--- a/tests/uitests/src/test/snapshots/images/features.roomaliasresolver.impl_RoomAliasResolverView_Day_2_en.png
+++ b/tests/uitests/src/test/snapshots/images/features.roomaliasresolver.impl_RoomAliasResolverView_Day_2_en.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:9de3402e8b3eed6005f80ecaeea325c533a0f4d51e2dd306baf6ad97a09042d4
-size 23373
+oid sha256:5c66ca10f770fa2f29716f7c737be0acef03e364e9a27a85b81e4ef63e768b6f
+size 24012
diff --git a/tests/uitests/src/test/snapshots/images/features.roomaliasresolver.impl_RoomAliasResolverView_Night_0_en.png b/tests/uitests/src/test/snapshots/images/features.roomaliasresolver.impl_RoomAliasResolverView_Night_0_en.png
index 0c7e27a22d..26a56fec35 100644
--- a/tests/uitests/src/test/snapshots/images/features.roomaliasresolver.impl_RoomAliasResolverView_Night_0_en.png
+++ b/tests/uitests/src/test/snapshots/images/features.roomaliasresolver.impl_RoomAliasResolverView_Night_0_en.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:a3f39d62131784e82104ee0033e4da9e2de45eacc1527b878fdaa9dd64d45aa2
-size 8324
+oid sha256:c5b7cb8b7ef8b58a5fa77b7c1c6a911798940337ea9646383ee0cb082dc68f7e
+size 8263
diff --git a/tests/uitests/src/test/snapshots/images/features.roomaliasresolver.impl_RoomAliasResolverView_Night_1_en.png b/tests/uitests/src/test/snapshots/images/features.roomaliasresolver.impl_RoomAliasResolverView_Night_1_en.png
index 7c9d79d83e..a6bed8f351 100644
--- a/tests/uitests/src/test/snapshots/images/features.roomaliasresolver.impl_RoomAliasResolverView_Night_1_en.png
+++ b/tests/uitests/src/test/snapshots/images/features.roomaliasresolver.impl_RoomAliasResolverView_Night_1_en.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:809913705eb237bdd8575a92be89cf616d27c7d54a32894378f693dbf1969d0a
-size 24731
+oid sha256:c02fa02a7f5787d375ffa6e9bb69cde0b23ca87512ee8120d318becd6de13bef
+size 26763
diff --git a/tests/uitests/src/test/snapshots/images/features.roomaliasresolver.impl_RoomAliasResolverView_Night_2_en.png b/tests/uitests/src/test/snapshots/images/features.roomaliasresolver.impl_RoomAliasResolverView_Night_2_en.png
index 6d2ed82c26..a0b5cf90f0 100644
--- a/tests/uitests/src/test/snapshots/images/features.roomaliasresolver.impl_RoomAliasResolverView_Night_2_en.png
+++ b/tests/uitests/src/test/snapshots/images/features.roomaliasresolver.impl_RoomAliasResolverView_Night_2_en.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:d1f5a7d25ad07bc6b0025ea4f600609f58b881452e826d93378f80062626b3d7
-size 21274
+oid sha256:5852e500de1f27083f033726a89d2dda594497d2af7fbe843091cdbd06ddd975
+size 21628
diff --git a/tests/uitests/src/test/snapshots/images/features.roomdetails.impl.invite_RoomInviteMembersView_Day_3_en.png b/tests/uitests/src/test/snapshots/images/features.roomdetails.impl.invite_RoomInviteMembersView_Day_3_en.png
new file mode 100644
index 0000000000..1f179c4be8
--- /dev/null
+++ b/tests/uitests/src/test/snapshots/images/features.roomdetails.impl.invite_RoomInviteMembersView_Day_3_en.png
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:a809a8792d519f93df9a15c57c06d3fd4f3cb7c84245e80cf61ff07ab1c5d620
+size 20363
diff --git a/tests/uitests/src/test/snapshots/images/features.roomdetails.impl.invite_RoomInviteMembersView_Night_3_en.png b/tests/uitests/src/test/snapshots/images/features.roomdetails.impl.invite_RoomInviteMembersView_Night_3_en.png
new file mode 100644
index 0000000000..f326451237
--- /dev/null
+++ b/tests/uitests/src/test/snapshots/images/features.roomdetails.impl.invite_RoomInviteMembersView_Night_3_en.png
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:433e3467cfa0c0f4e737ec15a1c41d6bbc36d4d2c2dd9f2f7f22bb457208f280
+size 19180
diff --git a/tests/uitests/src/test/snapshots/images/features.roomdetails.impl.rolesandpermissions.permissions_ChangeRoomPermissionsView_Day_6_en.png b/tests/uitests/src/test/snapshots/images/features.roomdetails.impl.rolesandpermissions.permissions_ChangeRoomPermissionsView_Day_6_en.png
index ac4547d7ea..e2f67353d2 100644
--- a/tests/uitests/src/test/snapshots/images/features.roomdetails.impl.rolesandpermissions.permissions_ChangeRoomPermissionsView_Day_6_en.png
+++ b/tests/uitests/src/test/snapshots/images/features.roomdetails.impl.rolesandpermissions.permissions_ChangeRoomPermissionsView_Day_6_en.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:a8747685a776c4fc59d8fed90b057ab18b8abf2670cd430ca4afcf745a402724
-size 44114
+oid sha256:146e40d680e33105cc06cda3a113432f29b42bf7f3b539b4ea17fd6ff9a9265e
+size 44093
diff --git a/tests/uitests/src/test/snapshots/images/features.roomdetails.impl.rolesandpermissions.permissions_ChangeRoomPermissionsView_Night_6_en.png b/tests/uitests/src/test/snapshots/images/features.roomdetails.impl.rolesandpermissions.permissions_ChangeRoomPermissionsView_Night_6_en.png
index ce722d74ff..f6dad027b0 100644
--- a/tests/uitests/src/test/snapshots/images/features.roomdetails.impl.rolesandpermissions.permissions_ChangeRoomPermissionsView_Night_6_en.png
+++ b/tests/uitests/src/test/snapshots/images/features.roomdetails.impl.rolesandpermissions.permissions_ChangeRoomPermissionsView_Night_6_en.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:a775ed56c60c2a57cdd8b2d4c54cf557919be0b80948a50402445c37806fd319
-size 42168
+oid sha256:49f72fe1ede6eb11c2e1572af27086df4f9c7eec45cf3ea3cfe6235ea89f12cf
+size 42150
diff --git a/tests/uitests/src/test/snapshots/images/features.roommembermoderation.impl_RoomMemberModerationView_Day_4_en.png b/tests/uitests/src/test/snapshots/images/features.roommembermoderation.impl_RoomMemberModerationView_Day_4_en.png
index 93944ff960..edec0550ca 100644
--- a/tests/uitests/src/test/snapshots/images/features.roommembermoderation.impl_RoomMemberModerationView_Day_4_en.png
+++ b/tests/uitests/src/test/snapshots/images/features.roommembermoderation.impl_RoomMemberModerationView_Day_4_en.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:7065059b0ee8165b631225f5468fd937c217b08544ec38bdb13d46dd0bda8a24
-size 30646
+oid sha256:e4063555b9c55be91104f51d5696383aba383d2b7b8d6ff490058f0228e45f81
+size 30659
diff --git a/tests/uitests/src/test/snapshots/images/features.roommembermoderation.impl_RoomMemberModerationView_Day_6_en.png b/tests/uitests/src/test/snapshots/images/features.roommembermoderation.impl_RoomMemberModerationView_Day_6_en.png
index 77921fc181..14d1396ac9 100644
--- a/tests/uitests/src/test/snapshots/images/features.roommembermoderation.impl_RoomMemberModerationView_Day_6_en.png
+++ b/tests/uitests/src/test/snapshots/images/features.roommembermoderation.impl_RoomMemberModerationView_Day_6_en.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:2071ff6a7820d23d20cfd6863b9cfa05439f596f9a94c734806d807d661bb813
-size 29383
+oid sha256:c09808dc63bad05bc97a6d5d5f62a4d0fd3db86c17e4662aa2b56eb50143361a
+size 29415
diff --git a/tests/uitests/src/test/snapshots/images/features.roommembermoderation.impl_RoomMemberModerationView_Night_4_en.png b/tests/uitests/src/test/snapshots/images/features.roommembermoderation.impl_RoomMemberModerationView_Night_4_en.png
index 2d0471e281..9c6513bfd1 100644
--- a/tests/uitests/src/test/snapshots/images/features.roommembermoderation.impl_RoomMemberModerationView_Night_4_en.png
+++ b/tests/uitests/src/test/snapshots/images/features.roommembermoderation.impl_RoomMemberModerationView_Night_4_en.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:517ee043e2f70702df7791d8b352598a6d7ff572ab5c7d42c606597b3efe2c35
-size 28815
+oid sha256:3a7da5666d690d5d9a6be61225b169e4703626ebc15f2f8f4f3e98d2e322de39
+size 28831
diff --git a/tests/uitests/src/test/snapshots/images/features.roommembermoderation.impl_RoomMemberModerationView_Night_6_en.png b/tests/uitests/src/test/snapshots/images/features.roommembermoderation.impl_RoomMemberModerationView_Night_6_en.png
index b067bdbc8c..9f70cf870f 100644
--- a/tests/uitests/src/test/snapshots/images/features.roommembermoderation.impl_RoomMemberModerationView_Night_6_en.png
+++ b/tests/uitests/src/test/snapshots/images/features.roommembermoderation.impl_RoomMemberModerationView_Night_6_en.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:77d65977a990b8505d61bc61d39ea6855e5e931cb0503a380464df9eee4f5854
-size 27528
+oid sha256:97d7e385717dd0ebd7beac1fbd5c205e13f7785febabee15bfffa0026b8d530c
+size 27616
diff --git a/tests/uitests/src/test/snapshots/images/features.securebackup.impl.enter_SecureBackupEnterRecoveryKeyView_Day_3_en.png b/tests/uitests/src/test/snapshots/images/features.securebackup.impl.enter_SecureBackupEnterRecoveryKeyView_Day_3_en.png
index ecae8555cf..30a1a4772b 100644
--- a/tests/uitests/src/test/snapshots/images/features.securebackup.impl.enter_SecureBackupEnterRecoveryKeyView_Day_3_en.png
+++ b/tests/uitests/src/test/snapshots/images/features.securebackup.impl.enter_SecureBackupEnterRecoveryKeyView_Day_3_en.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:e4582d19a955cf012c6c07db728b69ae4a1e99dff7292f1dcaaf68d8afbe3141
-size 34821
+oid sha256:4cea381806f7903d56640938ccf8c6d3312c8d27cd768629209db4f8a4b2fb75
+size 34891
diff --git a/tests/uitests/src/test/snapshots/images/features.securebackup.impl.enter_SecureBackupEnterRecoveryKeyView_Night_3_en.png b/tests/uitests/src/test/snapshots/images/features.securebackup.impl.enter_SecureBackupEnterRecoveryKeyView_Night_3_en.png
index 705fe313f0..f661545528 100644
--- a/tests/uitests/src/test/snapshots/images/features.securebackup.impl.enter_SecureBackupEnterRecoveryKeyView_Night_3_en.png
+++ b/tests/uitests/src/test/snapshots/images/features.securebackup.impl.enter_SecureBackupEnterRecoveryKeyView_Night_3_en.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:c1f6f4d016188b72e28ae192c9b2379a0734e34586295e4ab5a522fabb152f58
-size 32356
+oid sha256:8a8e1b4d80a8144e92f047259047104c39e3e03ddb9f49ce8b643f5ee074b772
+size 32384
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 26c609c792..e999349e08 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:74ff9446fb276504638707c4779e3947147d40c9114ee126ad22d1977b5d5397
-size 54561
+oid sha256:1b50f2f588c835adb9d2025fd904e8cd9462fb5b5f6952249b3b1fc0098e7dd2
+size 54688
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 f095c5ecda..790641766b 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:2ffd2de03c34e9329cdb7320b67133e5e9f66e3cb133c3be2cb2101de3a789dc
-size 52502
+oid sha256:2584a9ff1ae31f50e2c7902e2a04995c7c96d8085328e262d50be8a2395f71f9
+size 52541
diff --git a/tests/uitests/src/test/snapshots/images/features.securebackup.impl.setup_SecureBackupSetupViewChange_Day_4_en.png b/tests/uitests/src/test/snapshots/images/features.securebackup.impl.setup_SecureBackupSetupViewChange_Day_4_en.png
index 6b6971c495..b7b6ca3318 100644
--- a/tests/uitests/src/test/snapshots/images/features.securebackup.impl.setup_SecureBackupSetupViewChange_Day_4_en.png
+++ b/tests/uitests/src/test/snapshots/images/features.securebackup.impl.setup_SecureBackupSetupViewChange_Day_4_en.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:3e631c4ab7338e9c5fff80de7b5981a85d495b47977d10318a6d02c381d6049e
-size 48632
+oid sha256:0a8cf71b7c7ac794bf6f0fd71fe477cb0dd651ff86ad649fe4eaa9e8df83b1cf
+size 48594
diff --git a/tests/uitests/src/test/snapshots/images/features.securebackup.impl.setup_SecureBackupSetupViewChange_Day_5_en.png b/tests/uitests/src/test/snapshots/images/features.securebackup.impl.setup_SecureBackupSetupViewChange_Day_5_en.png
index 23adbc3c79..0d260a0a24 100644
--- a/tests/uitests/src/test/snapshots/images/features.securebackup.impl.setup_SecureBackupSetupViewChange_Day_5_en.png
+++ b/tests/uitests/src/test/snapshots/images/features.securebackup.impl.setup_SecureBackupSetupViewChange_Day_5_en.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:d0091ef6aaa0eb66f155e13993d6979578ea27464d28397af9b7587fbc715942
-size 35688
+oid sha256:098b7a3b50e1bca8c03c55c8b118694339b6cc9033f4f94847c66a59e0629743
+size 35835
diff --git a/tests/uitests/src/test/snapshots/images/features.securebackup.impl.setup_SecureBackupSetupViewChange_Night_4_en.png b/tests/uitests/src/test/snapshots/images/features.securebackup.impl.setup_SecureBackupSetupViewChange_Night_4_en.png
index 32fab22a28..8e3198caa9 100644
--- a/tests/uitests/src/test/snapshots/images/features.securebackup.impl.setup_SecureBackupSetupViewChange_Night_4_en.png
+++ b/tests/uitests/src/test/snapshots/images/features.securebackup.impl.setup_SecureBackupSetupViewChange_Night_4_en.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:7bba3b6776ec442d113b8cade307624406f608b09ca2dddad1ce07a35259d664
-size 45896
+oid sha256:a31fc85a97482f83147f8db4b3dc95ac5c96d16fbcc849ab44588bc2462377d7
+size 45963
diff --git a/tests/uitests/src/test/snapshots/images/features.securebackup.impl.setup_SecureBackupSetupViewChange_Night_5_en.png b/tests/uitests/src/test/snapshots/images/features.securebackup.impl.setup_SecureBackupSetupViewChange_Night_5_en.png
index 6b69fa0ceb..e1c6673840 100644
--- a/tests/uitests/src/test/snapshots/images/features.securebackup.impl.setup_SecureBackupSetupViewChange_Night_5_en.png
+++ b/tests/uitests/src/test/snapshots/images/features.securebackup.impl.setup_SecureBackupSetupViewChange_Night_5_en.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:d1091a682fa4b15d85e557a5681b502da7c9c13de54090125b5256d976ef7322
-size 32707
+oid sha256:01d4b4598591373cbb507fd4074aafc7a0c04d84bf89ff1bc7e4eaa7bde71a7a
+size 32880
diff --git a/tests/uitests/src/test/snapshots/images/features.securebackup.impl.setup_SecureBackupSetupView_Day_4_en.png b/tests/uitests/src/test/snapshots/images/features.securebackup.impl.setup_SecureBackupSetupView_Day_4_en.png
index 6b6971c495..b7b6ca3318 100644
--- a/tests/uitests/src/test/snapshots/images/features.securebackup.impl.setup_SecureBackupSetupView_Day_4_en.png
+++ b/tests/uitests/src/test/snapshots/images/features.securebackup.impl.setup_SecureBackupSetupView_Day_4_en.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:3e631c4ab7338e9c5fff80de7b5981a85d495b47977d10318a6d02c381d6049e
-size 48632
+oid sha256:0a8cf71b7c7ac794bf6f0fd71fe477cb0dd651ff86ad649fe4eaa9e8df83b1cf
+size 48594
diff --git a/tests/uitests/src/test/snapshots/images/features.securebackup.impl.setup_SecureBackupSetupView_Day_5_en.png b/tests/uitests/src/test/snapshots/images/features.securebackup.impl.setup_SecureBackupSetupView_Day_5_en.png
index 78b88b0ef7..da055ab499 100644
--- a/tests/uitests/src/test/snapshots/images/features.securebackup.impl.setup_SecureBackupSetupView_Day_5_en.png
+++ b/tests/uitests/src/test/snapshots/images/features.securebackup.impl.setup_SecureBackupSetupView_Day_5_en.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:5a2502351e4de7541a573b2d5b0f51643ea90dcad1c654acbcb342660df5fc98
-size 34306
+oid sha256:f4317eb9258f74756d4ecf3aa430dad3ee93cf446588d6fac9bbc6cc12c2c3b0
+size 34467
diff --git a/tests/uitests/src/test/snapshots/images/features.securebackup.impl.setup_SecureBackupSetupView_Night_4_en.png b/tests/uitests/src/test/snapshots/images/features.securebackup.impl.setup_SecureBackupSetupView_Night_4_en.png
index 32fab22a28..8e3198caa9 100644
--- a/tests/uitests/src/test/snapshots/images/features.securebackup.impl.setup_SecureBackupSetupView_Night_4_en.png
+++ b/tests/uitests/src/test/snapshots/images/features.securebackup.impl.setup_SecureBackupSetupView_Night_4_en.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:7bba3b6776ec442d113b8cade307624406f608b09ca2dddad1ce07a35259d664
-size 45896
+oid sha256:a31fc85a97482f83147f8db4b3dc95ac5c96d16fbcc849ab44588bc2462377d7
+size 45963
diff --git a/tests/uitests/src/test/snapshots/images/features.securebackup.impl.setup_SecureBackupSetupView_Night_5_en.png b/tests/uitests/src/test/snapshots/images/features.securebackup.impl.setup_SecureBackupSetupView_Night_5_en.png
index 4c2d58030a..b556abffc7 100644
--- a/tests/uitests/src/test/snapshots/images/features.securebackup.impl.setup_SecureBackupSetupView_Night_5_en.png
+++ b/tests/uitests/src/test/snapshots/images/features.securebackup.impl.setup_SecureBackupSetupView_Night_5_en.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:8f8a48e08a9caf55dffd4812091f24c26995dcb238944cd409c93c0ef359cebb
-size 31493
+oid sha256:d233d12ec3b268a3b0f4b902a784708dc4ddbf804b37d72111c5b7677e346ade
+size 31620
diff --git a/tests/uitests/src/test/snapshots/images/features.space.impl_SpaceView_Day_0_en.png b/tests/uitests/src/test/snapshots/images/features.space.impl_SpaceView_Day_0_en.png
new file mode 100644
index 0000000000..47fc782a13
--- /dev/null
+++ b/tests/uitests/src/test/snapshots/images/features.space.impl_SpaceView_Day_0_en.png
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:4c53e7edfe8b9ea00bb97f9ab6e8289081b5c36aad54a58d4f535fc533338797
+size 15733
diff --git a/tests/uitests/src/test/snapshots/images/features.space.impl_SpaceView_Day_1_en.png b/tests/uitests/src/test/snapshots/images/features.space.impl_SpaceView_Day_1_en.png
new file mode 100644
index 0000000000..fe88fafe4f
--- /dev/null
+++ b/tests/uitests/src/test/snapshots/images/features.space.impl_SpaceView_Day_1_en.png
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:0075dca9fd927dc7df4e987fe5cca8d2a2ca5b268bc46916dcd49724264a3859
+size 19834
diff --git a/tests/uitests/src/test/snapshots/images/features.space.impl_SpaceView_Day_2_en.png b/tests/uitests/src/test/snapshots/images/features.space.impl_SpaceView_Day_2_en.png
new file mode 100644
index 0000000000..80a6ed2561
--- /dev/null
+++ b/tests/uitests/src/test/snapshots/images/features.space.impl_SpaceView_Day_2_en.png
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:9d784e5d4d4af937a33825f7098d0849fa044d96e4cf21c7244f51432d3f32c7
+size 46725
diff --git a/tests/uitests/src/test/snapshots/images/features.space.impl_SpaceView_Day_3_en.png b/tests/uitests/src/test/snapshots/images/features.space.impl_SpaceView_Day_3_en.png
new file mode 100644
index 0000000000..1c0ff9913e
--- /dev/null
+++ b/tests/uitests/src/test/snapshots/images/features.space.impl_SpaceView_Day_3_en.png
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:1a1c851207069720dd83cf32da6da80d25a4a4c40cba9884548f9dea09ca6654
+size 45383
diff --git a/tests/uitests/src/test/snapshots/images/features.space.impl_SpaceView_Night_0_en.png b/tests/uitests/src/test/snapshots/images/features.space.impl_SpaceView_Night_0_en.png
new file mode 100644
index 0000000000..1de4e50542
--- /dev/null
+++ b/tests/uitests/src/test/snapshots/images/features.space.impl_SpaceView_Night_0_en.png
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:ea671a40116dfe7a0e4ac97b58cbbc48b3f70fe08b5613c4b21ec13bc6850c3f
+size 15589
diff --git a/tests/uitests/src/test/snapshots/images/features.space.impl_SpaceView_Night_1_en.png b/tests/uitests/src/test/snapshots/images/features.space.impl_SpaceView_Night_1_en.png
new file mode 100644
index 0000000000..18a49cfc20
--- /dev/null
+++ b/tests/uitests/src/test/snapshots/images/features.space.impl_SpaceView_Night_1_en.png
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:8b69241047e1d5787620331adc33f2b78084f47cf02c531a4e41011816590a09
+size 19523
diff --git a/tests/uitests/src/test/snapshots/images/features.space.impl_SpaceView_Night_2_en.png b/tests/uitests/src/test/snapshots/images/features.space.impl_SpaceView_Night_2_en.png
new file mode 100644
index 0000000000..bd899f7f08
--- /dev/null
+++ b/tests/uitests/src/test/snapshots/images/features.space.impl_SpaceView_Night_2_en.png
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:ae27a6a05d85587b066203ec8828db0ec1cec2171e1f3a63c6b0c26e0b71555e
+size 46151
diff --git a/tests/uitests/src/test/snapshots/images/features.space.impl_SpaceView_Night_3_en.png b/tests/uitests/src/test/snapshots/images/features.space.impl_SpaceView_Night_3_en.png
new file mode 100644
index 0000000000..b3c914f630
--- /dev/null
+++ b/tests/uitests/src/test/snapshots/images/features.space.impl_SpaceView_Night_3_en.png
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:067d6b499ce3ec737792a773c2959aea44829cb27a8fecbe1925ec884bc7f53f
+size 44650
diff --git a/tests/uitests/src/test/snapshots/images/libraries.designsystem.components.avatar_Avatar_Avatars_100_en.png b/tests/uitests/src/test/snapshots/images/libraries.designsystem.components.avatar_Avatar_Avatars_100_en.png
index 53dbe79213..eee5b83831 100644
--- a/tests/uitests/src/test/snapshots/images/libraries.designsystem.components.avatar_Avatar_Avatars_100_en.png
+++ b/tests/uitests/src/test/snapshots/images/libraries.designsystem.components.avatar_Avatar_Avatars_100_en.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:26b9908bbd388321444037dcc1aae55037d3dabc7a9f9b14c39ba871f4f9d593
-size 16128
+oid sha256:9640e8e6d758a03f995c7fbbb6c3c123109594138a7cc53d5416ef5e3e157693
+size 18006
diff --git a/tests/uitests/src/test/snapshots/images/libraries.designsystem.components.avatar_Avatar_Avatars_101_en.png b/tests/uitests/src/test/snapshots/images/libraries.designsystem.components.avatar_Avatar_Avatars_101_en.png
index 9c9b3d4717..70c84280d6 100644
--- a/tests/uitests/src/test/snapshots/images/libraries.designsystem.components.avatar_Avatar_Avatars_101_en.png
+++ b/tests/uitests/src/test/snapshots/images/libraries.designsystem.components.avatar_Avatar_Avatars_101_en.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:1a96b6d95b8941d80035b309444b9eaa038098fb16aa84dec209fc3ee215ac9e
-size 21687
+oid sha256:fbe699fb17947981c53d47a9570da71e2388ec493a3a9471aaa13a5405075069
+size 23421
diff --git a/tests/uitests/src/test/snapshots/images/libraries.designsystem.components.avatar_Avatar_Avatars_102_en.png b/tests/uitests/src/test/snapshots/images/libraries.designsystem.components.avatar_Avatar_Avatars_102_en.png
index 7946dc4e91..f4e93c12ae 100644
--- a/tests/uitests/src/test/snapshots/images/libraries.designsystem.components.avatar_Avatar_Avatars_102_en.png
+++ b/tests/uitests/src/test/snapshots/images/libraries.designsystem.components.avatar_Avatar_Avatars_102_en.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:ce1aba18ea8a6b45d9c40de9af961952e261c7c6200ab13cdfa67906d995208b
-size 14888
+oid sha256:8c6688901f89d3858ec67dda889fe589fb6b59202c64a4b700c2aa484e19f4cd
+size 17606
diff --git a/tests/uitests/src/test/snapshots/images/libraries.designsystem.components.avatar_Avatar_Avatars_103_en.png b/tests/uitests/src/test/snapshots/images/libraries.designsystem.components.avatar_Avatar_Avatars_103_en.png
index 0b12b366b9..53dbe79213 100644
--- a/tests/uitests/src/test/snapshots/images/libraries.designsystem.components.avatar_Avatar_Avatars_103_en.png
+++ b/tests/uitests/src/test/snapshots/images/libraries.designsystem.components.avatar_Avatar_Avatars_103_en.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:6a4d295ae71ba2709845312b84983b79348069ded46b30091b9fa769a587cbb7
-size 14337
+oid sha256:26b9908bbd388321444037dcc1aae55037d3dabc7a9f9b14c39ba871f4f9d593
+size 16128
diff --git a/tests/uitests/src/test/snapshots/images/libraries.designsystem.components.avatar_Avatar_Avatars_104_en.png b/tests/uitests/src/test/snapshots/images/libraries.designsystem.components.avatar_Avatar_Avatars_104_en.png
index 556cb141b0..9c9b3d4717 100644
--- a/tests/uitests/src/test/snapshots/images/libraries.designsystem.components.avatar_Avatar_Avatars_104_en.png
+++ b/tests/uitests/src/test/snapshots/images/libraries.designsystem.components.avatar_Avatar_Avatars_104_en.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:da8f54591a52475c6f47fa083a1bb397e1164dd3e735562388fde4ff45644150
-size 16275
+oid sha256:1a96b6d95b8941d80035b309444b9eaa038098fb16aa84dec209fc3ee215ac9e
+size 21687
diff --git a/tests/uitests/src/test/snapshots/images/libraries.designsystem.components.avatar_Avatar_Avatars_105_en.png b/tests/uitests/src/test/snapshots/images/libraries.designsystem.components.avatar_Avatar_Avatars_105_en.png
new file mode 100644
index 0000000000..7f55d277d5
--- /dev/null
+++ b/tests/uitests/src/test/snapshots/images/libraries.designsystem.components.avatar_Avatar_Avatars_105_en.png
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:8da97746633081690a09a79e3f9974257bbe0f292ad5b8ee2eed454c1273c01e
+size 19747
diff --git a/tests/uitests/src/test/snapshots/images/libraries.designsystem.components.avatar_Avatar_Avatars_106_en.png b/tests/uitests/src/test/snapshots/images/libraries.designsystem.components.avatar_Avatar_Avatars_106_en.png
new file mode 100644
index 0000000000..91a2bc23da
--- /dev/null
+++ b/tests/uitests/src/test/snapshots/images/libraries.designsystem.components.avatar_Avatar_Avatars_106_en.png
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:1aaa84f80b3691ed83308966e53deb8dbc97c7943d2f68a8036a6ead603ea627
+size 18270
diff --git a/tests/uitests/src/test/snapshots/images/libraries.designsystem.components.avatar_Avatar_Avatars_107_en.png b/tests/uitests/src/test/snapshots/images/libraries.designsystem.components.avatar_Avatar_Avatars_107_en.png
new file mode 100644
index 0000000000..a2cd42670a
--- /dev/null
+++ b/tests/uitests/src/test/snapshots/images/libraries.designsystem.components.avatar_Avatar_Avatars_107_en.png
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:ddaae721cac21a188dc3862e3e14e80eeb13c92826bccfb8364ecbd72948d9bd
+size 23653
diff --git a/tests/uitests/src/test/snapshots/images/libraries.designsystem.components.avatar_Avatar_Avatars_108_en.png b/tests/uitests/src/test/snapshots/images/libraries.designsystem.components.avatar_Avatar_Avatars_108_en.png
new file mode 100644
index 0000000000..885a613f50
--- /dev/null
+++ b/tests/uitests/src/test/snapshots/images/libraries.designsystem.components.avatar_Avatar_Avatars_108_en.png
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:207d569640554b3b11cadb03a231ae0dfd85a3c470695cc8428cb2e295d98776
+size 18858
diff --git a/tests/uitests/src/test/snapshots/images/libraries.designsystem.components.avatar_Avatar_Avatars_109_en.png b/tests/uitests/src/test/snapshots/images/libraries.designsystem.components.avatar_Avatar_Avatars_109_en.png
new file mode 100644
index 0000000000..4279c36d24
--- /dev/null
+++ b/tests/uitests/src/test/snapshots/images/libraries.designsystem.components.avatar_Avatar_Avatars_109_en.png
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:68ae347075a6bef936e9c905a12b6b561a01737ab886436d73f4987783a1b45f
+size 17541
diff --git a/tests/uitests/src/test/snapshots/images/libraries.designsystem.components.avatar_Avatar_Avatars_110_en.png b/tests/uitests/src/test/snapshots/images/libraries.designsystem.components.avatar_Avatar_Avatars_110_en.png
new file mode 100644
index 0000000000..1ff47d58e0
--- /dev/null
+++ b/tests/uitests/src/test/snapshots/images/libraries.designsystem.components.avatar_Avatar_Avatars_110_en.png
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:8caa1fbeb5250684363a21549cdcfff60489059c9d1f0ca115503e63675b3511
+size 22394
diff --git a/tests/uitests/src/test/snapshots/images/libraries.designsystem.components.avatar_Avatar_Avatars_111_en.png b/tests/uitests/src/test/snapshots/images/libraries.designsystem.components.avatar_Avatar_Avatars_111_en.png
new file mode 100644
index 0000000000..7946dc4e91
--- /dev/null
+++ b/tests/uitests/src/test/snapshots/images/libraries.designsystem.components.avatar_Avatar_Avatars_111_en.png
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:ce1aba18ea8a6b45d9c40de9af961952e261c7c6200ab13cdfa67906d995208b
+size 14888
diff --git a/tests/uitests/src/test/snapshots/images/libraries.designsystem.components.avatar_Avatar_Avatars_112_en.png b/tests/uitests/src/test/snapshots/images/libraries.designsystem.components.avatar_Avatar_Avatars_112_en.png
new file mode 100644
index 0000000000..0b12b366b9
--- /dev/null
+++ b/tests/uitests/src/test/snapshots/images/libraries.designsystem.components.avatar_Avatar_Avatars_112_en.png
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:6a4d295ae71ba2709845312b84983b79348069ded46b30091b9fa769a587cbb7
+size 14337
diff --git a/tests/uitests/src/test/snapshots/images/libraries.designsystem.components.avatar_Avatar_Avatars_113_en.png b/tests/uitests/src/test/snapshots/images/libraries.designsystem.components.avatar_Avatar_Avatars_113_en.png
new file mode 100644
index 0000000000..556cb141b0
--- /dev/null
+++ b/tests/uitests/src/test/snapshots/images/libraries.designsystem.components.avatar_Avatar_Avatars_113_en.png
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:da8f54591a52475c6f47fa083a1bb397e1164dd3e735562388fde4ff45644150
+size 16275
diff --git a/tests/uitests/src/test/snapshots/images/libraries.designsystem.components.avatar_Avatar_Avatars_45_en.png b/tests/uitests/src/test/snapshots/images/libraries.designsystem.components.avatar_Avatar_Avatars_45_en.png
index a50251b367..38de31dfeb 100644
--- a/tests/uitests/src/test/snapshots/images/libraries.designsystem.components.avatar_Avatar_Avatars_45_en.png
+++ b/tests/uitests/src/test/snapshots/images/libraries.designsystem.components.avatar_Avatar_Avatars_45_en.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:fd18a15bc49e87b8abc9231a13771a0fe34003b11fe1fd48df2d91f54bc40cc8
-size 15564
+oid sha256:3d5ed3a4c0340d904404c1ef68e7391e1303f865d15e88de6f82ed68e8dc4b4c
+size 19463
diff --git a/tests/uitests/src/test/snapshots/images/libraries.designsystem.components.avatar_Avatar_Avatars_46_en.png b/tests/uitests/src/test/snapshots/images/libraries.designsystem.components.avatar_Avatar_Avatars_46_en.png
index 2ec96aeb8a..7024a8cc93 100644
--- a/tests/uitests/src/test/snapshots/images/libraries.designsystem.components.avatar_Avatar_Avatars_46_en.png
+++ b/tests/uitests/src/test/snapshots/images/libraries.designsystem.components.avatar_Avatar_Avatars_46_en.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:388a1ac9f1790fd305fd329b73ae621093d323db3fa4d4d32eef92f8dd5b51ec
-size 14824
+oid sha256:c44464ab02dd9f1fc0624f2110bc9938c8aa8856bdad811aafa05eff2e144e4a
+size 18884
diff --git a/tests/uitests/src/test/snapshots/images/libraries.designsystem.components.avatar_Avatar_Avatars_47_en.png b/tests/uitests/src/test/snapshots/images/libraries.designsystem.components.avatar_Avatar_Avatars_47_en.png
index c07dc719a8..a9d29c9fc3 100644
--- a/tests/uitests/src/test/snapshots/images/libraries.designsystem.components.avatar_Avatar_Avatars_47_en.png
+++ b/tests/uitests/src/test/snapshots/images/libraries.designsystem.components.avatar_Avatar_Avatars_47_en.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:bc90e78d2fa94425322895028f1156bfda196ee2a761231920c6ffd80f02984b
-size 17512
+oid sha256:57145b520f6702934571122f4c243f8740658847c0c60e6f901179d1d420d16a
+size 20857
diff --git a/tests/uitests/src/test/snapshots/images/libraries.designsystem.components.avatar_Avatar_Avatars_48_en.png b/tests/uitests/src/test/snapshots/images/libraries.designsystem.components.avatar_Avatar_Avatars_48_en.png
index 33fa6946a2..a50251b367 100644
--- a/tests/uitests/src/test/snapshots/images/libraries.designsystem.components.avatar_Avatar_Avatars_48_en.png
+++ b/tests/uitests/src/test/snapshots/images/libraries.designsystem.components.avatar_Avatar_Avatars_48_en.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:74fda6437495995876f76dc1ff0e056de4937ef8d719b3be1ce73baccd31516e
-size 15889
+oid sha256:fd18a15bc49e87b8abc9231a13771a0fe34003b11fe1fd48df2d91f54bc40cc8
+size 15564
diff --git a/tests/uitests/src/test/snapshots/images/libraries.designsystem.components.avatar_Avatar_Avatars_49_en.png b/tests/uitests/src/test/snapshots/images/libraries.designsystem.components.avatar_Avatar_Avatars_49_en.png
index 2a2ed97c47..2ec96aeb8a 100644
--- a/tests/uitests/src/test/snapshots/images/libraries.designsystem.components.avatar_Avatar_Avatars_49_en.png
+++ b/tests/uitests/src/test/snapshots/images/libraries.designsystem.components.avatar_Avatar_Avatars_49_en.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:04fb2f230a09f0d3e27e151d98aa5d91e416b5ca9637b4db5d8e00118a68e7c4
-size 15166
+oid sha256:388a1ac9f1790fd305fd329b73ae621093d323db3fa4d4d32eef92f8dd5b51ec
+size 14824
diff --git a/tests/uitests/src/test/snapshots/images/libraries.designsystem.components.avatar_Avatar_Avatars_50_en.png b/tests/uitests/src/test/snapshots/images/libraries.designsystem.components.avatar_Avatar_Avatars_50_en.png
index 233b0baf35..c07dc719a8 100644
--- a/tests/uitests/src/test/snapshots/images/libraries.designsystem.components.avatar_Avatar_Avatars_50_en.png
+++ b/tests/uitests/src/test/snapshots/images/libraries.designsystem.components.avatar_Avatar_Avatars_50_en.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:896f698ef11d8a0577baf0a81cb54cabc307d95d05c230e5e3bdde40c3dc0900
-size 17844
+oid sha256:bc90e78d2fa94425322895028f1156bfda196ee2a761231920c6ffd80f02984b
+size 17512
diff --git a/tests/uitests/src/test/snapshots/images/libraries.designsystem.components.avatar_Avatar_Avatars_51_en.png b/tests/uitests/src/test/snapshots/images/libraries.designsystem.components.avatar_Avatar_Avatars_51_en.png
index 20cd179751..33fa6946a2 100644
--- a/tests/uitests/src/test/snapshots/images/libraries.designsystem.components.avatar_Avatar_Avatars_51_en.png
+++ b/tests/uitests/src/test/snapshots/images/libraries.designsystem.components.avatar_Avatar_Avatars_51_en.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:cf264b6f8af5b7432511d595ff8c663c5e2be33c9f85268627f5188e3f0f8db0
-size 18949
+oid sha256:74fda6437495995876f76dc1ff0e056de4937ef8d719b3be1ce73baccd31516e
+size 15889
diff --git a/tests/uitests/src/test/snapshots/images/libraries.designsystem.components.avatar_Avatar_Avatars_52_en.png b/tests/uitests/src/test/snapshots/images/libraries.designsystem.components.avatar_Avatar_Avatars_52_en.png
index 304c73c954..2a2ed97c47 100644
--- a/tests/uitests/src/test/snapshots/images/libraries.designsystem.components.avatar_Avatar_Avatars_52_en.png
+++ b/tests/uitests/src/test/snapshots/images/libraries.designsystem.components.avatar_Avatar_Avatars_52_en.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:0bbe1e3e8e1ea119cc61509617d3fa8e2bd047f619c41271901c73c46be1d610
-size 18201
+oid sha256:04fb2f230a09f0d3e27e151d98aa5d91e416b5ca9637b4db5d8e00118a68e7c4
+size 15166
diff --git a/tests/uitests/src/test/snapshots/images/libraries.designsystem.components.avatar_Avatar_Avatars_53_en.png b/tests/uitests/src/test/snapshots/images/libraries.designsystem.components.avatar_Avatar_Avatars_53_en.png
index 397c9c40c1..233b0baf35 100644
--- a/tests/uitests/src/test/snapshots/images/libraries.designsystem.components.avatar_Avatar_Avatars_53_en.png
+++ b/tests/uitests/src/test/snapshots/images/libraries.designsystem.components.avatar_Avatar_Avatars_53_en.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:7a7c183808801645e285dfba563c036c204a347de20b4b1e40fcfeab29fafb7d
-size 20876
+oid sha256:896f698ef11d8a0577baf0a81cb54cabc307d95d05c230e5e3bdde40c3dc0900
+size 17844
diff --git a/tests/uitests/src/test/snapshots/images/libraries.designsystem.components.avatar_Avatar_Avatars_54_en.png b/tests/uitests/src/test/snapshots/images/libraries.designsystem.components.avatar_Avatar_Avatars_54_en.png
index 559903c1ac..20cd179751 100644
--- a/tests/uitests/src/test/snapshots/images/libraries.designsystem.components.avatar_Avatar_Avatars_54_en.png
+++ b/tests/uitests/src/test/snapshots/images/libraries.designsystem.components.avatar_Avatar_Avatars_54_en.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:a48eb99f4466e3a883c0c7441006f201e0db22fd0e920ad0a77a8512637e01bb
-size 16445
+oid sha256:cf264b6f8af5b7432511d595ff8c663c5e2be33c9f85268627f5188e3f0f8db0
+size 18949
diff --git a/tests/uitests/src/test/snapshots/images/libraries.designsystem.components.avatar_Avatar_Avatars_55_en.png b/tests/uitests/src/test/snapshots/images/libraries.designsystem.components.avatar_Avatar_Avatars_55_en.png
index 42cab93666..304c73c954 100644
--- a/tests/uitests/src/test/snapshots/images/libraries.designsystem.components.avatar_Avatar_Avatars_55_en.png
+++ b/tests/uitests/src/test/snapshots/images/libraries.designsystem.components.avatar_Avatar_Avatars_55_en.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:895ba9a35b8854d5005fc0671a7e6cbba5e26525b4a8ed4fa0fb612432caa04e
-size 15205
+oid sha256:0bbe1e3e8e1ea119cc61509617d3fa8e2bd047f619c41271901c73c46be1d610
+size 18201
diff --git a/tests/uitests/src/test/snapshots/images/libraries.designsystem.components.avatar_Avatar_Avatars_56_en.png b/tests/uitests/src/test/snapshots/images/libraries.designsystem.components.avatar_Avatar_Avatars_56_en.png
index bb704942db..397c9c40c1 100644
--- a/tests/uitests/src/test/snapshots/images/libraries.designsystem.components.avatar_Avatar_Avatars_56_en.png
+++ b/tests/uitests/src/test/snapshots/images/libraries.designsystem.components.avatar_Avatar_Avatars_56_en.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:98baed819cd8b08085ceabf7dbccccc77b0fdf0d28a3f852879f6f8aa02ee441
-size 19848
+oid sha256:7a7c183808801645e285dfba563c036c204a347de20b4b1e40fcfeab29fafb7d
+size 20876
diff --git a/tests/uitests/src/test/snapshots/images/libraries.designsystem.components.avatar_Avatar_Avatars_57_en.png b/tests/uitests/src/test/snapshots/images/libraries.designsystem.components.avatar_Avatar_Avatars_57_en.png
index 7f42bdc985..559903c1ac 100644
--- a/tests/uitests/src/test/snapshots/images/libraries.designsystem.components.avatar_Avatar_Avatars_57_en.png
+++ b/tests/uitests/src/test/snapshots/images/libraries.designsystem.components.avatar_Avatar_Avatars_57_en.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:c4678c15b608547c255d5eeb128c144ae7a3c5a21de2b047fc77f15364822ac2
-size 12847
+oid sha256:a48eb99f4466e3a883c0c7441006f201e0db22fd0e920ad0a77a8512637e01bb
+size 16445
diff --git a/tests/uitests/src/test/snapshots/images/libraries.designsystem.components.avatar_Avatar_Avatars_58_en.png b/tests/uitests/src/test/snapshots/images/libraries.designsystem.components.avatar_Avatar_Avatars_58_en.png
index efb2ef5625..42cab93666 100644
--- a/tests/uitests/src/test/snapshots/images/libraries.designsystem.components.avatar_Avatar_Avatars_58_en.png
+++ b/tests/uitests/src/test/snapshots/images/libraries.designsystem.components.avatar_Avatar_Avatars_58_en.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:5e30395594c1a35d90fc0a04af340eb79cbe686d90856414d0024b769f86e89d
-size 12507
+oid sha256:895ba9a35b8854d5005fc0671a7e6cbba5e26525b4a8ed4fa0fb612432caa04e
+size 15205
diff --git a/tests/uitests/src/test/snapshots/images/libraries.designsystem.components.avatar_Avatar_Avatars_59_en.png b/tests/uitests/src/test/snapshots/images/libraries.designsystem.components.avatar_Avatar_Avatars_59_en.png
index d49a629afa..bb704942db 100644
--- a/tests/uitests/src/test/snapshots/images/libraries.designsystem.components.avatar_Avatar_Avatars_59_en.png
+++ b/tests/uitests/src/test/snapshots/images/libraries.designsystem.components.avatar_Avatar_Avatars_59_en.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:60362244c7adf3644ed2ae354643e0525aad2a4454f6b13abce8fd265f4987c6
-size 13777
+oid sha256:98baed819cd8b08085ceabf7dbccccc77b0fdf0d28a3f852879f6f8aa02ee441
+size 19848
diff --git a/tests/uitests/src/test/snapshots/images/libraries.designsystem.components.avatar_Avatar_Avatars_60_en.png b/tests/uitests/src/test/snapshots/images/libraries.designsystem.components.avatar_Avatar_Avatars_60_en.png
index c7da5ce09d..7f42bdc985 100644
--- a/tests/uitests/src/test/snapshots/images/libraries.designsystem.components.avatar_Avatar_Avatars_60_en.png
+++ b/tests/uitests/src/test/snapshots/images/libraries.designsystem.components.avatar_Avatar_Avatars_60_en.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:73de8ee7933c1a45a266761b14e09b008a62dc69b1600bbc69b8a01370fb97c1
-size 18641
+oid sha256:c4678c15b608547c255d5eeb128c144ae7a3c5a21de2b047fc77f15364822ac2
+size 12847
diff --git a/tests/uitests/src/test/snapshots/images/libraries.designsystem.components.avatar_Avatar_Avatars_61_en.png b/tests/uitests/src/test/snapshots/images/libraries.designsystem.components.avatar_Avatar_Avatars_61_en.png
index f9e9999e71..efb2ef5625 100644
--- a/tests/uitests/src/test/snapshots/images/libraries.designsystem.components.avatar_Avatar_Avatars_61_en.png
+++ b/tests/uitests/src/test/snapshots/images/libraries.designsystem.components.avatar_Avatar_Avatars_61_en.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:b62b7dc22bfc727cfcbf7f6a19683bcf4da116c7192f9943f5addd11c39fcadb
-size 17018
+oid sha256:5e30395594c1a35d90fc0a04af340eb79cbe686d90856414d0024b769f86e89d
+size 12507
diff --git a/tests/uitests/src/test/snapshots/images/libraries.designsystem.components.avatar_Avatar_Avatars_62_en.png b/tests/uitests/src/test/snapshots/images/libraries.designsystem.components.avatar_Avatar_Avatars_62_en.png
index 0f4930cb81..d49a629afa 100644
--- a/tests/uitests/src/test/snapshots/images/libraries.designsystem.components.avatar_Avatar_Avatars_62_en.png
+++ b/tests/uitests/src/test/snapshots/images/libraries.designsystem.components.avatar_Avatar_Avatars_62_en.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:c0855112283bf797bc846e1982c6293e321361368481a803e12658723aaf8409
-size 22988
+oid sha256:60362244c7adf3644ed2ae354643e0525aad2a4454f6b13abce8fd265f4987c6
+size 13777
diff --git a/tests/uitests/src/test/snapshots/images/libraries.designsystem.components.avatar_Avatar_Avatars_63_en.png b/tests/uitests/src/test/snapshots/images/libraries.designsystem.components.avatar_Avatar_Avatars_63_en.png
index b7e63845b6..c7da5ce09d 100644
--- a/tests/uitests/src/test/snapshots/images/libraries.designsystem.components.avatar_Avatar_Avatars_63_en.png
+++ b/tests/uitests/src/test/snapshots/images/libraries.designsystem.components.avatar_Avatar_Avatars_63_en.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:049b3ac784a8e400bad374a960ecb77d7f4bca81079be764dc74cb161f7a1093
-size 20880
+oid sha256:73de8ee7933c1a45a266761b14e09b008a62dc69b1600bbc69b8a01370fb97c1
+size 18641
diff --git a/tests/uitests/src/test/snapshots/images/libraries.designsystem.components.avatar_Avatar_Avatars_64_en.png b/tests/uitests/src/test/snapshots/images/libraries.designsystem.components.avatar_Avatar_Avatars_64_en.png
index 517de9d5bd..f9e9999e71 100644
--- a/tests/uitests/src/test/snapshots/images/libraries.designsystem.components.avatar_Avatar_Avatars_64_en.png
+++ b/tests/uitests/src/test/snapshots/images/libraries.designsystem.components.avatar_Avatar_Avatars_64_en.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:21d83d719bee5fd19ad090791c7848890d87e4bd9eaddb17c9da1773ec81667f
-size 19249
+oid sha256:b62b7dc22bfc727cfcbf7f6a19683bcf4da116c7192f9943f5addd11c39fcadb
+size 17018
diff --git a/tests/uitests/src/test/snapshots/images/libraries.designsystem.components.avatar_Avatar_Avatars_65_en.png b/tests/uitests/src/test/snapshots/images/libraries.designsystem.components.avatar_Avatar_Avatars_65_en.png
index e39f788f2a..0f4930cb81 100644
--- a/tests/uitests/src/test/snapshots/images/libraries.designsystem.components.avatar_Avatar_Avatars_65_en.png
+++ b/tests/uitests/src/test/snapshots/images/libraries.designsystem.components.avatar_Avatar_Avatars_65_en.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:edc743a5cd067eb13e464f27c2f12f95433bd020dd1b3e920614ee913e06e476
-size 25008
+oid sha256:c0855112283bf797bc846e1982c6293e321361368481a803e12658723aaf8409
+size 22988
diff --git a/tests/uitests/src/test/snapshots/images/libraries.designsystem.components.avatar_Avatar_Avatars_66_en.png b/tests/uitests/src/test/snapshots/images/libraries.designsystem.components.avatar_Avatar_Avatars_66_en.png
index 71ba87addd..b7e63845b6 100644
--- a/tests/uitests/src/test/snapshots/images/libraries.designsystem.components.avatar_Avatar_Avatars_66_en.png
+++ b/tests/uitests/src/test/snapshots/images/libraries.designsystem.components.avatar_Avatar_Avatars_66_en.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:45e6821d622bfef22cc41a040e12e2b49e0bb50a88b0a143bdb25e3368809412
-size 16496
+oid sha256:049b3ac784a8e400bad374a960ecb77d7f4bca81079be764dc74cb161f7a1093
+size 20880
diff --git a/tests/uitests/src/test/snapshots/images/libraries.designsystem.components.avatar_Avatar_Avatars_67_en.png b/tests/uitests/src/test/snapshots/images/libraries.designsystem.components.avatar_Avatar_Avatars_67_en.png
index c00f6f274d..517de9d5bd 100644
--- a/tests/uitests/src/test/snapshots/images/libraries.designsystem.components.avatar_Avatar_Avatars_67_en.png
+++ b/tests/uitests/src/test/snapshots/images/libraries.designsystem.components.avatar_Avatar_Avatars_67_en.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:6ddd2399d3d701fa962dc5683e054c2c4829ccd99d04498415ce88487f5e0ec8
-size 15760
+oid sha256:21d83d719bee5fd19ad090791c7848890d87e4bd9eaddb17c9da1773ec81667f
+size 19249
diff --git a/tests/uitests/src/test/snapshots/images/libraries.designsystem.components.avatar_Avatar_Avatars_68_en.png b/tests/uitests/src/test/snapshots/images/libraries.designsystem.components.avatar_Avatar_Avatars_68_en.png
index c6917d9519..e39f788f2a 100644
--- a/tests/uitests/src/test/snapshots/images/libraries.designsystem.components.avatar_Avatar_Avatars_68_en.png
+++ b/tests/uitests/src/test/snapshots/images/libraries.designsystem.components.avatar_Avatar_Avatars_68_en.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:4293d98ed31f87c59ff5741344c2e41f58ff8f19c9342f6626553e978dbfc674
-size 18429
+oid sha256:edc743a5cd067eb13e464f27c2f12f95433bd020dd1b3e920614ee913e06e476
+size 25008
diff --git a/tests/uitests/src/test/snapshots/images/libraries.designsystem.components.avatar_Avatar_Avatars_69_en.png b/tests/uitests/src/test/snapshots/images/libraries.designsystem.components.avatar_Avatar_Avatars_69_en.png
index 439c8e754f..71ba87addd 100644
--- a/tests/uitests/src/test/snapshots/images/libraries.designsystem.components.avatar_Avatar_Avatars_69_en.png
+++ b/tests/uitests/src/test/snapshots/images/libraries.designsystem.components.avatar_Avatar_Avatars_69_en.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:37d1e302d4a610aaab7cfc6a15572b7eb92b059d9384e7bbe4daebcaf2da9049
-size 21343
+oid sha256:45e6821d622bfef22cc41a040e12e2b49e0bb50a88b0a143bdb25e3368809412
+size 16496
diff --git a/tests/uitests/src/test/snapshots/images/libraries.designsystem.components.avatar_Avatar_Avatars_6_en.png b/tests/uitests/src/test/snapshots/images/libraries.designsystem.components.avatar_Avatar_Avatars_6_en.png
index 0622e6c69b..1bf67b7c98 100644
--- a/tests/uitests/src/test/snapshots/images/libraries.designsystem.components.avatar_Avatar_Avatars_6_en.png
+++ b/tests/uitests/src/test/snapshots/images/libraries.designsystem.components.avatar_Avatar_Avatars_6_en.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:3f52fa29e031ab362baed77ac18228960d67eb5d6bdf909b6c1fb3777f5eacc5
-size 19629
+oid sha256:8cb143e42d0bc07652d74c74ba641a5332ee9bebb071fa5efba59ecacad04be5
+size 21857
diff --git a/tests/uitests/src/test/snapshots/images/libraries.designsystem.components.avatar_Avatar_Avatars_70_en.png b/tests/uitests/src/test/snapshots/images/libraries.designsystem.components.avatar_Avatar_Avatars_70_en.png
index 19347bbaaa..c00f6f274d 100644
--- a/tests/uitests/src/test/snapshots/images/libraries.designsystem.components.avatar_Avatar_Avatars_70_en.png
+++ b/tests/uitests/src/test/snapshots/images/libraries.designsystem.components.avatar_Avatar_Avatars_70_en.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:536d8d899945483352137d23356f3777db8e2225288f01e8cbcd1a770ca7f3ee
-size 20494
+oid sha256:6ddd2399d3d701fa962dc5683e054c2c4829ccd99d04498415ce88487f5e0ec8
+size 15760
diff --git a/tests/uitests/src/test/snapshots/images/libraries.designsystem.components.avatar_Avatar_Avatars_71_en.png b/tests/uitests/src/test/snapshots/images/libraries.designsystem.components.avatar_Avatar_Avatars_71_en.png
index 3a5d6c57ad..c6917d9519 100644
--- a/tests/uitests/src/test/snapshots/images/libraries.designsystem.components.avatar_Avatar_Avatars_71_en.png
+++ b/tests/uitests/src/test/snapshots/images/libraries.designsystem.components.avatar_Avatar_Avatars_71_en.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:542b080ae9374e4f6d57689b1e1b6a84a0f81f017bd276bbcab43b9659be4335
-size 23534
+oid sha256:4293d98ed31f87c59ff5741344c2e41f58ff8f19c9342f6626553e978dbfc674
+size 18429
diff --git a/tests/uitests/src/test/snapshots/images/libraries.designsystem.components.avatar_Avatar_Avatars_72_en.png b/tests/uitests/src/test/snapshots/images/libraries.designsystem.components.avatar_Avatar_Avatars_72_en.png
index c116d68c19..439c8e754f 100644
--- a/tests/uitests/src/test/snapshots/images/libraries.designsystem.components.avatar_Avatar_Avatars_72_en.png
+++ b/tests/uitests/src/test/snapshots/images/libraries.designsystem.components.avatar_Avatar_Avatars_72_en.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:aeb02390258eade3ceb8c437bcf3592f3dde463d6f1b2a43ffefd61abf4184c4
-size 17236
+oid sha256:37d1e302d4a610aaab7cfc6a15572b7eb92b059d9384e7bbe4daebcaf2da9049
+size 21343
diff --git a/tests/uitests/src/test/snapshots/images/libraries.designsystem.components.avatar_Avatar_Avatars_73_en.png b/tests/uitests/src/test/snapshots/images/libraries.designsystem.components.avatar_Avatar_Avatars_73_en.png
index 04ec60caeb..19347bbaaa 100644
--- a/tests/uitests/src/test/snapshots/images/libraries.designsystem.components.avatar_Avatar_Avatars_73_en.png
+++ b/tests/uitests/src/test/snapshots/images/libraries.designsystem.components.avatar_Avatar_Avatars_73_en.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:d5c6bfe22fb71a9c6353718c2124000245182359ac1c43dfc8dd9b91415e66e6
-size 16385
+oid sha256:536d8d899945483352137d23356f3777db8e2225288f01e8cbcd1a770ca7f3ee
+size 20494
diff --git a/tests/uitests/src/test/snapshots/images/libraries.designsystem.components.avatar_Avatar_Avatars_74_en.png b/tests/uitests/src/test/snapshots/images/libraries.designsystem.components.avatar_Avatar_Avatars_74_en.png
index e74e8a07b8..3a5d6c57ad 100644
--- a/tests/uitests/src/test/snapshots/images/libraries.designsystem.components.avatar_Avatar_Avatars_74_en.png
+++ b/tests/uitests/src/test/snapshots/images/libraries.designsystem.components.avatar_Avatar_Avatars_74_en.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:408f90e8a2f4dcd0716118fb522e5cd4adba0b2a429723fc2e47555b82acf005
-size 19501
+oid sha256:542b080ae9374e4f6d57689b1e1b6a84a0f81f017bd276bbcab43b9659be4335
+size 23534
diff --git a/tests/uitests/src/test/snapshots/images/libraries.designsystem.components.avatar_Avatar_Avatars_75_en.png b/tests/uitests/src/test/snapshots/images/libraries.designsystem.components.avatar_Avatar_Avatars_75_en.png
index 84b6c56c0e..c116d68c19 100644
--- a/tests/uitests/src/test/snapshots/images/libraries.designsystem.components.avatar_Avatar_Avatars_75_en.png
+++ b/tests/uitests/src/test/snapshots/images/libraries.designsystem.components.avatar_Avatar_Avatars_75_en.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:9778edbbb33ab0bbaa0072bd4659488937efe0f8b8fac0a5b64497fe6a1e28e2
-size 20838
+oid sha256:aeb02390258eade3ceb8c437bcf3592f3dde463d6f1b2a43ffefd61abf4184c4
+size 17236
diff --git a/tests/uitests/src/test/snapshots/images/libraries.designsystem.components.avatar_Avatar_Avatars_76_en.png b/tests/uitests/src/test/snapshots/images/libraries.designsystem.components.avatar_Avatar_Avatars_76_en.png
index aa9b310163..04ec60caeb 100644
--- a/tests/uitests/src/test/snapshots/images/libraries.designsystem.components.avatar_Avatar_Avatars_76_en.png
+++ b/tests/uitests/src/test/snapshots/images/libraries.designsystem.components.avatar_Avatar_Avatars_76_en.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:97f43860bf9e65c7822943f8806a0642ce59957be5e35650e2b69a2c562a694c
-size 18637
+oid sha256:d5c6bfe22fb71a9c6353718c2124000245182359ac1c43dfc8dd9b91415e66e6
+size 16385
diff --git a/tests/uitests/src/test/snapshots/images/libraries.designsystem.components.avatar_Avatar_Avatars_77_en.png b/tests/uitests/src/test/snapshots/images/libraries.designsystem.components.avatar_Avatar_Avatars_77_en.png
index 3e54c2ace5..e74e8a07b8 100644
--- a/tests/uitests/src/test/snapshots/images/libraries.designsystem.components.avatar_Avatar_Avatars_77_en.png
+++ b/tests/uitests/src/test/snapshots/images/libraries.designsystem.components.avatar_Avatar_Avatars_77_en.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:77e71b006b71300ccb1005ad3cac6a93ae242ff03f2936fdf9d10c0604d20faa
-size 26121
+oid sha256:408f90e8a2f4dcd0716118fb522e5cd4adba0b2a429723fc2e47555b82acf005
+size 19501
diff --git a/tests/uitests/src/test/snapshots/images/libraries.designsystem.components.avatar_Avatar_Avatars_78_en.png b/tests/uitests/src/test/snapshots/images/libraries.designsystem.components.avatar_Avatar_Avatars_78_en.png
index b2eb2208d7..84b6c56c0e 100644
--- a/tests/uitests/src/test/snapshots/images/libraries.designsystem.components.avatar_Avatar_Avatars_78_en.png
+++ b/tests/uitests/src/test/snapshots/images/libraries.designsystem.components.avatar_Avatar_Avatars_78_en.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:e744d3fe3315dc6cb5beab80dc29d565500367772339071575b6505370e47207
-size 14771
+oid sha256:9778edbbb33ab0bbaa0072bd4659488937efe0f8b8fac0a5b64497fe6a1e28e2
+size 20838
diff --git a/tests/uitests/src/test/snapshots/images/libraries.designsystem.components.avatar_Avatar_Avatars_79_en.png b/tests/uitests/src/test/snapshots/images/libraries.designsystem.components.avatar_Avatar_Avatars_79_en.png
index 5dd29ba5c0..aa9b310163 100644
--- a/tests/uitests/src/test/snapshots/images/libraries.designsystem.components.avatar_Avatar_Avatars_79_en.png
+++ b/tests/uitests/src/test/snapshots/images/libraries.designsystem.components.avatar_Avatar_Avatars_79_en.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:448ea365e3e75059bc888961e3454562d35ab116c75b3b9855723b5fc1480d92
-size 14028
+oid sha256:97f43860bf9e65c7822943f8806a0642ce59957be5e35650e2b69a2c562a694c
+size 18637
diff --git a/tests/uitests/src/test/snapshots/images/libraries.designsystem.components.avatar_Avatar_Avatars_7_en.png b/tests/uitests/src/test/snapshots/images/libraries.designsystem.components.avatar_Avatar_Avatars_7_en.png
index dccb49ff50..3db35531c4 100644
--- a/tests/uitests/src/test/snapshots/images/libraries.designsystem.components.avatar_Avatar_Avatars_7_en.png
+++ b/tests/uitests/src/test/snapshots/images/libraries.designsystem.components.avatar_Avatar_Avatars_7_en.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:4b6a0bdd2239b473f541e95588f2531a2761d0d9872cda61cdd87e2e195b14cf
-size 17425
+oid sha256:5eecc64fbbf67e53578ba6c974905c16d000a5dc8b2e0fa99c41e46dea36424b
+size 19651
diff --git a/tests/uitests/src/test/snapshots/images/libraries.designsystem.components.avatar_Avatar_Avatars_80_en.png b/tests/uitests/src/test/snapshots/images/libraries.designsystem.components.avatar_Avatar_Avatars_80_en.png
index 4985f409fd..3e54c2ace5 100644
--- a/tests/uitests/src/test/snapshots/images/libraries.designsystem.components.avatar_Avatar_Avatars_80_en.png
+++ b/tests/uitests/src/test/snapshots/images/libraries.designsystem.components.avatar_Avatar_Avatars_80_en.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:ad98105fcd6d6c02e5ae036ad49770b4aa35d94e32ab3a63f040deccc2375e6e
-size 16703
+oid sha256:77e71b006b71300ccb1005ad3cac6a93ae242ff03f2936fdf9d10c0604d20faa
+size 26121
diff --git a/tests/uitests/src/test/snapshots/images/libraries.designsystem.components.avatar_Avatar_Avatars_81_en.png b/tests/uitests/src/test/snapshots/images/libraries.designsystem.components.avatar_Avatar_Avatars_81_en.png
index e34b1d369a..b2eb2208d7 100644
--- a/tests/uitests/src/test/snapshots/images/libraries.designsystem.components.avatar_Avatar_Avatars_81_en.png
+++ b/tests/uitests/src/test/snapshots/images/libraries.designsystem.components.avatar_Avatar_Avatars_81_en.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:5b8e747d51d6a6ab1ab6ff80224d0241a16f38b39e0c156dc6eef47ea56eca63
-size 18140
+oid sha256:e744d3fe3315dc6cb5beab80dc29d565500367772339071575b6505370e47207
+size 14771
diff --git a/tests/uitests/src/test/snapshots/images/libraries.designsystem.components.avatar_Avatar_Avatars_82_en.png b/tests/uitests/src/test/snapshots/images/libraries.designsystem.components.avatar_Avatar_Avatars_82_en.png
index fcf2962f34..5dd29ba5c0 100644
--- a/tests/uitests/src/test/snapshots/images/libraries.designsystem.components.avatar_Avatar_Avatars_82_en.png
+++ b/tests/uitests/src/test/snapshots/images/libraries.designsystem.components.avatar_Avatar_Avatars_82_en.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:34f28c6dbbe094b9ba070c6f1ef4b10b2625ea094629b6305dff70bdf6367ddc
-size 16894
+oid sha256:448ea365e3e75059bc888961e3454562d35ab116c75b3b9855723b5fc1480d92
+size 14028
diff --git a/tests/uitests/src/test/snapshots/images/libraries.designsystem.components.avatar_Avatar_Avatars_83_en.png b/tests/uitests/src/test/snapshots/images/libraries.designsystem.components.avatar_Avatar_Avatars_83_en.png
index 8e996d615c..4985f409fd 100644
--- a/tests/uitests/src/test/snapshots/images/libraries.designsystem.components.avatar_Avatar_Avatars_83_en.png
+++ b/tests/uitests/src/test/snapshots/images/libraries.designsystem.components.avatar_Avatar_Avatars_83_en.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:ccfe44da86dce16ba4816cfe2029c05d317fe29ca3bb816278f2bd929298d855
-size 21532
+oid sha256:ad98105fcd6d6c02e5ae036ad49770b4aa35d94e32ab3a63f040deccc2375e6e
+size 16703
diff --git a/tests/uitests/src/test/snapshots/images/libraries.designsystem.components.avatar_Avatar_Avatars_84_en.png b/tests/uitests/src/test/snapshots/images/libraries.designsystem.components.avatar_Avatar_Avatars_84_en.png
index 54558de104..e34b1d369a 100644
--- a/tests/uitests/src/test/snapshots/images/libraries.designsystem.components.avatar_Avatar_Avatars_84_en.png
+++ b/tests/uitests/src/test/snapshots/images/libraries.designsystem.components.avatar_Avatar_Avatars_84_en.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:e5b77bec92bc7c4da3fdc72831797d685bf042131c2222351cc7c852da48cd60
-size 17662
+oid sha256:5b8e747d51d6a6ab1ab6ff80224d0241a16f38b39e0c156dc6eef47ea56eca63
+size 18140
diff --git a/tests/uitests/src/test/snapshots/images/libraries.designsystem.components.avatar_Avatar_Avatars_85_en.png b/tests/uitests/src/test/snapshots/images/libraries.designsystem.components.avatar_Avatar_Avatars_85_en.png
index d36db47fcc..fcf2962f34 100644
--- a/tests/uitests/src/test/snapshots/images/libraries.designsystem.components.avatar_Avatar_Avatars_85_en.png
+++ b/tests/uitests/src/test/snapshots/images/libraries.designsystem.components.avatar_Avatar_Avatars_85_en.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:99f2b0e2fda05d6fa16c0f2dcc52e92f6fa1c656c6d84cf03e8507a5c14104e8
-size 16932
+oid sha256:34f28c6dbbe094b9ba070c6f1ef4b10b2625ea094629b6305dff70bdf6367ddc
+size 16894
diff --git a/tests/uitests/src/test/snapshots/images/libraries.designsystem.components.avatar_Avatar_Avatars_86_en.png b/tests/uitests/src/test/snapshots/images/libraries.designsystem.components.avatar_Avatar_Avatars_86_en.png
index e0660d56c3..8e996d615c 100644
--- a/tests/uitests/src/test/snapshots/images/libraries.designsystem.components.avatar_Avatar_Avatars_86_en.png
+++ b/tests/uitests/src/test/snapshots/images/libraries.designsystem.components.avatar_Avatar_Avatars_86_en.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:e79cb41e125705af70990dec3e3fdc0a0202ec8d62f2077eb2a298243ae2e94d
-size 19624
+oid sha256:ccfe44da86dce16ba4816cfe2029c05d317fe29ca3bb816278f2bd929298d855
+size 21532
diff --git a/tests/uitests/src/test/snapshots/images/libraries.designsystem.components.avatar_Avatar_Avatars_87_en.png b/tests/uitests/src/test/snapshots/images/libraries.designsystem.components.avatar_Avatar_Avatars_87_en.png
index bc91269c49..54558de104 100644
--- a/tests/uitests/src/test/snapshots/images/libraries.designsystem.components.avatar_Avatar_Avatars_87_en.png
+++ b/tests/uitests/src/test/snapshots/images/libraries.designsystem.components.avatar_Avatar_Avatars_87_en.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:e0faccb345f65a543c56e4db44714614915a62b6916a77a0f4adfdae5215311e
-size 15128
+oid sha256:e5b77bec92bc7c4da3fdc72831797d685bf042131c2222351cc7c852da48cd60
+size 17662
diff --git a/tests/uitests/src/test/snapshots/images/libraries.designsystem.components.avatar_Avatar_Avatars_88_en.png b/tests/uitests/src/test/snapshots/images/libraries.designsystem.components.avatar_Avatar_Avatars_88_en.png
index 259e239462..d36db47fcc 100644
--- a/tests/uitests/src/test/snapshots/images/libraries.designsystem.components.avatar_Avatar_Avatars_88_en.png
+++ b/tests/uitests/src/test/snapshots/images/libraries.designsystem.components.avatar_Avatar_Avatars_88_en.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:5d626da2924325c074dcd2baf1c112430399553a9ee652cac03b0b1d3db4cff3
-size 14393
+oid sha256:99f2b0e2fda05d6fa16c0f2dcc52e92f6fa1c656c6d84cf03e8507a5c14104e8
+size 16932
diff --git a/tests/uitests/src/test/snapshots/images/libraries.designsystem.components.avatar_Avatar_Avatars_89_en.png b/tests/uitests/src/test/snapshots/images/libraries.designsystem.components.avatar_Avatar_Avatars_89_en.png
index 2082b4df3a..e0660d56c3 100644
--- a/tests/uitests/src/test/snapshots/images/libraries.designsystem.components.avatar_Avatar_Avatars_89_en.png
+++ b/tests/uitests/src/test/snapshots/images/libraries.designsystem.components.avatar_Avatar_Avatars_89_en.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:2be7c565d30e9f45a583b93ec948a7cb35a4bc872c4f479bd1efe9eda8972e7c
-size 17044
+oid sha256:e79cb41e125705af70990dec3e3fdc0a0202ec8d62f2077eb2a298243ae2e94d
+size 19624
diff --git a/tests/uitests/src/test/snapshots/images/libraries.designsystem.components.avatar_Avatar_Avatars_8_en.png b/tests/uitests/src/test/snapshots/images/libraries.designsystem.components.avatar_Avatar_Avatars_8_en.png
index d1b6ea7f02..3f0469f5cc 100644
--- a/tests/uitests/src/test/snapshots/images/libraries.designsystem.components.avatar_Avatar_Avatars_8_en.png
+++ b/tests/uitests/src/test/snapshots/images/libraries.designsystem.components.avatar_Avatar_Avatars_8_en.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:3898d22d9de94323eb04d5385af9a1084434c521f8b51f5af74ef1159dd2d1cc
-size 25138
+oid sha256:c425ffed237de0e71451baf51f674051c3ab6481ecceeff15c7f2f73193fd3ab
+size 26866
diff --git a/tests/uitests/src/test/snapshots/images/libraries.designsystem.components.avatar_Avatar_Avatars_90_en.png b/tests/uitests/src/test/snapshots/images/libraries.designsystem.components.avatar_Avatar_Avatars_90_en.png
index 6dfa192fb9..bc91269c49 100644
--- a/tests/uitests/src/test/snapshots/images/libraries.designsystem.components.avatar_Avatar_Avatars_90_en.png
+++ b/tests/uitests/src/test/snapshots/images/libraries.designsystem.components.avatar_Avatar_Avatars_90_en.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:c28eae20f614eae53e09aa4e396792f36ee1478c8141faad788fe397502da237
-size 20671
+oid sha256:e0faccb345f65a543c56e4db44714614915a62b6916a77a0f4adfdae5215311e
+size 15128
diff --git a/tests/uitests/src/test/snapshots/images/libraries.designsystem.components.avatar_Avatar_Avatars_91_en.png b/tests/uitests/src/test/snapshots/images/libraries.designsystem.components.avatar_Avatar_Avatars_91_en.png
index b740d5c979..259e239462 100644
--- a/tests/uitests/src/test/snapshots/images/libraries.designsystem.components.avatar_Avatar_Avatars_91_en.png
+++ b/tests/uitests/src/test/snapshots/images/libraries.designsystem.components.avatar_Avatar_Avatars_91_en.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:8ada8d054436b15e9029150eb99e78103050f8d0428a1c78ef5667bfd54d3be5
-size 19195
+oid sha256:5d626da2924325c074dcd2baf1c112430399553a9ee652cac03b0b1d3db4cff3
+size 14393
diff --git a/tests/uitests/src/test/snapshots/images/libraries.designsystem.components.avatar_Avatar_Avatars_92_en.png b/tests/uitests/src/test/snapshots/images/libraries.designsystem.components.avatar_Avatar_Avatars_92_en.png
index 6b06753f70..2082b4df3a 100644
--- a/tests/uitests/src/test/snapshots/images/libraries.designsystem.components.avatar_Avatar_Avatars_92_en.png
+++ b/tests/uitests/src/test/snapshots/images/libraries.designsystem.components.avatar_Avatar_Avatars_92_en.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:7586db3dc8687c5c5fc73d28dd968041b192c160286f6a7c881eb7d86a2d1bd2
-size 24477
+oid sha256:2be7c565d30e9f45a583b93ec948a7cb35a4bc872c4f479bd1efe9eda8972e7c
+size 17044
diff --git a/tests/uitests/src/test/snapshots/images/libraries.designsystem.components.avatar_Avatar_Avatars_93_en.png b/tests/uitests/src/test/snapshots/images/libraries.designsystem.components.avatar_Avatar_Avatars_93_en.png
index 42b0241e10..6dfa192fb9 100644
--- a/tests/uitests/src/test/snapshots/images/libraries.designsystem.components.avatar_Avatar_Avatars_93_en.png
+++ b/tests/uitests/src/test/snapshots/images/libraries.designsystem.components.avatar_Avatar_Avatars_93_en.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:2ef75decb9f501eb6c1941e212e1b330203c16458bfc2e10bfac3d197b091a35
-size 17116
+oid sha256:c28eae20f614eae53e09aa4e396792f36ee1478c8141faad788fe397502da237
+size 20671
diff --git a/tests/uitests/src/test/snapshots/images/libraries.designsystem.components.avatar_Avatar_Avatars_94_en.png b/tests/uitests/src/test/snapshots/images/libraries.designsystem.components.avatar_Avatar_Avatars_94_en.png
index 04732e27fb..b740d5c979 100644
--- a/tests/uitests/src/test/snapshots/images/libraries.designsystem.components.avatar_Avatar_Avatars_94_en.png
+++ b/tests/uitests/src/test/snapshots/images/libraries.designsystem.components.avatar_Avatar_Avatars_94_en.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:4940205ca9411e3175d24d7a45a49df77b2187318d4245d902db75230838e26f
-size 15869
+oid sha256:8ada8d054436b15e9029150eb99e78103050f8d0428a1c78ef5667bfd54d3be5
+size 19195
diff --git a/tests/uitests/src/test/snapshots/images/libraries.designsystem.components.avatar_Avatar_Avatars_95_en.png b/tests/uitests/src/test/snapshots/images/libraries.designsystem.components.avatar_Avatar_Avatars_95_en.png
index a48e1ad7d3..6b06753f70 100644
--- a/tests/uitests/src/test/snapshots/images/libraries.designsystem.components.avatar_Avatar_Avatars_95_en.png
+++ b/tests/uitests/src/test/snapshots/images/libraries.designsystem.components.avatar_Avatar_Avatars_95_en.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:a1faa9029414b146707f2cd0d7c4899355cd196c3b5acd6e95ebe0d0bb599003
-size 20504
+oid sha256:7586db3dc8687c5c5fc73d28dd968041b192c160286f6a7c881eb7d86a2d1bd2
+size 24477
diff --git a/tests/uitests/src/test/snapshots/images/libraries.designsystem.components.avatar_Avatar_Avatars_96_en.png b/tests/uitests/src/test/snapshots/images/libraries.designsystem.components.avatar_Avatar_Avatars_96_en.png
index 3eeb6f47e4..42b0241e10 100644
--- a/tests/uitests/src/test/snapshots/images/libraries.designsystem.components.avatar_Avatar_Avatars_96_en.png
+++ b/tests/uitests/src/test/snapshots/images/libraries.designsystem.components.avatar_Avatar_Avatars_96_en.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:90982bf0b723b89c9b070c1dc94eb5a9fcf66623c382d496174f026e053929fb
-size 19493
+oid sha256:2ef75decb9f501eb6c1941e212e1b330203c16458bfc2e10bfac3d197b091a35
+size 17116
diff --git a/tests/uitests/src/test/snapshots/images/libraries.designsystem.components.avatar_Avatar_Avatars_97_en.png b/tests/uitests/src/test/snapshots/images/libraries.designsystem.components.avatar_Avatar_Avatars_97_en.png
index eee5b83831..04732e27fb 100644
--- a/tests/uitests/src/test/snapshots/images/libraries.designsystem.components.avatar_Avatar_Avatars_97_en.png
+++ b/tests/uitests/src/test/snapshots/images/libraries.designsystem.components.avatar_Avatar_Avatars_97_en.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:9640e8e6d758a03f995c7fbbb6c3c123109594138a7cc53d5416ef5e3e157693
-size 18006
+oid sha256:4940205ca9411e3175d24d7a45a49df77b2187318d4245d902db75230838e26f
+size 15869
diff --git a/tests/uitests/src/test/snapshots/images/libraries.designsystem.components.avatar_Avatar_Avatars_98_en.png b/tests/uitests/src/test/snapshots/images/libraries.designsystem.components.avatar_Avatar_Avatars_98_en.png
index 70c84280d6..a48e1ad7d3 100644
--- a/tests/uitests/src/test/snapshots/images/libraries.designsystem.components.avatar_Avatar_Avatars_98_en.png
+++ b/tests/uitests/src/test/snapshots/images/libraries.designsystem.components.avatar_Avatar_Avatars_98_en.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:fbe699fb17947981c53d47a9570da71e2388ec493a3a9471aaa13a5405075069
-size 23421
+oid sha256:a1faa9029414b146707f2cd0d7c4899355cd196c3b5acd6e95ebe0d0bb599003
+size 20504
diff --git a/tests/uitests/src/test/snapshots/images/libraries.designsystem.components.avatar_Avatar_Avatars_99_en.png b/tests/uitests/src/test/snapshots/images/libraries.designsystem.components.avatar_Avatar_Avatars_99_en.png
index f4e93c12ae..3eeb6f47e4 100644
--- a/tests/uitests/src/test/snapshots/images/libraries.designsystem.components.avatar_Avatar_Avatars_99_en.png
+++ b/tests/uitests/src/test/snapshots/images/libraries.designsystem.components.avatar_Avatar_Avatars_99_en.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:8c6688901f89d3858ec67dda889fe589fb6b59202c64a4b700c2aa484e19f4cd
-size 17606
+oid sha256:90982bf0b723b89c9b070c1dc94eb5a9fcf66623c382d496174f026e053929fb
+size 19493
diff --git a/tests/uitests/src/test/snapshots/images/libraries.designsystem.components_ProgressDialogWithContent_Day_0_en.png b/tests/uitests/src/test/snapshots/images/libraries.designsystem.components_ProgressDialogWithContent_Day_0_en.png
new file mode 100644
index 0000000000..d4ef5f016f
--- /dev/null
+++ b/tests/uitests/src/test/snapshots/images/libraries.designsystem.components_ProgressDialogWithContent_Day_0_en.png
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:7b637e70da73ea0fca81adb861abf69fb2092d35493417fb29103f5acebf6fa0
+size 11706
diff --git a/tests/uitests/src/test/snapshots/images/libraries.designsystem.components_ProgressDialogWithContent_Night_0_en.png b/tests/uitests/src/test/snapshots/images/libraries.designsystem.components_ProgressDialogWithContent_Night_0_en.png
new file mode 100644
index 0000000000..7e648f0530
--- /dev/null
+++ b/tests/uitests/src/test/snapshots/images/libraries.designsystem.components_ProgressDialogWithContent_Night_0_en.png
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:440b6f0e84c9fccfbbc997a40e1e8459df1962218fa4fdceb7ea8ecc8c96090b
+size 11442
diff --git a/tests/uitests/src/test/snapshots/images/libraries.designsystem.components_ProgressDialogWithTextAndContent_Day_0_en.png b/tests/uitests/src/test/snapshots/images/libraries.designsystem.components_ProgressDialogWithTextAndContent_Day_0_en.png
new file mode 100644
index 0000000000..b58b42b2d6
--- /dev/null
+++ b/tests/uitests/src/test/snapshots/images/libraries.designsystem.components_ProgressDialogWithTextAndContent_Day_0_en.png
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:b3212b09963d5fa9b89b1ebfd8f904b3f436399299e67f560f39620d063eb997
+size 11408
diff --git a/tests/uitests/src/test/snapshots/images/libraries.designsystem.components_ProgressDialogWithTextAndContent_Night_0_en.png b/tests/uitests/src/test/snapshots/images/libraries.designsystem.components_ProgressDialogWithTextAndContent_Night_0_en.png
new file mode 100644
index 0000000000..a534eae610
--- /dev/null
+++ b/tests/uitests/src/test/snapshots/images/libraries.designsystem.components_ProgressDialogWithTextAndContent_Night_0_en.png
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:ae69faa0c95f4ae4b7b410da438f0e3992571c21837e644e63621fa1f73e297a
+size 11220
diff --git a/tests/uitests/src/test/snapshots/images/libraries.designsystem.theme.components_DialogWithVeryLongTitleAndIcon_Dialog_with_a_very_long_title_and_icon_Dialogs_en.png b/tests/uitests/src/test/snapshots/images/libraries.designsystem.theme.components_DialogWithVeryLongTitleAndIcon_Dialog_with_a_very_long_title_and_icon_Dialogs_en.png
new file mode 100644
index 0000000000..460e856f24
--- /dev/null
+++ b/tests/uitests/src/test/snapshots/images/libraries.designsystem.theme.components_DialogWithVeryLongTitleAndIcon_Dialog_with_a_very_long_title_and_icon_Dialogs_en.png
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:5b77f17f245a60b74cfff9e28cb0f5d0251172332582e00f6bcf2767c867bcd8
+size 56167
diff --git a/tests/uitests/src/test/snapshots/images/libraries.designsystem.theme.components_DialogWithVeryLongTitle_Dialog_with_a_very_long_title_Dialogs_en.png b/tests/uitests/src/test/snapshots/images/libraries.designsystem.theme.components_DialogWithVeryLongTitle_Dialog_with_a_very_long_title_Dialogs_en.png
new file mode 100644
index 0000000000..f4a7fb3f40
--- /dev/null
+++ b/tests/uitests/src/test/snapshots/images/libraries.designsystem.theme.components_DialogWithVeryLongTitle_Dialog_with_a_very_long_title_Dialogs_en.png
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:e1a1350f33dd50756aa7aa175e1dbcc42c5922d82d4b020a5556c4e0d1db0b83
+size 63540
diff --git a/tests/uitests/src/test/snapshots/images/libraries.matrix.ui.components_SpaceHeaderView_Day_0_en.png b/tests/uitests/src/test/snapshots/images/libraries.matrix.ui.components_SpaceHeaderView_Day_0_en.png
index 785ed41190..7a7bf57ab7 100644
--- a/tests/uitests/src/test/snapshots/images/libraries.matrix.ui.components_SpaceHeaderView_Day_0_en.png
+++ b/tests/uitests/src/test/snapshots/images/libraries.matrix.ui.components_SpaceHeaderView_Day_0_en.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:ebb657ce2227ccefcf9055c8c90342d6581ac0d916cd9f7e6a4990fa2bdc4177
-size 61352
+oid sha256:21acaf9ea606378f5f1e83795e41bec9edc2da05143efba04b70f67cce2c80b0
+size 61626
diff --git a/tests/uitests/src/test/snapshots/images/libraries.matrix.ui.components_SpaceHeaderView_Night_0_en.png b/tests/uitests/src/test/snapshots/images/libraries.matrix.ui.components_SpaceHeaderView_Night_0_en.png
index e9329548e3..e76102c580 100644
--- a/tests/uitests/src/test/snapshots/images/libraries.matrix.ui.components_SpaceHeaderView_Night_0_en.png
+++ b/tests/uitests/src/test/snapshots/images/libraries.matrix.ui.components_SpaceHeaderView_Night_0_en.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:97c8ea5d2d83222ee16c0a27c783e04ec12dbd26aff427c28a21c9c581ad057d
-size 60558
+oid sha256:e20d4dc80e8f983516cde0361333f941818cade431fb38ae318cfa9a589ab0d8
+size 60846
diff --git a/tests/uitests/src/test/snapshots/images/libraries.permissions.api_PermissionsView_Day_0_en.png b/tests/uitests/src/test/snapshots/images/libraries.permissions.api_PermissionsView_Day_0_en.png
index fb72370351..9e034f4fbb 100644
--- a/tests/uitests/src/test/snapshots/images/libraries.permissions.api_PermissionsView_Day_0_en.png
+++ b/tests/uitests/src/test/snapshots/images/libraries.permissions.api_PermissionsView_Day_0_en.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:fa702b884d741412232c68245a503bd06c9fa595be214a5cf852ea576d77a031
-size 26878
+oid sha256:db93be255fb6e9a70e1814bad2275b4e828924aaf5dfdf623456290d986926e4
+size 26853
diff --git a/tests/uitests/src/test/snapshots/images/libraries.permissions.api_PermissionsView_Day_1_en.png b/tests/uitests/src/test/snapshots/images/libraries.permissions.api_PermissionsView_Day_1_en.png
index 56fabcb8dd..e8c4accaa2 100644
--- a/tests/uitests/src/test/snapshots/images/libraries.permissions.api_PermissionsView_Day_1_en.png
+++ b/tests/uitests/src/test/snapshots/images/libraries.permissions.api_PermissionsView_Day_1_en.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:6e70d3bca33fcccf6839b651a8b34056bdcbbacf18447fa8d99638ddc0558816
-size 26011
+oid sha256:ba7cfc134e5843e053b6c0c842b882e4a18505451959510da2b02dc295f68da6
+size 25985
diff --git a/tests/uitests/src/test/snapshots/images/libraries.permissions.api_PermissionsView_Day_2_en.png b/tests/uitests/src/test/snapshots/images/libraries.permissions.api_PermissionsView_Day_2_en.png
index c138569904..e4163ee256 100644
--- a/tests/uitests/src/test/snapshots/images/libraries.permissions.api_PermissionsView_Day_2_en.png
+++ b/tests/uitests/src/test/snapshots/images/libraries.permissions.api_PermissionsView_Day_2_en.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:cdb77ac0053690361d44a221b2290557a8c9b904eb5771c0d4bc76382804d579
-size 26491
+oid sha256:cf678d8b087d3d1ae5ee836ec177828610ad074ff611c8b7f42b4008589bd911
+size 26467
diff --git a/tests/uitests/src/test/snapshots/images/libraries.permissions.api_PermissionsView_Day_3_en.png b/tests/uitests/src/test/snapshots/images/libraries.permissions.api_PermissionsView_Day_3_en.png
index b1232891b4..32f9d544c8 100644
--- a/tests/uitests/src/test/snapshots/images/libraries.permissions.api_PermissionsView_Day_3_en.png
+++ b/tests/uitests/src/test/snapshots/images/libraries.permissions.api_PermissionsView_Day_3_en.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:e3de92534cdb971ef27901f9e5e5db4146b39d9527afc6b23daa7718ee4d4ef4
-size 20477
+oid sha256:0dd34239f647ab049a3dc1bf137abd7e31081b4da25fa850ee9ebff89a84cdd4
+size 20460
diff --git a/tests/uitests/src/test/snapshots/images/libraries.permissions.api_PermissionsView_Night_0_en.png b/tests/uitests/src/test/snapshots/images/libraries.permissions.api_PermissionsView_Night_0_en.png
index a839d4cbc7..b10e2188fe 100644
--- a/tests/uitests/src/test/snapshots/images/libraries.permissions.api_PermissionsView_Night_0_en.png
+++ b/tests/uitests/src/test/snapshots/images/libraries.permissions.api_PermissionsView_Night_0_en.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:541193db62ebb995d81e48f3f49a74fafa8d537e9dd99c4f7537b7cd14a1258f
-size 25632
+oid sha256:bad56fc6d29cf54e760ac8a5d13e53cc047651c2cf1efad36d78dc3956bb7ac5
+size 25638
diff --git a/tests/uitests/src/test/snapshots/images/libraries.permissions.api_PermissionsView_Night_1_en.png b/tests/uitests/src/test/snapshots/images/libraries.permissions.api_PermissionsView_Night_1_en.png
index d995dccd06..f0a44c0dbc 100644
--- a/tests/uitests/src/test/snapshots/images/libraries.permissions.api_PermissionsView_Night_1_en.png
+++ b/tests/uitests/src/test/snapshots/images/libraries.permissions.api_PermissionsView_Night_1_en.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:1ae7e0666a300169a5eabf6e8d8e8846034488e3cfb92e5c2fe7c1cdd889fb13
-size 24880
+oid sha256:42dd21b3fcd9faf803153852e6ed3ea9d43cdc6f637af3d1a34f4892174738eb
+size 24886
diff --git a/tests/uitests/src/test/snapshots/images/libraries.permissions.api_PermissionsView_Night_2_en.png b/tests/uitests/src/test/snapshots/images/libraries.permissions.api_PermissionsView_Night_2_en.png
index d3b91b8c05..f8337097c9 100644
--- a/tests/uitests/src/test/snapshots/images/libraries.permissions.api_PermissionsView_Night_2_en.png
+++ b/tests/uitests/src/test/snapshots/images/libraries.permissions.api_PermissionsView_Night_2_en.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:9a32d7138ef227596fda8a0e495143ab255bf30913ce62d1d9f40108cde79728
-size 25303
+oid sha256:4284ff47ebb1fec51df90fc55219f9354c751d3d9c17c2b2d133b57550176b7b
+size 25304
diff --git a/tests/uitests/src/test/snapshots/images/libraries.permissions.api_PermissionsView_Night_3_en.png b/tests/uitests/src/test/snapshots/images/libraries.permissions.api_PermissionsView_Night_3_en.png
index 9951f9bfa8..fafa6d94da 100644
--- a/tests/uitests/src/test/snapshots/images/libraries.permissions.api_PermissionsView_Night_3_en.png
+++ b/tests/uitests/src/test/snapshots/images/libraries.permissions.api_PermissionsView_Night_3_en.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:c91ae52ece27098b46e8e787407262d50bbf95c42550b26faeabcc8a382887eb
-size 19192
+oid sha256:952550c4bfcc10751a781279f1023b11e42e73b585c97543a212e3d7f0887218
+size 19156
diff --git a/tests/uitests/src/test/snapshots/images/libraries.textcomposer_TextComposerLinkDialogCreateLinkWithoutText_Day_0_en.png b/tests/uitests/src/test/snapshots/images/libraries.textcomposer_TextComposerLinkDialogCreateLinkWithoutText_Day_0_en.png
index 3d5088afdc..b50f6ba4a8 100644
--- a/tests/uitests/src/test/snapshots/images/libraries.textcomposer_TextComposerLinkDialogCreateLinkWithoutText_Day_0_en.png
+++ b/tests/uitests/src/test/snapshots/images/libraries.textcomposer_TextComposerLinkDialogCreateLinkWithoutText_Day_0_en.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:736b3ea3821b421acc7f1a9bdc54f2c603dea34f3995150cccaef8b15ba7d75f
-size 13057
+oid sha256:bda5872074c486c4b40575b814ed2865056c02931ee1ca0f8a98ac4f32e5f985
+size 13093
diff --git a/tests/uitests/src/test/snapshots/images/libraries.textcomposer_TextComposerLinkDialogCreateLinkWithoutText_Night_0_en.png b/tests/uitests/src/test/snapshots/images/libraries.textcomposer_TextComposerLinkDialogCreateLinkWithoutText_Night_0_en.png
index 411f8fb2da..00b7d45027 100644
--- a/tests/uitests/src/test/snapshots/images/libraries.textcomposer_TextComposerLinkDialogCreateLinkWithoutText_Night_0_en.png
+++ b/tests/uitests/src/test/snapshots/images/libraries.textcomposer_TextComposerLinkDialogCreateLinkWithoutText_Night_0_en.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:8a56cab67985d64487d89b4ccecff21e391c1562edebb28280ee5ab8f26393ad
-size 12033
+oid sha256:648ac4cf6333a39bbfb90e8a5faf2aa44a1de19c1613bf754ca6bc4d1974fc8b
+size 12019
diff --git a/tests/uitests/src/test/snapshots/images/libraries.textcomposer_TextComposerLinkDialogCreateLink_Day_0_en.png b/tests/uitests/src/test/snapshots/images/libraries.textcomposer_TextComposerLinkDialogCreateLink_Day_0_en.png
index 7713f10b20..639d4d89b5 100644
--- a/tests/uitests/src/test/snapshots/images/libraries.textcomposer_TextComposerLinkDialogCreateLink_Day_0_en.png
+++ b/tests/uitests/src/test/snapshots/images/libraries.textcomposer_TextComposerLinkDialogCreateLink_Day_0_en.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:886722a012510c51dbad9a50f717d6ba3b64425cad0755c90afdd84a5cae67c0
-size 14618
+oid sha256:7f6e0912e5970104f0dd09d152d6a3da57f7a2b2201aa5dd86c7b691c797edad
+size 14637
diff --git a/tests/uitests/src/test/snapshots/images/libraries.textcomposer_TextComposerLinkDialogCreateLink_Night_0_en.png b/tests/uitests/src/test/snapshots/images/libraries.textcomposer_TextComposerLinkDialogCreateLink_Night_0_en.png
index 426d15e371..24e9093c2e 100644
--- a/tests/uitests/src/test/snapshots/images/libraries.textcomposer_TextComposerLinkDialogCreateLink_Night_0_en.png
+++ b/tests/uitests/src/test/snapshots/images/libraries.textcomposer_TextComposerLinkDialogCreateLink_Night_0_en.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:edc8ef6512ea5f0e39a059d692063455e2e1174a8e781eccd0c2e543d156544a
-size 13465
+oid sha256:b879de5d6db9a3cff7de4b2ee779b6c8de456b629f31f07fcb57de3a7c7e7c28
+size 13409
diff --git a/tests/uitests/src/test/snapshots/images/libraries.textcomposer_TextComposerLinkDialogEditLink_Day_0_en.png b/tests/uitests/src/test/snapshots/images/libraries.textcomposer_TextComposerLinkDialogEditLink_Day_0_en.png
index 560c64ad73..0342d06c2c 100644
--- a/tests/uitests/src/test/snapshots/images/libraries.textcomposer_TextComposerLinkDialogEditLink_Day_0_en.png
+++ b/tests/uitests/src/test/snapshots/images/libraries.textcomposer_TextComposerLinkDialogEditLink_Day_0_en.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:6ab5214a9d6f424910cd551454392443faf40694b5c3bde3b839fc49e1cd0633
-size 16845
+oid sha256:14d318ad147102d2cdfe73c46125fa35864010ea38dcd6dfbb7fd3b12d64d878
+size 16873
diff --git a/tests/uitests/src/test/snapshots/images/libraries.textcomposer_TextComposerLinkDialogEditLink_Night_0_en.png b/tests/uitests/src/test/snapshots/images/libraries.textcomposer_TextComposerLinkDialogEditLink_Night_0_en.png
index 6a2334efc0..262699e09c 100644
--- a/tests/uitests/src/test/snapshots/images/libraries.textcomposer_TextComposerLinkDialogEditLink_Night_0_en.png
+++ b/tests/uitests/src/test/snapshots/images/libraries.textcomposer_TextComposerLinkDialogEditLink_Night_0_en.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:d7bd2c66d3efa336b22df0820ea9e36633a22b36927163d3950088d9179376dd
-size 15521
+oid sha256:2ce99713434fba303745a45b2d12d18841c90ab65fb650e700a5fc9e070bd79f
+size 15496
diff --git a/tests/uitests/src/test/snapshots/images/libraries.troubleshoot.impl_TroubleshootNotificationsView_Day_2_en.png b/tests/uitests/src/test/snapshots/images/libraries.troubleshoot.impl_TroubleshootNotificationsView_Day_2_en.png
index 22eaaced82..2442a17143 100644
--- a/tests/uitests/src/test/snapshots/images/libraries.troubleshoot.impl_TroubleshootNotificationsView_Day_2_en.png
+++ b/tests/uitests/src/test/snapshots/images/libraries.troubleshoot.impl_TroubleshootNotificationsView_Day_2_en.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:642e972ecba4cf6af7961066a67b556047d0ab3c35a4ce66e043ba185d93b528
-size 20101
+oid sha256:9051334b3879fe2a6fb56a3c573ecb49eca7700a94184d828e2c0329cbb82b4b
+size 25070
diff --git a/tests/uitests/src/test/snapshots/images/libraries.troubleshoot.impl_TroubleshootNotificationsView_Night_2_en.png b/tests/uitests/src/test/snapshots/images/libraries.troubleshoot.impl_TroubleshootNotificationsView_Night_2_en.png
index 5b2d1f6f65..40126799db 100644
--- a/tests/uitests/src/test/snapshots/images/libraries.troubleshoot.impl_TroubleshootNotificationsView_Night_2_en.png
+++ b/tests/uitests/src/test/snapshots/images/libraries.troubleshoot.impl_TroubleshootNotificationsView_Night_2_en.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:26e11efbeec28f03e9b8d0df822e886b9e420fc523286cc0aa69760f8d5b639c
-size 19562
+oid sha256:50fb2b753bdad6a9df4ce2f55a552464e229c7b81be16e0d4f5c8e4e4b3d129b
+size 24312
diff --git a/tests/uitests/src/test/snapshots/images/services.apperror.impl_AppErrorView_Day_0_en.png b/tests/uitests/src/test/snapshots/images/services.apperror.impl_AppErrorView_Day_0_en.png
index 08d3f6a214..d15340871f 100644
--- a/tests/uitests/src/test/snapshots/images/services.apperror.impl_AppErrorView_Day_0_en.png
+++ b/tests/uitests/src/test/snapshots/images/services.apperror.impl_AppErrorView_Day_0_en.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:3f181687fc541a13928a35f9a23fca99a6d6bdf7875bd900fe444d001b5256fd
-size 19592
+oid sha256:94242ace02e2db7156e0bdb2c3e071255006ed839360db7a3322a8bb0a93458a
+size 19570
diff --git a/tests/uitests/src/test/snapshots/images/services.apperror.impl_AppErrorView_Night_0_en.png b/tests/uitests/src/test/snapshots/images/services.apperror.impl_AppErrorView_Night_0_en.png
index 38a6de5b59..616d21a8a6 100644
--- a/tests/uitests/src/test/snapshots/images/services.apperror.impl_AppErrorView_Night_0_en.png
+++ b/tests/uitests/src/test/snapshots/images/services.apperror.impl_AppErrorView_Night_0_en.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:81f5b10dd42b27de179693857fd3aeac838562540371be8e789801c69755edc6
-size 18202
+oid sha256:b7ff1f5db38fc99452f0a7c3fc727ee7ffd6461b69ad0d58d126571b1eea2851
+size 18191
diff --git a/tools/localazy/config.json b/tools/localazy/config.json
index 0aac7e51af..4264b35229 100644
--- a/tools/localazy/config.json
+++ b/tools/localazy/config.json
@@ -123,6 +123,7 @@
"includeRegex" : [
"push_.*",
"notification_.*",
+ "troubleshoot_notifications\\.test_blocked_users\\..*",
"troubleshoot_notifications_test_current_push_provider.*",
"troubleshoot_notifications_test_detect_push_provider.*",
"troubleshoot_notifications_test_display_notification_.*",
diff --git a/tools/release/release.sh b/tools/release/release.sh
index 30d4cea205..59a29dc13c 100755
--- a/tools/release/release.sh
+++ b/tools/release/release.sh
@@ -64,7 +64,8 @@ fi
# Read minSdkVersion from file plugins/src/main/kotlin/Versions.kt
minSdkVersion=$(grep "MIN_SDK_FOSS =" ./plugins/src/main/kotlin/Versions.kt |cut -d '=' -f 2 |xargs)
-buildToolsVersion="36.0.0"
+# Read buildToolsVersion from file plugins/src/main/kotlin/Versions.kt
+buildToolsVersion=$(grep "BUILD_TOOLS_VERSION =" ./plugins/src/main/kotlin/Versions.kt |cut -d '=' -f 2 |xargs)
buildToolsPath="${androidHome}/build-tools/${buildToolsVersion}"
if [[ ! -d ${buildToolsPath} ]]; then
@@ -145,7 +146,7 @@ printf "Creating fastlane file...\n"
printf -v versionReleaseNumber2Digits "%02d" "${versionReleaseNumber}"
fastlaneFile="20${versionYear}${versionMonth}${versionReleaseNumber2Digits}0.txt"
fastlanePathFile="./fastlane/metadata/android/en-US/changelogs/${fastlaneFile}"
-printf "Main changes in this version: TODO.\nFull changelog: https://github.com/element-hq/element-x-android/releases" > "${fastlanePathFile}"
+printf "Main changes in this version: bug fixes and improvements.\nFull changelog: https://github.com/element-hq/element-x-android/releases" > "${fastlanePathFile}"
read -r -p "I have created the file ${fastlanePathFile}, please edit it and press enter to continue. "
git add "${fastlanePathFile}"
diff --git a/tools/templates/files/fileTemplates/Template Module Feature Build Gradle Impl.kts b/tools/templates/files/fileTemplates/Template Module Feature Build Gradle Impl.kts
index 5ba8e9f684..d650a1f3e2 100644
--- a/tools/templates/files/fileTemplates/Template Module Feature Build Gradle Impl.kts
+++ b/tools/templates/files/fileTemplates/Template Module Feature Build Gradle Impl.kts
@@ -1,4 +1,5 @@
import extension.setupDependencyInjection
+import extension.testCommonDependencies
plugins {
id("io.element.android-compose-library")
@@ -19,10 +20,6 @@ dependencies {
implementation(projects.libraries.matrixui)
implementation(projects.libraries.designsystem)
- testImplementation(libs.test.junit)
- testImplementation(libs.coroutines.test)
- testImplementation(libs.molecule.runtime)
- testImplementation(libs.test.truth)
- testImplementation(libs.test.turbine)
+ testCommonDependencies(libs)
testImplementation(projects.libraries.matrix.test)
}
diff --git a/tools/templates/files/fileTemplates/Template Module Feature Entry Point API.kt b/tools/templates/files/fileTemplates/Template Module Feature Entry Point API.kt
index 6297ec4e24..37f0500444 100644
--- a/tools/templates/files/fileTemplates/Template Module Feature Entry Point API.kt
+++ b/tools/templates/files/fileTemplates/Template Module Feature Entry Point API.kt
@@ -6,7 +6,6 @@ import com.bumble.appyx.core.plugin.Plugin
import io.element.android.libraries.architecture.FeatureEntryPoint
interface ${FEATURE_NAME}EntryPoint : FeatureEntryPoint {
-
fun nodeBuilder(parentNode: Node, buildContext: BuildContext): NodeBuilder
interface NodeBuilder {