diff --git a/.github/workflows/nightlyReports.yml b/.github/workflows/nightlyReports.yml
index 65a2717f36..b27183cc59 100644
--- a/.github/workflows/nightlyReports.yml
+++ b/.github/workflows/nightlyReports.yml
@@ -33,7 +33,7 @@ jobs:
run: ./gradlew verifyPaparazziDebug $CI_GRADLE_ARG_PROPERTIES
- name: 📈 Generate kover report and verify coverage
- run: ./gradlew :app:koverXmlReportGplayDebug :app:koverHtmlReportGplayDebug :app:koverVerifyGplayDebug $CI_GRADLE_ARG_PROPERTIES
+ run: ./gradlew :app:koverXmlReportGplayDebug :app:koverHtmlReportGplayDebug :app:koverVerifyAll $CI_GRADLE_ARG_PROPERTIES
- name: ✅ Upload kover report
if: always()
diff --git a/.github/workflows/quality.yml b/.github/workflows/quality.yml
index b62dbb0127..c3e29a2306 100644
--- a/.github/workflows/quality.yml
+++ b/.github/workflows/quality.yml
@@ -10,7 +10,7 @@ on:
# Enrich gradle.properties for CI/CD
env:
GRADLE_OPTS: -Dorg.gradle.jvmargs="-Xmx6g -Dfile.encoding=UTF-8 -XX:+HeapDumpOnOutOfMemoryError" -Dkotlin.incremental=false -XX:+UseParallelGC
- CI_GRADLE_ARG_PROPERTIES: --stacktrace -PpreDexEnable=false --max-workers 8 --no-daemon --warn
+ CI_GRADLE_ARG_PROPERTIES: --stacktrace -PpreDexEnable=false --max-workers 8 --no-daemon
jobs:
checkScript:
@@ -33,12 +33,13 @@ jobs:
- name: Search for invalid screenshot files
run: ./tools/test/checkInvalidScreenshots.py
- check:
- name: Project Check Suite
+ # Code checks
+ konsist:
+ name: Konsist tests
runs-on: ubuntu-latest
# Allow all jobs on main and develop. Just one per PR.
concurrency:
- group: ${{ github.ref == 'refs/heads/main' && format('check-main-{0}', github.sha) || github.ref == 'refs/heads/develop' && format('check-develop-{0}', github.sha) || format('check-{0}', github.ref) }}
+ group: ${{ github.ref == 'refs/heads/main' && format('check-konsist-main-{0}', github.sha) || github.ref == 'refs/heads/develop' && format('check-konsist-develop-{0}', github.sha) || format('check-konsist-{0}', github.ref) }}
cancel-in-progress: true
steps:
- uses: actions/checkout@v4
@@ -55,8 +56,40 @@ jobs:
uses: gradle/actions/setup-gradle@v3
with:
cache-read-only: ${{ github.ref != 'refs/heads/develop' }}
- - name: Run code quality check suite
- run: ./gradlew runQualityChecks $CI_GRADLE_ARG_PROPERTIES
+ - name: Run Konsist tests
+ run: ./gradlew :tests:konsist:testDebugUnitTest $CI_GRADLE_ARG_PROPERTIES --no-daemon
+ - name: Upload reports
+ if: always()
+ uses: actions/upload-artifact@v4
+ with:
+ name: konsist-report
+ path: |
+ **/build/reports/**/*.*
+
+ lint:
+ name: Android lint check
+ runs-on: ubuntu-latest
+ # Allow all jobs on main and develop. Just one per PR.
+ concurrency:
+ group: ${{ github.ref == 'refs/heads/main' && format('check-lint-main-{0}', github.sha) || github.ref == 'refs/heads/develop' && format('check-lint-develop-{0}', github.sha) || format('check-lint-{0}', github.ref) }}
+ cancel-in-progress: true
+ steps:
+ - uses: actions/checkout@v4
+ with:
+ # Ensure we are building the branch and not the branch after being merged on develop
+ # https://github.com/actions/checkout/issues/881
+ ref: ${{ github.event_name == 'pull_request' && github.event.pull_request.head.sha || github.ref }}
+ - name: Use JDK 17
+ uses: actions/setup-java@v4
+ with:
+ distribution: 'temurin' # See 'Supported distributions' for available options
+ java-version: '17'
+ - name: Configure gradle
+ uses: gradle/actions/setup-gradle@v3
+ with:
+ cache-read-only: ${{ github.ref != 'refs/heads/develop' }}
+ - name: Run lint
+ run: ./gradlew :app:lintGplayDebug :app:lintFdroidDebug $CI_GRADLE_ARG_PROPERTIES
- name: Upload reports
if: always()
uses: actions/upload-artifact@v4
@@ -64,6 +97,108 @@ jobs:
name: linting-report
path: |
**/build/reports/**/*.*
+
+ detekt:
+ name: Detekt checks
+ runs-on: ubuntu-latest
+ # Allow all jobs on main and develop. Just one per PR.
+ concurrency:
+ group: ${{ github.ref == 'refs/heads/main' && format('check-detekt-main-{0}', github.sha) || github.ref == 'refs/heads/develop' && format('check-detekt-develop-{0}', github.sha) || format('check-detekt-{0}', github.ref) }}
+ cancel-in-progress: true
+ steps:
+ - uses: actions/checkout@v4
+ with:
+ # Ensure we are building the branch and not the branch after being merged on develop
+ # https://github.com/actions/checkout/issues/881
+ ref: ${{ github.event_name == 'pull_request' && github.event.pull_request.head.sha || github.ref }}
+ - name: Use JDK 17
+ uses: actions/setup-java@v4
+ with:
+ distribution: 'temurin' # See 'Supported distributions' for available options
+ java-version: '17'
+ - name: Configure gradle
+ uses: gradle/actions/setup-gradle@v3
+ with:
+ cache-read-only: ${{ github.ref != 'refs/heads/develop' }}
+ - name: Run Detekt
+ run: ./gradlew detekt $CI_GRADLE_ARG_PROPERTIES --no-daemon
+ - name: Upload reports
+ if: always()
+ uses: actions/upload-artifact@v4
+ with:
+ name: detekt-report
+ path: |
+ **/build/reports/**/*.*
+
+ ktlint:
+ name: Ktlint checks
+ runs-on: ubuntu-latest
+ # Allow all jobs on main and develop. Just one per PR.
+ concurrency:
+ group: ${{ github.ref == 'refs/heads/main' && format('check-ktlint-main-{0}', github.sha) || github.ref == 'refs/heads/develop' && format('check-ktlint-develop-{0}', github.sha) || format('check-ktlint-{0}', github.ref) }}
+ cancel-in-progress: true
+ steps:
+ - uses: actions/checkout@v4
+ with:
+ # Ensure we are building the branch and not the branch after being merged on develop
+ # https://github.com/actions/checkout/issues/881
+ ref: ${{ github.event_name == 'pull_request' && github.event.pull_request.head.sha || github.ref }}
+ - name: Use JDK 17
+ uses: actions/setup-java@v4
+ with:
+ distribution: 'temurin' # See 'Supported distributions' for available options
+ java-version: '17'
+ - name: Configure gradle
+ uses: gradle/actions/setup-gradle@v3
+ with:
+ cache-read-only: ${{ github.ref != 'refs/heads/develop' }}
+ - name: Run Ktlint check
+ run: ./gradlew ktlintCheck $CI_GRADLE_ARG_PROPERTIES
+ - name: Upload reports
+ if: always()
+ uses: actions/upload-artifact@v4
+ with:
+ name: ktlint-report
+ path: |
+ **/build/reports/**/*.*
+
+ knit:
+ name: Knit checks
+ runs-on: ubuntu-latest
+ # Allow all jobs on main and develop. Just one per PR.
+ concurrency:
+ group: ${{ github.ref == 'refs/heads/main' && format('check-knit-main-{0}', github.sha) || github.ref == 'refs/heads/develop' && format('check-knit-develop-{0}', github.sha) || format('check-knit-{0}', github.ref) }}
+ cancel-in-progress: true
+ steps:
+ - uses: actions/checkout@v4
+ with:
+ # Ensure we are building the branch and not the branch after being merged on develop
+ # https://github.com/actions/checkout/issues/881
+ ref: ${{ github.event_name == 'pull_request' && github.event.pull_request.head.sha || github.ref }}
+ - name: Use JDK 17
+ uses: actions/setup-java@v4
+ with:
+ distribution: 'temurin' # See 'Supported distributions' for available options
+ java-version: '17'
+ - name: Configure gradle
+ uses: gradle/actions/setup-gradle@v3
+ with:
+ cache-read-only: ${{ github.ref != 'refs/heads/develop' }}
+ - name: Run Knit
+ run: ./gradlew knitCheck $CI_GRADLE_ARG_PROPERTIES
+
+ upload_reports:
+ name: Project Check Suite
+ runs-on: ubuntu-latest
+ needs: [konsist, lint, ktlint, detekt]
+ steps:
+ - uses: actions/checkout@v4
+ with:
+ # Ensure we are building the branch and not the branch after being merged on develop
+ # https://github.com/actions/checkout/issues/881
+ ref: ${{ github.event_name == 'pull_request' && github.event.pull_request.head.sha || github.ref }}
+ - name: Download reports from previous jobs
+ uses: actions/download-artifact@v4
- name: Prepare Danger
if: always()
run: |
diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml
index 4c84c4e2fe..3998bc0246 100644
--- a/.github/workflows/release.yml
+++ b/.github/workflows/release.yml
@@ -11,8 +11,8 @@ env:
CI_GRADLE_ARG_PROPERTIES: --stacktrace -PpreDexEnable=false --max-workers 8 --no-daemon
jobs:
- release:
- name: Create App Bundle
+ gplay:
+ name: Create App Bundle (Gplay)
runs-on: ubuntu-latest
concurrency:
group: ${{ github.ref == 'refs/head/main' && format('build-release-main-{0}', github.sha) }}
@@ -38,3 +38,31 @@ jobs:
name: elementx-app-gplay-bundle-unsigned
path: |
app/build/outputs/bundle/gplayRelease/app-gplay-release.aab
+
+ fdroid:
+ name: Create APKs (FDroid)
+ runs-on: ubuntu-latest
+ concurrency:
+ group: ${{ github.ref == 'refs/head/main' && format('build-release-main-{0}', github.sha) }}
+ cancel-in-progress: true
+ steps:
+ - uses: actions/checkout@v4
+ - name: Use JDK 17
+ uses: actions/setup-java@v4
+ with:
+ distribution: 'temurin' # See 'Supported distributions' for available options
+ java-version: '17'
+ - name: Configure gradle
+ uses: gradle/actions/setup-gradle@v3
+ - name: Create APKs
+ env:
+ ELEMENT_ANDROID_MAPTILER_API_KEY: ${{ secrets.MAPTILER_KEY }}
+ ELEMENT_ANDROID_MAPTILER_LIGHT_MAP_ID: ${{ secrets.MAPTILER_LIGHT_MAP_ID }}
+ ELEMENT_ANDROID_MAPTILER_DARK_MAP_ID: ${{ secrets.MAPTILER_DARK_MAP_ID }}
+ run: ./gradlew assembleFdroidRelease $CI_GRADLE_ARG_PROPERTIES
+ - name: Upload apks as artifact
+ uses: actions/upload-artifact@v4
+ with:
+ name: elementx-app-fdroid-apks-unsigned
+ path: |
+ app/build/outputs/apk/fdroid/release/*.apk
diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml
index 4952ac435c..a678cb54cb 100644
--- a/.github/workflows/tests.yml
+++ b/.github/workflows/tests.yml
@@ -55,7 +55,7 @@ jobs:
run: ./gradlew verifyPaparazziDebug $CI_GRADLE_ARG_PROPERTIES
- name: 📈Generate kover report and verify coverage
- run: ./gradlew :app:koverXmlReportGplayDebug :app:koverHtmlReportGplayDebug :app:koverVerifyGplayDebug $CI_GRADLE_ARG_PROPERTIES
+ run: ./gradlew :app:koverXmlReportGplayDebug :app:koverHtmlReportGplayDebug :app:koverVerifyAll $CI_GRADLE_ARG_PROPERTIES
- name: 🚫 Upload kover failed coverage reports
if: failure()
diff --git a/.gitignore b/.gitignore
index e7029fd3cd..342d97a933 100644
--- a/.gitignore
+++ b/.gitignore
@@ -45,6 +45,7 @@ captures/
.idea/assetWizardSettings.xml
.idea/compiler.xml
.idea/deploymentTargetDropDown.xml
+.idea/deploymentTargetSelector.xml
.idea/gradle.xml
.idea/jarRepositories.xml
.idea/misc.xml
diff --git a/.idea/kotlinc.xml b/.idea/kotlinc.xml
index fe63bb677d..148fdd2469 100644
--- a/.idea/kotlinc.xml
+++ b/.idea/kotlinc.xml
@@ -1,6 +1,6 @@
-
+
\ No newline at end of file
diff --git a/.maestro/tests/roomList/timeline/messages/text.yaml b/.maestro/tests/roomList/timeline/messages/text.yaml
index 6767886d8d..cae5e310c0 100644
--- a/.maestro/tests/roomList/timeline/messages/text.yaml
+++ b/.maestro/tests/roomList/timeline/messages/text.yaml
@@ -2,7 +2,7 @@ appId: ${MAESTRO_APP_ID}
---
- takeScreenshot: build/maestro/510-Timeline
- tapOn:
- id: "rich_text_editor"
+ id: "text_editor"
- inputText: "Hello world!"
- tapOn: "Send"
- hideKeyboard
diff --git a/.maestro/tests/settings/settings.yaml b/.maestro/tests/settings/settings.yaml
index c77d118a3b..15181a458b 100644
--- a/.maestro/tests/settings/settings.yaml
+++ b/.maestro/tests/settings/settings.yaml
@@ -34,7 +34,7 @@ appId: ${MAESTRO_APP_ID}
- tapOn:
text: "Advanced settings"
-- assertVisible: "Rich text editor"
+- assertVisible: "View source"
- back
- tapOn:
diff --git a/CHANGES.md b/CHANGES.md
index d091404139..d303339a27 100644
--- a/CHANGES.md
+++ b/CHANGES.md
@@ -1,3 +1,26 @@
+Changes in Element X v0.4.13 (2024-05-22)
+=========================================
+
+Features ✨
+----------
+ - Add plain text editor based on Markdown input. ([#2840](https://github.com/element-hq/element-x-android/issues/2840))
+
+Bugfixes 🐛
+----------
+ - Use members display names for their membership state events. ([#2286](https://github.com/element-hq/element-x-android/issues/2286))
+ - Make sure explicit links in messages take priority over links found by linkification (urls, emails, phone numbers, etc.) ([#2291](https://github.com/element-hq/element-x-android/issues/2291))
+ - Fix modal contents overlapping screen lock pin. ([#2692](https://github.com/element-hq/element-x-android/issues/2692))
+ - Fix a crash when trying to create an `EncryptedFile` in Android 6. ([#2846](https://github.com/element-hq/element-x-android/issues/2846))
+ - Session falsely displayed as 'verified' with no internet connection. ([#2884](https://github.com/element-hq/element-x-android/issues/2884))
+
+Other changes
+-------------
+ - Allow configuring push notification provider ([#2340](https://github.com/element-hq/element-x-android/issues/2340))
+ - UX cleanup: reorder text composer actions to prioritise camera ones. ([#2803](https://github.com/element-hq/element-x-android/issues/2803))
+ - Translation added into Portuguese and Simplified Chinese ([#2834](https://github.com/element-hq/element-x-android/issues/2834))
+ - Use via parameters when joining a room from permalink. ([#2843](https://github.com/element-hq/element-x-android/issues/2843))
+
+
Changes in Element X v0.4.12 (2024-05-13)
=========================================
diff --git a/app/src/main/kotlin/io/element/android/x/MainActivity.kt b/app/src/main/kotlin/io/element/android/x/MainActivity.kt
index c11e63a164..eb3f9450f5 100644
--- a/app/src/main/kotlin/io/element/android/x/MainActivity.kt
+++ b/app/src/main/kotlin/io/element/android/x/MainActivity.kt
@@ -32,6 +32,9 @@ import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalUriHandler
import androidx.core.splashscreen.SplashScreen.Companion.installSplashScreen
+import androidx.lifecycle.Lifecycle
+import androidx.lifecycle.lifecycleScope
+import androidx.lifecycle.repeatOnLifecycle
import com.bumble.appyx.core.integration.NodeHost
import com.bumble.appyx.core.integrationpoint.NodeActivity
import com.bumble.appyx.core.plugin.NodeReadyObserver
@@ -39,13 +42,16 @@ import io.element.android.compound.theme.ElementTheme
import io.element.android.compound.theme.Theme
import io.element.android.compound.theme.isDark
import io.element.android.compound.theme.mapToTheme
+import io.element.android.features.lockscreen.api.LockScreenEntryPoint
+import io.element.android.features.lockscreen.api.LockScreenLockState
+import io.element.android.features.lockscreen.api.LockScreenService
import io.element.android.features.lockscreen.api.handleSecureFlag
-import io.element.android.features.lockscreen.api.isLocked
import io.element.android.libraries.architecture.bindings
import io.element.android.libraries.core.log.logger.LoggerTag
import io.element.android.libraries.designsystem.utils.snackbar.LocalSnackbarDispatcher
import io.element.android.x.di.AppBindings
import io.element.android.x.intent.SafeUriHandler
+import kotlinx.coroutines.launch
import timber.log.Timber
private val loggerTag = LoggerTag("MainActivity")
@@ -59,27 +65,13 @@ class MainActivity : NodeActivity() {
installSplashScreen()
super.onCreate(savedInstanceState)
appBindings = bindings()
- appBindings.lockScreenService().handleSecureFlag(this)
+ setupLockManagement(appBindings.lockScreenService(), appBindings.lockScreenEntryPoint())
enableEdgeToEdge()
setContent {
MainContent(appBindings)
}
}
- @Deprecated("")
- override fun onBackPressed() {
- // If the app is locked, we need to intercept onBackPressed before it goes to OnBackPressedDispatcher.
- // Indeed, otherwise we would need to trick Appyx backstack management everywhere.
- // Without this trick, we would get pop operations on the hidden backstack.
- if (appBindings.lockScreenService().isLocked) {
- // Do not kill the app in this case, just go to background.
- moveTaskToBack(false)
- } else {
- @Suppress("DEPRECATION")
- super.onBackPressed()
- }
- }
-
@Composable
private fun MainContent(appBindings: AppBindings) {
val theme by remember {
@@ -96,8 +88,8 @@ class MainActivity : NodeActivity() {
) {
Box(
modifier = Modifier
- .fillMaxSize()
- .background(MaterialTheme.colorScheme.background),
+ .fillMaxSize()
+ .background(MaterialTheme.colorScheme.background),
) {
if (migrationState.migrationAction.isSuccess()) {
MainNodeHost()
@@ -131,6 +123,22 @@ class MainActivity : NodeActivity() {
}
}
+ private fun setupLockManagement(
+ lockScreenService: LockScreenService,
+ lockScreenEntryPoint: LockScreenEntryPoint
+ ) {
+ lockScreenService.handleSecureFlag(this)
+ lifecycleScope.launch {
+ repeatOnLifecycle(Lifecycle.State.RESUMED) {
+ lockScreenService.lockState.collect { state ->
+ if (state == LockScreenLockState.Locked) {
+ startActivity(lockScreenEntryPoint.pinUnlockIntent(this@MainActivity))
+ }
+ }
+ }
+ }
+ }
+
/**
* Called when:
* - the launcher icon is clicked (if the app is already running);
diff --git a/app/src/main/kotlin/io/element/android/x/di/AppBindings.kt b/app/src/main/kotlin/io/element/android/x/di/AppBindings.kt
index d8be841b97..bad34edfa0 100644
--- a/app/src/main/kotlin/io/element/android/x/di/AppBindings.kt
+++ b/app/src/main/kotlin/io/element/android/x/di/AppBindings.kt
@@ -18,6 +18,7 @@ package io.element.android.x.di
import com.squareup.anvil.annotations.ContributesTo
import io.element.android.features.api.MigrationEntryPoint
+import io.element.android.features.lockscreen.api.LockScreenEntryPoint
import io.element.android.features.lockscreen.api.LockScreenService
import io.element.android.features.preferences.api.store.AppPreferencesStore
import io.element.android.features.rageshake.api.reporter.BugReporter
@@ -38,4 +39,6 @@ interface AppBindings {
fun preferencesStore(): AppPreferencesStore
fun migrationEntryPoint(): MigrationEntryPoint
+
+ fun lockScreenEntryPoint(): LockScreenEntryPoint
}
diff --git a/app/src/main/res/xml/locales_config.xml b/app/src/main/res/xml/locales_config.xml
index 17e0192414..8d5ad58e43 100644
--- a/app/src/main/res/xml/locales_config.xml
+++ b/app/src/main/res/xml/locales_config.xml
@@ -10,10 +10,13 @@
+
+
+
diff --git a/appconfig/src/main/kotlin/io/element/android/appconfig/MessageComposerConfig.kt b/appconfig/src/main/kotlin/io/element/android/appconfig/MessageComposerConfig.kt
new file mode 100644
index 0000000000..a927064f3d
--- /dev/null
+++ b/appconfig/src/main/kotlin/io/element/android/appconfig/MessageComposerConfig.kt
@@ -0,0 +1,24 @@
+/*
+ * Copyright (c) 2024 New Vector Ltd
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package io.element.android.appconfig
+
+object MessageComposerConfig {
+ /**
+ * Enable the rich text editing in the composer.
+ */
+ const val ENABLE_RICH_TEXT_EDITING = true
+}
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 9c8b29b356..bd68a9151e 100644
--- a/appnav/src/main/kotlin/io/element/android/appnav/LoggedInFlowNode.kt
+++ b/appnav/src/main/kotlin/io/element/android/appnav/LoggedInFlowNode.kt
@@ -37,6 +37,7 @@ import com.bumble.appyx.navmodel.backstack.operation.push
import com.bumble.appyx.navmodel.backstack.operation.replace
import dagger.assisted.Assisted
import dagger.assisted.AssistedInject
+import im.vector.app.features.analytics.plan.JoinedRoom
import io.element.android.anvilannotations.ContributesNode
import io.element.android.appnav.loggedin.LoggedInNode
import io.element.android.appnav.room.RoomFlowNode
@@ -46,9 +47,6 @@ import io.element.android.features.createroom.api.CreateRoomEntryPoint
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.lockscreen.api.LockScreenEntryPoint
-import io.element.android.features.lockscreen.api.LockScreenLockState
-import io.element.android.features.lockscreen.api.LockScreenService
import io.element.android.features.networkmonitor.api.NetworkMonitor
import io.element.android.features.networkmonitor.api.NetworkStatus
import io.element.android.features.preferences.api.PreferencesEntryPoint
@@ -99,8 +97,6 @@ class LoggedInFlowNode @AssistedInject constructor(
private val coroutineScope: CoroutineScope,
private val networkMonitor: NetworkMonitor,
private val ftueService: FtueService,
- private val lockScreenEntryPoint: LockScreenEntryPoint,
- private val lockScreenStateService: LockScreenService,
private val roomDirectoryEntryPoint: RoomDirectoryEntryPoint,
private val matrixClient: MatrixClient,
snackbarDispatcher: SnackbarDispatcher,
@@ -110,7 +106,7 @@ class LoggedInFlowNode @AssistedInject constructor(
savedStateMap = buildContext.savedStateMap,
),
permanentNavModel = PermanentNavModel(
- navTargets = setOf(NavTarget.LoggedInPermanent, NavTarget.LockPermanent),
+ navTargets = setOf(NavTarget.LoggedInPermanent),
savedStateMap = buildContext.savedStateMap,
),
buildContext = buildContext,
@@ -188,15 +184,14 @@ class LoggedInFlowNode @AssistedInject constructor(
@Parcelize
data object LoggedInPermanent : NavTarget
- @Parcelize
- data object LockPermanent : NavTarget
-
@Parcelize
data object RoomList : NavTarget
@Parcelize
data class Room(
val roomIdOrAlias: RoomIdOrAlias,
+ val serverNames: List = emptyList(),
+ val trigger: JoinedRoom.Trigger? = null,
val roomDescription: RoomDescription? = null,
val initialElement: RoomNavigationTarget = RoomNavigationTarget.Messages()
) : NavTarget
@@ -232,11 +227,6 @@ class LoggedInFlowNode @AssistedInject constructor(
NavTarget.LoggedInPermanent -> {
createNode(buildContext)
}
- NavTarget.LockPermanent -> {
- lockScreenEntryPoint.nodeBuilder(this, buildContext)
- .target(LockScreenEntryPoint.Target.Unlock)
- .build()
- }
NavTarget.RoomList -> {
val callback = object : RoomListEntryPoint.Callback {
override fun onRoomClicked(roomId: RoomId) {
@@ -292,8 +282,9 @@ class LoggedInFlowNode @AssistedInject constructor(
backstack.push(
NavTarget.Room(
roomIdOrAlias = data.roomIdOrAlias,
+ serverNames = data.viaParameters,
+ trigger = JoinedRoom.Trigger.Timeline,
initialElement = RoomNavigationTarget.Messages(data.eventId),
- // TODO Use the viaParameters
)
)
}
@@ -311,6 +302,8 @@ class LoggedInFlowNode @AssistedInject constructor(
val inputs = RoomFlowNode.Inputs(
roomIdOrAlias = navTarget.roomIdOrAlias,
roomDescription = Optional.ofNullable(navTarget.roomDescription),
+ serverNames = navTarget.serverNames,
+ trigger = Optional.ofNullable(navTarget.trigger),
initialElement = navTarget.initialElement
)
createNode(buildContext, plugins = listOf(inputs, callback))
@@ -370,12 +363,14 @@ class LoggedInFlowNode @AssistedInject constructor(
NavTarget.RoomDirectorySearch -> {
roomDirectoryEntryPoint.nodeBuilder(this, buildContext)
.callback(object : RoomDirectoryEntryPoint.Callback {
- override fun onRoomJoined(roomId: RoomId) {
- backstack.push(NavTarget.Room(roomId.toRoomIdOrAlias()))
- }
-
override fun onResultClicked(roomDescription: RoomDescription) {
- backstack.push(NavTarget.Room(roomDescription.roomId.toRoomIdOrAlias(), roomDescription))
+ backstack.push(
+ NavTarget.Room(
+ roomIdOrAlias = roomDescription.roomId.toRoomIdOrAlias(),
+ roomDescription = roomDescription,
+ trigger = JoinedRoom.Trigger.RoomDirectory,
+ )
+ )
}
})
.build()
@@ -383,7 +378,12 @@ class LoggedInFlowNode @AssistedInject constructor(
}
}
- suspend fun attachRoom(roomIdOrAlias: RoomIdOrAlias, eventId: EventId? = null) {
+ suspend fun attachRoom(
+ roomIdOrAlias: RoomIdOrAlias,
+ serverNames: List = emptyList(),
+ trigger: JoinedRoom.Trigger? = null,
+ eventId: EventId? = null,
+ ) {
waitForNavTargetAttached { navTarget ->
navTarget is NavTarget.RoomList
}
@@ -391,6 +391,8 @@ class LoggedInFlowNode @AssistedInject constructor(
backstack.push(
NavTarget.Room(
roomIdOrAlias = roomIdOrAlias,
+ serverNames = serverNames,
+ trigger = trigger,
initialElement = RoomNavigationTarget.Messages(
focusedEventId = eventId
)
@@ -415,15 +417,11 @@ class LoggedInFlowNode @AssistedInject constructor(
@Composable
override fun View(modifier: Modifier) {
Box(modifier = modifier) {
- val lockScreenState by lockScreenStateService.lockState.collectAsState()
val ftueState by ftueService.state.collectAsState()
BackstackView()
if (ftueState is FtueState.Complete) {
PermanentChild(permanentNavModel = permanentNavModel, navTarget = NavTarget.LoggedInPermanent)
}
- if (lockScreenState == LockScreenLockState.Locked) {
- PermanentChild(permanentNavModel = permanentNavModel, navTarget = NavTarget.LockPermanent)
- }
}
}
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 db04345a4e..4b886d9c99 100644
--- a/appnav/src/main/kotlin/io/element/android/appnav/RootFlowNode.kt
+++ b/appnav/src/main/kotlin/io/element/android/appnav/RootFlowNode.kt
@@ -34,6 +34,7 @@ import com.bumble.appyx.navmodel.backstack.operation.pop
import com.bumble.appyx.navmodel.backstack.operation.push
import dagger.assisted.Assisted
import dagger.assisted.AssistedInject
+import im.vector.app.features.analytics.plan.JoinedRoom
import io.element.android.anvilannotations.ContributesNode
import io.element.android.appnav.di.MatrixClientsHolder
import io.element.android.appnav.intent.IntentResolver
@@ -295,6 +296,8 @@ class RootFlowNode @AssistedInject constructor(
is PermalinkData.RoomLink -> {
attachRoom(
roomIdOrAlias = permalinkData.roomIdOrAlias,
+ trigger = JoinedRoom.Trigger.MobilePermalink,
+ serverNames = permalinkData.viaParameters,
eventId = permalinkData.eventId,
)
}
diff --git a/appnav/src/main/kotlin/io/element/android/appnav/loggedin/LoggedInPresenter.kt b/appnav/src/main/kotlin/io/element/android/appnav/loggedin/LoggedInPresenter.kt
index 313f4aafe0..6362695772 100644
--- a/appnav/src/main/kotlin/io/element/android/appnav/loggedin/LoggedInPresenter.kt
+++ b/appnav/src/main/kotlin/io/element/android/appnav/loggedin/LoggedInPresenter.kt
@@ -36,6 +36,7 @@ import io.element.android.libraries.matrix.api.verification.SessionVerifiedStatu
import io.element.android.libraries.push.api.PushService
import io.element.android.services.analytics.api.AnalyticsService
import kotlinx.coroutines.flow.map
+import timber.log.Timber
import javax.inject.Inject
class LoggedInPresenter @Inject constructor(
@@ -55,10 +56,26 @@ class LoggedInPresenter @Inject constructor(
LaunchedEffect(isVerified) {
if (isVerified) {
// Ensure pusher is registered
- // TODO Manually select push provider for now
- val pushProvider = pushService.getAvailablePushProviders().firstOrNull() ?: return@LaunchedEffect
- val distributor = pushProvider.getDistributors().firstOrNull() ?: return@LaunchedEffect
- pushService.registerWith(matrixClient, pushProvider, distributor)
+ val currentPushProvider = pushService.getCurrentPushProvider()
+ val result = if (currentPushProvider == null) {
+ // Register with the first available push provider
+ val pushProvider = pushService.getAvailablePushProviders().firstOrNull() ?: return@LaunchedEffect
+ val distributor = pushProvider.getDistributors().firstOrNull() ?: return@LaunchedEffect
+ pushService.registerWith(matrixClient, pushProvider, distributor)
+ } else {
+ val currentPushDistributor = currentPushProvider.getCurrentDistributor(matrixClient)
+ if (currentPushDistributor == null) {
+ // Register with the first available distributor
+ val distributor = currentPushProvider.getDistributors().firstOrNull() ?: return@LaunchedEffect
+ pushService.registerWith(matrixClient, currentPushProvider, distributor)
+ } else {
+ // Re-register with the current distributor
+ pushService.registerWith(matrixClient, currentPushProvider, currentPushDistributor)
+ }
+ }
+ result.onFailure {
+ Timber.e(it, "Failed to register pusher")
+ }
}
}
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 800b7037cf..70337e8d33 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
@@ -32,6 +32,7 @@ import com.bumble.appyx.navmodel.backstack.BackStack
import com.bumble.appyx.navmodel.backstack.operation.newRoot
import dagger.assisted.Assisted
import dagger.assisted.AssistedInject
+import im.vector.app.features.analytics.plan.JoinedRoom
import io.element.android.anvilannotations.ContributesNode
import io.element.android.appnav.room.joined.JoinedRoomFlowNode
import io.element.android.appnav.room.joined.JoinedRoomLoadedFlowNode
@@ -54,6 +55,7 @@ import io.element.android.libraries.matrix.api.core.RoomAlias
import io.element.android.libraries.matrix.api.core.RoomId
import io.element.android.libraries.matrix.api.core.RoomIdOrAlias
import io.element.android.libraries.matrix.api.room.CurrentUserMembership
+import io.element.android.libraries.matrix.api.room.alias.ResolvedRoomAlias
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.launchIn
@@ -83,6 +85,8 @@ class RoomFlowNode @AssistedInject constructor(
data class Inputs(
val roomIdOrAlias: RoomIdOrAlias,
val roomDescription: Optional,
+ val serverNames: List,
+ val trigger: Optional,
val initialElement: RoomNavigationTarget,
) : NodeInputs
@@ -96,7 +100,11 @@ class RoomFlowNode @AssistedInject constructor(
data class Resolving(val roomAlias: RoomAlias) : NavTarget
@Parcelize
- data class JoinRoom(val roomId: RoomId) : NavTarget
+ data class JoinRoom(
+ val roomId: RoomId,
+ val serverNames: List,
+ val trigger: im.vector.app.features.analytics.plan.JoinedRoom.Trigger,
+ ) : NavTarget
@Parcelize
data class JoinedRoom(val roomId: RoomId) : NavTarget
@@ -114,13 +122,13 @@ class RoomFlowNode @AssistedInject constructor(
backstack.newRoot(NavTarget.Resolving(i.roomAlias))
}
is RoomIdOrAlias.Id -> {
- subscribeToRoomInfoFlow(i.roomId)
+ subscribeToRoomInfoFlow(i.roomId, inputs.serverNames)
}
}
}
}
- private fun subscribeToRoomInfoFlow(roomId: RoomId) {
+ private fun subscribeToRoomInfoFlow(roomId: RoomId, serverNames: List) {
val roomInfoFlow = client.getRoomInfoFlow(
roomId = roomId
).map { it.getOrNull() }
@@ -136,7 +144,13 @@ class RoomFlowNode @AssistedInject constructor(
// 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))
+ backstack.newRoot(
+ NavTarget.JoinRoom(
+ roomId = roomId,
+ serverNames = serverNames,
+ trigger = inputs.trigger.getOrNull() ?: JoinedRoom.Trigger.Invite,
+ )
+ )
} else {
backstack.newRoot(NavTarget.JoinedRoom(roomId))
}
@@ -147,7 +161,13 @@ class RoomFlowNode @AssistedInject constructor(
}
else -> {
// Was invited or the room is not known, display the join room screen
- backstack.newRoot(NavTarget.JoinRoom(roomId))
+ backstack.newRoot(
+ NavTarget.JoinRoom(
+ roomId = roomId,
+ serverNames = serverNames,
+ trigger = inputs.trigger.getOrNull() ?: JoinedRoom.Trigger.Invite,
+ )
+ )
}
}
}.launchIn(lifecycleScope)
@@ -158,8 +178,11 @@ class RoomFlowNode @AssistedInject constructor(
is NavTarget.Loading -> loadingNode(buildContext)
is NavTarget.Resolving -> {
val callback = object : RoomAliasResolverEntryPoint.Callback {
- override fun onAliasResolved(roomId: RoomId) {
- subscribeToRoomInfoFlow(roomId)
+ override fun onAliasResolved(data: ResolvedRoomAlias) {
+ subscribeToRoomInfoFlow(
+ roomId = data.roomId,
+ serverNames = data.servers,
+ )
}
}
val params = RoomAliasResolverEntryPoint.Params(navTarget.roomAlias)
@@ -173,6 +196,8 @@ class RoomFlowNode @AssistedInject constructor(
roomId = navTarget.roomId,
roomIdOrAlias = inputs.roomIdOrAlias,
roomDescription = inputs.roomDescription,
+ serverNames = navTarget.serverNames,
+ trigger = navTarget.trigger,
)
joinRoomEntryPoint.createNode(this, buildContext, inputs)
}
diff --git a/fastlane/metadata/android/en-US/changelogs/40004130.txt b/fastlane/metadata/android/en-US/changelogs/40004130.txt
new file mode 100644
index 0000000000..a00be64eae
--- /dev/null
+++ b/fastlane/metadata/android/en-US/changelogs/40004130.txt
@@ -0,0 +1,2 @@
+Main changes in this version: Add plain text editor based on Markdown input.
+Full changelog: https://github.com/element-hq/element-x-android/releases
diff --git a/features/analytics/api/src/main/res/values-ka/translations.xml b/features/analytics/api/src/main/res/values-ka/translations.xml
new file mode 100644
index 0000000000..fa12b9cc94
--- /dev/null
+++ b/features/analytics/api/src/main/res/values-ka/translations.xml
@@ -0,0 +1,7 @@
+
+
+ "გააზიარეთ ანონიმური გამოყენების მონაცემები, რათა დაგვეხმაროთ პრობლემების იდენტიფიცირებაში."
+ "შეგიძლიათ, წაიკითხოთ ჩვენი ყველა პირობა %1$s."
+ "აქ"
+ "გააზიარეთ ანალიტიკური მონაცემები"
+
diff --git a/features/analytics/api/src/main/res/values-pt/translations.xml b/features/analytics/api/src/main/res/values-pt/translations.xml
new file mode 100644
index 0000000000..434df0b892
--- /dev/null
+++ b/features/analytics/api/src/main/res/values-pt/translations.xml
@@ -0,0 +1,7 @@
+
+
+ "Partilhe dados de utilização anónimos para nos ajudar a identificar problemas."
+ "Podes ler todos os nossos termos %1$s."
+ "aqui"
+ "Partilhar dados de utilização"
+
diff --git a/features/analytics/api/src/main/res/values-zh/translations.xml b/features/analytics/api/src/main/res/values-zh/translations.xml
new file mode 100644
index 0000000000..e5f9fccd66
--- /dev/null
+++ b/features/analytics/api/src/main/res/values-zh/translations.xml
@@ -0,0 +1,7 @@
+
+
+ "共享匿名使用数据以帮助我们排查问题。"
+ "您可以阅读我们的所有条款 %1$s。"
+ "此处"
+ "共享分析数据"
+
diff --git a/features/analytics/impl/src/main/res/values-ka/translations.xml b/features/analytics/impl/src/main/res/values-ka/translations.xml
new file mode 100644
index 0000000000..fb561f4442
--- /dev/null
+++ b/features/analytics/impl/src/main/res/values-ka/translations.xml
@@ -0,0 +1,10 @@
+
+
+ "ჩვენ არ ჩავწერთ და არ დავაფიქსირებთ პერსონალურ მონაცემებს"
+ "გააზიარეთ ანონიმური გამოყენების მონაცემები, რათა დაგვეხმაროთ პრობლემების იდენტიფიცირებაში."
+ "შეგიძლიათ, წაიკითხოთ ჩვენი ყველა პირობა %1$s."
+ "აქ"
+ "ამის გამორთვა ნებისმიერ დროს შეგიძლიათ"
+ "თქვენს მონაცემებს მესამე პირს არ გადავცემთ"
+ "დაგვეხმარეთ, გავაუმჯობესოთ %1$s"
+
diff --git a/features/analytics/impl/src/main/res/values-pt/translations.xml b/features/analytics/impl/src/main/res/values-pt/translations.xml
new file mode 100644
index 0000000000..1a837d6313
--- /dev/null
+++ b/features/analytics/impl/src/main/res/values-pt/translations.xml
@@ -0,0 +1,10 @@
+
+
+ "Não recolheremos ou analisaremos quaisquer dados pessoais"
+ "Partilhe dados de utilização anónimos para nos ajudar a identificar problemas."
+ "Podes ler todos os nossos termos %1$s."
+ "aqui"
+ "Podes desligar qualquer momento"
+ "Não partilharemos os teus dados com terceiros"
+ "Ajude a melhorar a %1$s"
+
diff --git a/features/analytics/impl/src/main/res/values-zh/translations.xml b/features/analytics/impl/src/main/res/values-zh/translations.xml
new file mode 100644
index 0000000000..887930eac7
--- /dev/null
+++ b/features/analytics/impl/src/main/res/values-zh/translations.xml
@@ -0,0 +1,10 @@
+
+
+ "我们不会记录或分析任何个人数据"
+ "共享匿名使用数据以帮助我们排查问题。"
+ "您可以阅读我们的所有条款 %1$s。"
+ "此处"
+ "你可以随时关闭此功能"
+ "我们不会与第三方共享您的数据"
+ "帮助改进 %1$s"
+
diff --git a/features/call/src/main/res/values-ka/translations.xml b/features/call/src/main/res/values-ka/translations.xml
new file mode 100644
index 0000000000..755bb2402b
--- /dev/null
+++ b/features/call/src/main/res/values-ka/translations.xml
@@ -0,0 +1,6 @@
+
+
+ "მიმდინარე ზარი"
+ "დააწკაპუნეთ ზარში დასაბრუნებლად"
+ "☎️ ზარი მიმდინარეობს"
+
diff --git a/features/call/src/main/res/values-pt/translations.xml b/features/call/src/main/res/values-pt/translations.xml
new file mode 100644
index 0000000000..87f439ace5
--- /dev/null
+++ b/features/call/src/main/res/values-pt/translations.xml
@@ -0,0 +1,6 @@
+
+
+ "Chamada em curso"
+ "Toca para voltar à chamada"
+ "☎️ Chamada em curso"
+
diff --git a/features/call/src/main/res/values-zh/translations.xml b/features/call/src/main/res/values-zh/translations.xml
new file mode 100644
index 0000000000..4d57257d19
--- /dev/null
+++ b/features/call/src/main/res/values-zh/translations.xml
@@ -0,0 +1,6 @@
+
+
+ "通话进行中"
+ "点按即可返回通话"
+ "☎️ 通话中"
+
diff --git a/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/configureroom/ConfigureRoomView.kt b/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/configureroom/ConfigureRoomView.kt
index 5852103b92..ad9bb7bfdf 100644
--- a/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/configureroom/ConfigureRoomView.kt
+++ b/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/configureroom/ConfigureRoomView.kt
@@ -29,12 +29,10 @@ import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.selection.selectableGroup
import androidx.compose.foundation.text.KeyboardOptions
import androidx.compose.foundation.verticalScroll
-import androidx.compose.material.ExperimentalMaterialApi
-import androidx.compose.material.ModalBottomSheetValue
-import androidx.compose.material.rememberModalBottomSheetState
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.runtime.Composable
-import androidx.compose.runtime.rememberCoroutineScope
+import androidx.compose.runtime.mutableStateOf
+import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalFocusManager
@@ -63,9 +61,7 @@ import io.element.android.libraries.matrix.ui.components.SelectedUsersRowList
import io.element.android.libraries.matrix.ui.components.UnsavedAvatar
import io.element.android.libraries.permissions.api.PermissionsView
import io.element.android.libraries.ui.strings.CommonStrings
-import kotlinx.coroutines.launch
-@OptIn(ExperimentalMaterialApi::class)
@Composable
fun ConfigureRoomView(
state: ConfigureRoomState,
@@ -73,17 +69,12 @@ fun ConfigureRoomView(
onRoomCreated: (RoomId) -> Unit,
modifier: Modifier = Modifier,
) {
- val coroutineScope = rememberCoroutineScope()
val focusManager = LocalFocusManager.current
- val itemActionsBottomSheetState = rememberModalBottomSheetState(
- initialValue = ModalBottomSheetValue.Hidden,
- )
+ val isAvatarActionsSheetVisible = remember { mutableStateOf(false) }
fun onAvatarClicked() {
focusManager.clearFocus()
- coroutineScope.launch {
- itemActionsBottomSheetState.show()
- }
+ isAvatarActionsSheetVisible.value = true
}
Scaffold(
@@ -143,7 +134,8 @@ fun ConfigureRoomView(
AvatarActionBottomSheet(
actions = state.avatarActions,
- modalBottomSheetState = itemActionsBottomSheetState,
+ isVisible = isAvatarActionsSheetVisible.value,
+ onDismiss = { isAvatarActionsSheetVisible.value = false },
onActionSelected = { state.eventSink(ConfigureRoomEvents.HandleAvatarAction(it)) }
)
diff --git a/features/createroom/impl/src/main/res/values-ka/translations.xml b/features/createroom/impl/src/main/res/values-ka/translations.xml
new file mode 100644
index 0000000000..45a6c79d33
--- /dev/null
+++ b/features/createroom/impl/src/main/res/values-ka/translations.xml
@@ -0,0 +1,14 @@
+
+
+ "ახალი ოთახი"
+ "ხალხის მოწვევა"
+ "ოთახის შექმნისას შეცდომა მოხდა"
+ "ამ ოთახში შეტყობინებები დაშიფრულია. შემდგომ დაშიფვრის გამორთვა შეუძლებელია."
+ "კერძო ოთახი (მხოლოდ მოწვევა)"
+ "შეტყობინებები არ არის დაშიფრული და ყველას შეუძლია მათი წაკითხვა. შეგიძლიათ ჩართოთ დაშიფვრა მოგვიანებით."
+ "საჯარო ოთახი (ნებისმიერი)"
+ "ოთახის სახელი"
+ "ოთახის შექმნა"
+ "თემა (სურვილისამებრ)"
+ "ჩატის დაწყების მცდელობისას შეცდომა მოხდა"
+
diff --git a/features/createroom/impl/src/main/res/values-pt/translations.xml b/features/createroom/impl/src/main/res/values-pt/translations.xml
new file mode 100644
index 0000000000..398be62190
--- /dev/null
+++ b/features/createroom/impl/src/main/res/values-pt/translations.xml
@@ -0,0 +1,14 @@
+
+
+ "Nova sala"
+ "Convidar pessoas"
+ "Ocorreu um erro ao criar a sala"
+ "As mensagens serão cifradas. Uma vez ativada, não é possível desativar a cifragem."
+ "Sala privada (entrada apenas por convite)"
+ "As mensagens não serão cifradas e qualquer um as poderá ler. É possível ativar a cifragem posteriormente."
+ "Sala pública (entrada livre)"
+ "Nome da sala"
+ "Criar uma sala"
+ "Descrição (opcional)"
+ "Ocorreu um erro ao tentar iniciar uma conversa"
+
diff --git a/features/createroom/impl/src/main/res/values-zh/translations.xml b/features/createroom/impl/src/main/res/values-zh/translations.xml
new file mode 100644
index 0000000000..4a5c2120a2
--- /dev/null
+++ b/features/createroom/impl/src/main/res/values-zh/translations.xml
@@ -0,0 +1,14 @@
+
+
+ "新聊天室"
+ "邀请朋友"
+ "创建房间时出错"
+ "此聊天室中的消息已加密。加密无法禁用。"
+ "私人房间(仅限受邀者)"
+ "消息未加密,任何人都可以查看。你可以稍后启用加密。"
+ "公共房间(任何人)"
+ "房间名称"
+ "创建房间"
+ "主题(可选)"
+ "在开始聊天时发生了错误"
+
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 772343ea58..6720fa0274 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
@@ -132,9 +132,8 @@ class FtueFlowNode @AssistedInject constructor(
lifecycleScope.launch { moveToNextStep() }
}
}
- lockScreenEntryPoint.nodeBuilder(this, buildContext)
+ lockScreenEntryPoint.nodeBuilder(this, buildContext, LockScreenEntryPoint.Target.Setup)
.callback(callback)
- .target(LockScreenEntryPoint.Target.Setup)
.build()
}
}
diff --git a/features/ftue/impl/src/main/res/values-be/translations.xml b/features/ftue/impl/src/main/res/values-be/translations.xml
index e9666b57e3..8496f9f631 100644
--- a/features/ftue/impl/src/main/res/values-be/translations.xml
+++ b/features/ftue/impl/src/main/res/values-be/translations.xml
@@ -11,11 +11,12 @@
"Злучэнне небяспечнае"
"Вам будзе прапанавана ўвесці дзве лічбы, паказаныя на гэтай прыладзе."
"Увядзіце наступны нумар на іншай прыладзе."
+ "Гатовы да сканавання"
"Адкрыйце %1$s на настольнай прыладзе"
"Націсніце на свой аватар"
"Выберыце %1$s"
"“Звязаць новую прыладу”"
- "Выконвайце паказаныя інструкцыі"
+ "Адсканіруйце QR-код з дапамогай гэтай прылады"
"Адкрыйце %1$s на іншай прыладзе, каб атрымаць QR-код"
"Выкарыстоўвайце QR-код, паказаны на іншай прыладзе."
"Паўтарыць спробу"
diff --git a/features/ftue/impl/src/main/res/values-cs/translations.xml b/features/ftue/impl/src/main/res/values-cs/translations.xml
index b6c0efa729..e27eeb7404 100644
--- a/features/ftue/impl/src/main/res/values-cs/translations.xml
+++ b/features/ftue/impl/src/main/res/values-cs/translations.xml
@@ -11,11 +11,12 @@
"Připojení není zabezpečené"
"Budete požádáni o zadání dvou níže uvedených číslic."
"Zadejte níže uvedené číslo na svém dalším zařízení"
+ "Připraveno ke skenování"
"Otevřete %1$s na stolním počítači"
"Klikněte na svůj avatar"
"Vybrat %1$s"
"\"Připojit nové zařízení\""
- "Postupujte podle uvedených pokynů"
+ "Naskenujte QR kód pomocí tohoto zařízení"
"Otevřete %1$s na jiném zařízení pro získání QR kódu"
"Použijte QR kód zobrazený na druhém zařízení."
"Zkusit znovu"
diff --git a/features/ftue/impl/src/main/res/values-de/translations.xml b/features/ftue/impl/src/main/res/values-de/translations.xml
index 4640cf119c..41fe886ee6 100644
--- a/features/ftue/impl/src/main/res/values-de/translations.xml
+++ b/features/ftue/impl/src/main/res/values-de/translations.xml
@@ -11,11 +11,12 @@
"Die Verbindung ist nicht sicher"
"Du wirst aufgefordert, die beiden unten abgebildeten Ziffern einzugeben."
"Trage die unten angezeigte Zahl auf einem anderen Device ein"
+ "Bereit zum Scannen"
"%1$s auf einem Desktop-Gerät öffnen"
"Klick auf deinen Avatar"
"Wähle %1$s"
"\"Neues Gerät verknüpfen\""
- "Befolge die angezeigten Anweisungen"
+ "Scanne den QR-Code mit diesem Gerät"
"Öffne %1$s auf einem anderen Gerät, um den QR-Code zu erhalten"
"Verwende den QR-Code, der auf dem anderen Gerät angezeigt wird."
"Erneut versuchen"
diff --git a/features/ftue/impl/src/main/res/values-hu/translations.xml b/features/ftue/impl/src/main/res/values-hu/translations.xml
index e5c11f0c2b..0d463d2900 100644
--- a/features/ftue/impl/src/main/res/values-hu/translations.xml
+++ b/features/ftue/impl/src/main/res/values-hu/translations.xml
@@ -11,11 +11,12 @@
"A kapcsolat nem biztonságos"
"A rendszer kérni fogja, hogy adja meg az alábbi két számjegyet az eszközén."
"Adja meg az alábbi számot a másik eszközén"
+ "Készen áll a beolvasásra"
"Nyissa meg az %1$set egy asztali eszközön"
"Kattintson a profilképére"
"Válassza ezt: %1$s"
"„Új eszköz összekapcsolása”"
- "Kövesse a látható utasításokat"
+ "Olvassa be a QR-kódot ezzel az eszközzel"
"Nyissa meg az %1$set egy másik eszközön a QR-kód lekéréséhez."
"Használja a másik eszközön látható QR-kódot."
"Próbálja újra"
diff --git a/features/ftue/impl/src/main/res/values-it/translations.xml b/features/ftue/impl/src/main/res/values-it/translations.xml
index 8c253c8c5a..cb81d4d97a 100644
--- a/features/ftue/impl/src/main/res/values-it/translations.xml
+++ b/features/ftue/impl/src/main/res/values-it/translations.xml
@@ -2,7 +2,33 @@
"Potrai modificare le tue impostazioni in seguito."
"Consenti le notifiche e non perdere mai un messaggio"
+ "Stabilendo la connessione"
+ "Non è stato possibile stabilire una connessione sicura con il nuovo dispositivo. I tuoi dispositivi esistenti sono ancora al sicuro e non devi preoccuparti di loro."
+ "E adesso?"
+ "Prova ad accedere di nuovo con un codice QR nel caso si sia verificato un problema di rete."
+ "Se riscontri lo stesso problema, prova con un altra rete wifi o usa i dati mobili al posto del wifi."
+ "Se il problema persiste, accedi manualmente"
+ "La connessione non è sicura"
+ "Ti verrà chiesto di inserire le due cifre mostrate su questo dispositivo."
+ "Inserisci il numero qui sotto sull\'altro dispositivo"
+ "Apri %1$s su un dispositivo desktop"
+ "Clicca sul tuo avatar"
+ "Seleziona %1$s"
+ "\"Collega un nuovo dispositivo\""
+ "Segui le istruzioni mostrate"
+ "Apri %1$s su un altro dispositivo per ottenere il codice QR"
+ "Usa il codice QR mostrato sull\'altro dispositivo."
"Riprova"
+ "Codice QR sbagliato"
+ "Vai alle impostazioni della fotocamera"
+ "Per continuare, è necessario fornire l\'autorizzazione a %1$s per utilizzare la fotocamera del dispositivo."
+ "Consenti l\'accesso alla fotocamera per la scansione del codice QR"
+ "Scansiona il codice QR"
+ "Ricomincia"
+ "Si è verificato un errore inatteso. Riprova."
+ "In attesa dell\'altro dispositivo"
+ "Il fornitore dell\'account potrebbe richiedere il seguente codice per verificare l\'accesso."
+ "Il tuo codice di verifica"
"Chiamate, sondaggi, ricerche e altro ancora saranno aggiunti nel corso dell\'anno."
"La cronologia dei messaggi per le stanze crittografate non è ancora disponibile."
"Ci piacerebbe sentire il tuo parere, facci sapere cosa ne pensi tramite la pagina delle impostazioni."
diff --git a/features/ftue/impl/src/main/res/values-ka/translations.xml b/features/ftue/impl/src/main/res/values-ka/translations.xml
new file mode 100644
index 0000000000..04aacccf83
--- /dev/null
+++ b/features/ftue/impl/src/main/res/values-ka/translations.xml
@@ -0,0 +1,11 @@
+
+
+ "თქვენ შეგიძლიათ შეცვალოთ თქვენი პარამეტრები მოგვიანებით."
+ "ყველა შეტყობინებაზე შეტყობინებების მიღება"
+ "ზარები, გამოკითხვები, ძიება და სხვა დაემატება ამ წლის ბოლოს."
+ "დაშიფრული ოთახებისთვის შეტყობინებების ისტორია ჯერ არ არის ხელმისაწვდომი."
+ "ჩვენ სიამოვნებით მოვისმინოთ თქვენგან, შეგვატყობინეთ რას ფიქრობთ პარამეტრების გვერდზე."
+ "დავიწყოთ!"
+ "აი, რა უნდა იცოდეთ:"
+ "კეთილი იყოს თქვენი მობრძანება %1$s-ში!"
+
diff --git a/features/ftue/impl/src/main/res/values-pt/translations.xml b/features/ftue/impl/src/main/res/values-pt/translations.xml
new file mode 100644
index 0000000000..5b2660f6c6
--- /dev/null
+++ b/features/ftue/impl/src/main/res/values-pt/translations.xml
@@ -0,0 +1,39 @@
+
+
+ "Podes alterar as tuas definições mais tarde."
+ "Permite as notificações e nunca percas uma mensagem"
+ "A estabelecer uma ligação segura"
+ "Não foi possível estabelecer uma ligação segura com o novo dispositivo. Os teus outros dispositivos continuam seguros, não precisas de te preocupar com eles."
+ "E agora?"
+ "Tenta iniciar sessão novamente com um código QR, caso se trate de um problema de rede"
+ "Se tiveres o mesmo problema, experimenta uma rede Wi-Fi diferente ou utiliza os teus dados móveis."
+ "Se isso não funcionar, inicia sessão manualmente"
+ "Ligação insegura"
+ "Ser-te-á pedido que insiras os dois dígitos indicados neste dispositivo."
+ "Insere o número abaixo no teu dispositivo"
+ "Pronto para ler"
+ "Abre a %1$s num computador"
+ "Carrega no teu avatar"
+ "Seleciona %1$s"
+ "“Ligar novo dispositivo”"
+ "Lê o código QR com este dispositivo"
+ "Abre a %1$s noutro dispositivo para obteres o código QR"
+ "Lê o código QR apresentado no outro dispositivo."
+ "Tentar novamente"
+ "Código QR inválido"
+ "Ir para as configurações da câmara"
+ "Para continuar, tens que dar permissão à %1$s para aceder à câmara do teu dispositivo."
+ "Permitir o acesso à câmara para ler o código QR"
+ "Ler o código QR"
+ "Começar de novo"
+ "Ocorreu um erro inesperado. Tenta novamente."
+ "À espera do teu outro dispositivo"
+ "O teu fornecedor de conta pode pedir o seguinte código para verificar o início de sessão."
+ "O teu código de verificação"
+ "Chamadas, sondagens, pesquisa e mais funcionalidades vão ser adicionadas ao longo do ano."
+ "O histórico de mensagens em salas cifradas ainda não está disponível."
+ "Gostaríamos de ouvir a tua opinião, diz-nos o que pensas através da página de configurações."
+ "Vamos lá!"
+ "Eis o que tens de saber:"
+ "Bem-vindo à %1$s!"
+
diff --git a/features/ftue/impl/src/main/res/values-ro/translations.xml b/features/ftue/impl/src/main/res/values-ro/translations.xml
index 492e333fe2..58482738d6 100644
--- a/features/ftue/impl/src/main/res/values-ro/translations.xml
+++ b/features/ftue/impl/src/main/res/values-ro/translations.xml
@@ -2,7 +2,34 @@
"Puteți modifica setările mai târziu."
"Permiteți notificările și nu pierdeți niciodată un mesaj"
+ "Se stabilește o conexiune securizată"
+ "Nu a putut fi făcută o conexiune sigură la noul dispozitiv. Dispozitivele existente sunt încă în siguranță și nu trebuie să vă faceți griji cu privire la ele."
+ "Și acum?"
+ "Încercați să vă conectați din nou cu un cod QR în cazul în care a fost o problemă de rețea."
+ "Dacă întâmpinați aceeași problemă, încercați o altă rețea Wi-Fi sau utilizați datele mobile în loc de Wi-Fi."
+ "Dacă nu funcționează, conectați-vă manual"
+ "Conexiunea nu este sigură"
+ "Vi se va cere să introduceți cele două cifre afișate pe acest dispozitiv."
+ "Introduceți numărul de mai jos pe celălalt dispozitiv"
+ "Gata de scanare"
+ "Deschideți %1$s pe un dispozitiv desktop"
+ "Faceți clic pe avatarul dumneavoastră"
+ "Selectați %1$s"
+ "„Conectați un dispozitiv nou”"
+ "Scanați codul QR cu acest dispozitiv"
+ "Deschideți %1$s pe un alt dispozitiv pentru a obține codul QR"
+ "Utilizați codul QR afișat pe celălalt dispozitiv."
"Încercați din nou"
+ "Cod QR greșit"
+ "Mergeți la setările camerei"
+ "Trebuie să acordați permisiunea ca %1$s să folosească camera dispozitivului pentru a continua."
+ "Permiteți accesul la cameră pentru a scana codul QR"
+ "Scanați codul QR"
+ "Începeți din nou"
+ "A apărut o eroare neașteptată. Vă rugăm să încercați din nou."
+ "În așteptarea celuilalt dispozitiv"
+ "Furnizorul dumneavoastră de cont poate solicita următorul cod pentru a verifica conectarea."
+ "Codul dumneavoastră de verificare"
"Apelurile, sondajele, căutare și multe altele vor fi adăugate în cursul acestui an."
"Istoricul mesajelor pentru camerele criptate nu va fi disponibil în această actualizare."
"Ne-ar plăcea să auzim de la dumneavoastră, spuneți-ne ce părere aveți prin intermediul paginii de setări."
diff --git a/features/ftue/impl/src/main/res/values-ru/translations.xml b/features/ftue/impl/src/main/res/values-ru/translations.xml
index 3fe5ceefc2..300647b7f0 100644
--- a/features/ftue/impl/src/main/res/values-ru/translations.xml
+++ b/features/ftue/impl/src/main/res/values-ru/translations.xml
@@ -2,19 +2,20 @@
"Вы можете изменить настройки позже."
"Разрешите уведомления и никогда не пропустите сообщение"
- "Установление соединения"
+ "Установление безопасного соединения"
"Не удалось установить безопасное соединение с новым устройством. Существующие устройства по-прежнему в безопасности, и вам не нужно беспокоиться о них."
"Что теперь?"
"Попробуйте снова войти в систему с помощью QR-кода, если это была сетевая проблема"
"Если вы столкнулись с той же проблемой, попробуйте сменить точку доступа Wi-Fi или используйте мобильные данные"
"Если это не помогло, войдите вручную"
"Соединение не защищено"
- "Вам будет предложено ввести две цифры, показанные ниже."
- "Введите номер на своем устройстве"
+ "Вам нужно будет ввести две цифры, показанные на этом устройстве."
+ "Введите показанный номер на своем другом устройстве"
"Откройте %1$s на настольном устройстве"
"Нажмите на свое изображение"
"Выбрать %1$s"
"\"Привязать новое устройство\""
+ "Соблюдайте показанную инструкцию"
"Откройте %1$s на другом устройстве, чтобы получить QR-код"
"Используйте QR-код, показанный на другом устройстве."
"Повторить попытку"
diff --git a/features/ftue/impl/src/main/res/values-sk/translations.xml b/features/ftue/impl/src/main/res/values-sk/translations.xml
index 593fe78182..0344f5588e 100644
--- a/features/ftue/impl/src/main/res/values-sk/translations.xml
+++ b/features/ftue/impl/src/main/res/values-sk/translations.xml
@@ -11,11 +11,12 @@
"Pripojenie nie je bezpečené"
"Budete požiadaní o zadanie dvoch číslic zobrazených na tomto zariadení."
"Zadajte nižšie uvedené číslo na vašom druhom zariadení"
+ "Pripravené na skenovanie"
"Otvorte %1$s na stolnom zariadení"
"Kliknite na svoj obrázok"
"Vyberte %1$s"
"„Prepojiť nové zariadenie“"
- "Postupujte podľa zobrazených pokynov"
+ "Naskenujte QR kód pomocou tohto zariadenia"
"Ak chcete získať QR kód, otvorte %1$s na inom zariadení"
"Použite QR kód zobrazený na druhom zariadení."
"Skúste to znova"
diff --git a/features/ftue/impl/src/main/res/values-zh/translations.xml b/features/ftue/impl/src/main/res/values-zh/translations.xml
new file mode 100644
index 0000000000..f6432fb3c6
--- /dev/null
+++ b/features/ftue/impl/src/main/res/values-zh/translations.xml
@@ -0,0 +1,38 @@
+
+
+ "您可以稍后更改设置。"
+ "允许通知,绝不错过任何消息"
+ "建立安全连接"
+ "无法与新设备建立安全连接。您现有的设备仍然安全,无需担心。"
+ "现在怎么办?"
+ "如果这是网络问题,请尝试使用二维码再次登录"
+ "如果你遇到同样的问题,请尝试使用不同的 WiFi 网络或使用你的移动数据代替 WiFi"
+ "如果不起作用,请手动登录"
+ "连接不安全"
+ "您会被要求输入此设备上显示的两位数。"
+ "在您的其他设备上输入下面的数字"
+ "在桌面设备上打开 %1$s"
+ "点击你的头像"
+ "选择 %1$s"
+ "「连接新设备」"
+ "按照说明进行操作"
+ "在另一台设备上打开 %1$s 以获取二维码"
+ "使用其他设备上显示的二维码。"
+ "再试一次"
+ "二维码错误"
+ "转到摄像头设置"
+ "您需要授予 %1$s 使用设备摄像头的权限才能继续。"
+ "允许摄像头权限以扫描 QR 码"
+ "扫描二维码"
+ "重新开始"
+ "发生了意外错误。请再试一次。"
+ "等着您的其他设备"
+ "您的账户提供商可能会要求您提供以下代码来验证登录。"
+ "您的验证码"
+ "今年晚些时候将增加通话、投票、搜索等功能。"
+ "加密房间的消息历史记录尚不可用。"
+ "我们很乐意听取您的意见,请通过设置页面告诉我们您的想法。"
+ "开始吧!"
+ "以下是您需要了解的内容:"
+ "欢迎使用 %1$s"
+
diff --git a/features/ftue/impl/src/main/res/values/localazy.xml b/features/ftue/impl/src/main/res/values/localazy.xml
index 9264bfd4b1..256dcbae31 100644
--- a/features/ftue/impl/src/main/res/values/localazy.xml
+++ b/features/ftue/impl/src/main/res/values/localazy.xml
@@ -11,11 +11,12 @@
"Connection not secure"
"You’ll be asked to enter the two digits shown on this device."
"Enter the number below on your other device"
+ "Ready to scan"
"Open %1$s on a desktop device"
"Click on your avatar"
"Select %1$s"
"“Link new device”"
- "Follow the instructions shown"
+ "Scan the QR code with this device"
"Open %1$s on another device to get the QR code"
"Use the QR code shown on the other device."
"Try again"
diff --git a/features/invite/api/build.gradle.kts b/features/invite/api/build.gradle.kts
index 52df82e38a..95fceb41f2 100644
--- a/features/invite/api/build.gradle.kts
+++ b/features/invite/api/build.gradle.kts
@@ -25,4 +25,5 @@ android {
dependencies {
implementation(projects.libraries.architecture)
implementation(projects.libraries.matrix.api)
+ implementation(projects.services.analytics.api)
}
diff --git a/features/invite/impl/src/main/kotlin/io/element/android/features/invite/impl/response/AcceptDeclineInvitePresenter.kt b/features/invite/impl/src/main/kotlin/io/element/android/features/invite/impl/response/AcceptDeclineInvitePresenter.kt
index ec18aea045..05ba21b98d 100644
--- a/features/invite/impl/src/main/kotlin/io/element/android/features/invite/impl/response/AcceptDeclineInvitePresenter.kt
+++ b/features/invite/impl/src/main/kotlin/io/element/android/features/invite/impl/response/AcceptDeclineInvitePresenter.kt
@@ -33,9 +33,8 @@ import io.element.android.libraries.architecture.runCatchingUpdatingState
import io.element.android.libraries.architecture.runUpdatingState
import io.element.android.libraries.matrix.api.MatrixClient
import io.element.android.libraries.matrix.api.core.RoomId
+import io.element.android.libraries.matrix.api.room.join.JoinRoom
import io.element.android.libraries.push.api.notifications.NotificationDrawerManager
-import io.element.android.services.analytics.api.AnalyticsService
-import io.element.android.services.analytics.api.extensions.toAnalyticsJoinedRoom
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.launch
import java.util.Optional
@@ -44,7 +43,7 @@ import kotlin.jvm.optionals.getOrNull
class AcceptDeclineInvitePresenter @Inject constructor(
private val client: MatrixClient,
- private val analyticsService: AnalyticsService,
+ private val joinRoom: JoinRoom,
private val notificationDrawerManager: NotificationDrawerManager,
) : Presenter {
@Composable
@@ -59,9 +58,11 @@ class AcceptDeclineInvitePresenter @Inject constructor(
fun handleEvents(event: AcceptDeclineInviteEvents) {
when (event) {
is AcceptDeclineInviteEvents.AcceptInvite -> {
- currentInvite = Optional.of(event.invite)
- localCoroutineScope.acceptInvite(event.invite.roomId, acceptedAction)
+ // currentInvite is used to render the decline confirmation dialog
+ // and to reuse the roomId when the user confirm the rejection of the invitation.
+ // Just set it to empty here.
currentInvite = Optional.empty()
+ localCoroutineScope.acceptInvite(event.invite.roomId, acceptedAction)
}
is AcceptDeclineInviteEvents.DeclineInvite -> {
@@ -100,14 +101,18 @@ class AcceptDeclineInvitePresenter @Inject constructor(
)
}
- private fun CoroutineScope.acceptInvite(roomId: RoomId, acceptedAction: MutableState>) = launch {
+ private fun CoroutineScope.acceptInvite(
+ roomId: RoomId,
+ acceptedAction: MutableState>,
+ ) = launch {
acceptedAction.runUpdatingState {
- client.joinRoom(roomId)
+ joinRoom(
+ roomId = roomId,
+ serverNames = emptyList(),
+ trigger = JoinedRoom.Trigger.Invite,
+ )
.onSuccess {
notificationDrawerManager.clearMembershipNotificationForRoom(client.sessionId, roomId, doRender = true)
- client.getRoom(roomId)?.use { room ->
- analyticsService.capture(room.toAnalyticsJoinedRoom(JoinedRoom.Trigger.Invite))
- }
}
.map { roomId }
}
diff --git a/features/invite/impl/src/main/res/values-ka/translations.xml b/features/invite/impl/src/main/res/values-ka/translations.xml
new file mode 100644
index 0000000000..3accaf9eda
--- /dev/null
+++ b/features/invite/impl/src/main/res/values-ka/translations.xml
@@ -0,0 +1,9 @@
+
+
+ "დარწმუნებული ხართ, რომ გსურთ, უარი თქვათ მოწვევაზე %1$s-ში?"
+ "მოწვევაზე უარის თქმა"
+ "დარწმუნებული ხართ, რომ გსურთ, უარი თქვათ ჩატზე %1$s-თან?"
+ "ჩატზე უარის თქვა"
+ "მოწვევები არ არის"
+ "%1$s (%2$s) მოგიწვიათ"
+
diff --git a/features/invite/impl/src/main/res/values-pt/translations.xml b/features/invite/impl/src/main/res/values-pt/translations.xml
new file mode 100644
index 0000000000..1bdde3eaee
--- /dev/null
+++ b/features/invite/impl/src/main/res/values-pt/translations.xml
@@ -0,0 +1,9 @@
+
+
+ "Tens a certeza que queres rejeitar o convite para %1$s?"
+ "Rejeitar conite"
+ "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/main/res/values-zh/translations.xml b/features/invite/impl/src/main/res/values-zh/translations.xml
new file mode 100644
index 0000000000..3d25434438
--- /dev/null
+++ b/features/invite/impl/src/main/res/values-zh/translations.xml
@@ -0,0 +1,9 @@
+
+
+ "您确定要拒绝加入 %1$s 的邀请吗?"
+ "拒绝邀请"
+ "您确定要拒绝与 %1$s 开始私聊吗?"
+ "拒绝聊天"
+ "没有邀请"
+ "%1$s (%2$s)邀请了你"
+
diff --git a/features/invite/impl/src/test/kotlin/io/element/android/features/invite/impl/response/AcceptDeclineInvitePresenterTest.kt b/features/invite/impl/src/test/kotlin/io/element/android/features/invite/impl/response/AcceptDeclineInvitePresenterTest.kt
index 90dcc104d4..247df956e6 100644
--- a/features/invite/impl/src/test/kotlin/io/element/android/features/invite/impl/response/AcceptDeclineInvitePresenterTest.kt
+++ b/features/invite/impl/src/test/kotlin/io/element/android/features/invite/impl/response/AcceptDeclineInvitePresenterTest.kt
@@ -17,6 +17,7 @@
package io.element.android.features.invite.impl.response
import com.google.common.truth.Truth.assertThat
+import im.vector.app.features.analytics.plan.JoinedRoom
import io.element.android.features.invite.api.response.AcceptDeclineInviteEvents
import io.element.android.features.invite.api.response.InviteData
import io.element.android.libraries.architecture.AsyncAction
@@ -26,13 +27,13 @@ import io.element.android.libraries.matrix.test.A_ROOM_ID
import io.element.android.libraries.matrix.test.A_ROOM_NAME
import io.element.android.libraries.matrix.test.FakeMatrixClient
import io.element.android.libraries.matrix.test.room.FakeMatrixRoom
+import io.element.android.libraries.matrix.test.room.join.FakeJoinRoom
import io.element.android.libraries.push.api.notifications.NotificationDrawerManager
import io.element.android.libraries.push.test.notifications.FakeNotificationDrawerManager
-import io.element.android.services.analytics.api.AnalyticsService
-import io.element.android.services.analytics.test.FakeAnalyticsService
import io.element.android.tests.testutils.WarmUpRule
import io.element.android.tests.testutils.lambda.assert
import io.element.android.tests.testutils.lambda.lambdaRecorder
+import io.element.android.tests.testutils.lambda.value
import io.element.android.tests.testutils.test
import kotlinx.coroutines.test.runTest
import org.junit.Rule
@@ -163,13 +164,10 @@ class AcceptDeclineInvitePresenterTest {
@Test
fun `present - accepting invite error flow`() = runTest {
- val joinRoomFailure = lambdaRecorder { roomId: RoomId ->
+ val joinRoomFailure = lambdaRecorder { roomId: RoomId, _: List, _: JoinedRoom.Trigger ->
Result.failure(RuntimeException("Failed to join room $roomId"))
}
- val client = FakeMatrixClient().apply {
- joinRoomLambda = joinRoomFailure
- }
- val presenter = createAcceptDeclineInvitePresenter(client = client)
+ val presenter = createAcceptDeclineInvitePresenter(joinRoomLambda = joinRoomFailure)
presenter.test {
val inviteData = anInviteData()
awaitItem().also { state ->
@@ -177,33 +175,35 @@ class AcceptDeclineInvitePresenterTest {
AcceptDeclineInviteEvents.AcceptInvite(inviteData)
)
}
- skipItems(1)
awaitItem().also { state ->
- assertThat(state.invite).isEqualTo(Optional.of(inviteData))
+ assertThat(state.invite).isEqualTo(Optional.empty())
+ assertThat(state.acceptAction).isEqualTo(AsyncAction.Loading)
+ }
+ awaitItem().also { state ->
assertThat(state.acceptAction).isInstanceOf(AsyncAction.Failure::class.java)
state.eventSink(
InternalAcceptDeclineInviteEvents.DismissAcceptError
)
}
- skipItems(1)
awaitItem().also { state ->
assertThat(state.invite).isEqualTo(Optional.empty())
assertThat(state.acceptAction).isInstanceOf(AsyncAction.Uninitialized::class.java)
}
cancelAndConsumeRemainingEvents()
}
- assert(joinRoomFailure).isCalledOnce()
+ assert(joinRoomFailure)
+ .isCalledExactly(1)
+ .withSequence(
+ listOf(value(A_ROOM_ID), value(emptyList()), value(JoinedRoom.Trigger.Invite))
+ )
}
@Test
fun `present - accepting invite success flow`() = runTest {
- val joinRoomSuccess = lambdaRecorder { _: RoomId ->
+ val joinRoomSuccess = lambdaRecorder { _: RoomId, _: List, _: JoinedRoom.Trigger ->
Result.success(Unit)
}
- val client = FakeMatrixClient().apply {
- joinRoomLambda = joinRoomSuccess
- }
- val presenter = createAcceptDeclineInvitePresenter(client = client)
+ val presenter = createAcceptDeclineInvitePresenter(joinRoomLambda = joinRoomSuccess)
presenter.test {
val inviteData = anInviteData()
awaitItem().also { state ->
@@ -211,14 +211,20 @@ class AcceptDeclineInvitePresenterTest {
AcceptDeclineInviteEvents.AcceptInvite(inviteData)
)
}
- skipItems(1)
awaitItem().also { state ->
- assertThat(state.invite).isEqualTo(Optional.of(inviteData))
+ assertThat(state.invite).isEqualTo(Optional.empty())
+ assertThat(state.acceptAction).isEqualTo(AsyncAction.Loading)
+ }
+ awaitItem().also { state ->
assertThat(state.acceptAction).isInstanceOf(AsyncAction.Success::class.java)
}
cancelAndConsumeRemainingEvents()
}
- assert(joinRoomSuccess).isCalledOnce()
+ assert(joinRoomSuccess)
+ .isCalledExactly(1)
+ .withSequence(
+ listOf(value(A_ROOM_ID), value(emptyList()), value(JoinedRoom.Trigger.Invite))
+ )
}
private fun anInviteData(
@@ -235,12 +241,14 @@ class AcceptDeclineInvitePresenterTest {
private fun createAcceptDeclineInvitePresenter(
client: MatrixClient = FakeMatrixClient(),
- analyticsService: AnalyticsService = FakeAnalyticsService(),
+ joinRoomLambda: (RoomId, List, JoinedRoom.Trigger) -> Result = { _, _, _ ->
+ Result.success(Unit)
+ },
notificationDrawerManager: NotificationDrawerManager = FakeNotificationDrawerManager(),
): AcceptDeclineInvitePresenter {
return AcceptDeclineInvitePresenter(
client = client,
- analyticsService = analyticsService,
+ joinRoom = FakeJoinRoom(joinRoomLambda),
notificationDrawerManager = notificationDrawerManager,
)
}
diff --git a/features/joinroom/api/build.gradle.kts b/features/joinroom/api/build.gradle.kts
index a016c2d195..461723f785 100644
--- a/features/joinroom/api/build.gradle.kts
+++ b/features/joinroom/api/build.gradle.kts
@@ -26,4 +26,5 @@ dependencies {
implementation(projects.libraries.architecture)
implementation(projects.libraries.matrix.api)
implementation(projects.features.roomdirectory.api)
+ implementation(projects.services.analytics.api)
}
diff --git a/features/joinroom/api/src/main/kotlin/io/element/android/features/joinroom/api/JoinRoomEntryPoint.kt b/features/joinroom/api/src/main/kotlin/io/element/android/features/joinroom/api/JoinRoomEntryPoint.kt
index d62a9819c9..04ca23340e 100644
--- a/features/joinroom/api/src/main/kotlin/io/element/android/features/joinroom/api/JoinRoomEntryPoint.kt
+++ b/features/joinroom/api/src/main/kotlin/io/element/android/features/joinroom/api/JoinRoomEntryPoint.kt
@@ -18,6 +18,7 @@ package io.element.android.features.joinroom.api
import com.bumble.appyx.core.modality.BuildContext
import com.bumble.appyx.core.node.Node
+import im.vector.app.features.analytics.plan.JoinedRoom
import io.element.android.features.roomdirectory.api.RoomDescription
import io.element.android.libraries.architecture.FeatureEntryPoint
import io.element.android.libraries.architecture.NodeInputs
@@ -32,5 +33,7 @@ interface JoinRoomEntryPoint : FeatureEntryPoint {
val roomId: RoomId,
val roomIdOrAlias: RoomIdOrAlias,
val roomDescription: Optional,
+ val serverNames: List,
+ val trigger: JoinedRoom.Trigger,
) : NodeInputs
}
diff --git a/features/joinroom/impl/build.gradle.kts b/features/joinroom/impl/build.gradle.kts
index 33fdbb6b47..319f15eea4 100644
--- a/features/joinroom/impl/build.gradle.kts
+++ b/features/joinroom/impl/build.gradle.kts
@@ -44,9 +44,10 @@ dependencies {
implementation(projects.libraries.matrix.api)
implementation(projects.libraries.matrixui)
implementation(projects.libraries.designsystem)
+ implementation(projects.libraries.uiStrings)
implementation(projects.features.invite.api)
implementation(projects.features.roomdirectory.api)
- implementation(projects.libraries.uiStrings)
+ implementation(projects.services.analytics.api)
testImplementation(libs.test.junit)
testImplementation(libs.coroutines.test)
diff --git a/features/joinroom/impl/src/main/kotlin/io/element/android/features/joinroom/impl/JoinRoomNode.kt b/features/joinroom/impl/src/main/kotlin/io/element/android/features/joinroom/impl/JoinRoomNode.kt
index 5d302abc8b..2cddd9d45b 100644
--- a/features/joinroom/impl/src/main/kotlin/io/element/android/features/joinroom/impl/JoinRoomNode.kt
+++ b/features/joinroom/impl/src/main/kotlin/io/element/android/features/joinroom/impl/JoinRoomNode.kt
@@ -41,6 +41,8 @@ class JoinRoomNode @AssistedInject constructor(
inputs.roomId,
inputs.roomIdOrAlias,
inputs.roomDescription,
+ inputs.serverNames,
+ inputs.trigger,
)
@Composable
@@ -49,6 +51,7 @@ class JoinRoomNode @AssistedInject constructor(
JoinRoomView(
state = state,
onBackPressed = ::navigateUp,
+ onJoinSuccess = ::navigateUp,
onKnockSuccess = ::navigateUp,
modifier = modifier
)
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 ea88150c78..5f1efe827e 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
@@ -29,6 +29,7 @@ import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.runtime.setValue
import dagger.assisted.Assisted
import dagger.assisted.AssistedInject
+import im.vector.app.features.analytics.plan.JoinedRoom
import io.element.android.features.invite.api.response.AcceptDeclineInviteEvents
import io.element.android.features.invite.api.response.AcceptDeclineInviteState
import io.element.android.features.invite.api.response.InviteData
@@ -41,10 +42,10 @@ import io.element.android.libraries.core.meta.BuildMeta
import io.element.android.libraries.matrix.api.MatrixClient
import io.element.android.libraries.matrix.api.core.RoomId
import io.element.android.libraries.matrix.api.core.RoomIdOrAlias
-import io.element.android.libraries.matrix.api.core.toRoomIdOrAlias
import io.element.android.libraries.matrix.api.room.CurrentUserMembership
import io.element.android.libraries.matrix.api.room.MatrixRoomInfo
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.preview.RoomPreview
import io.element.android.libraries.matrix.ui.model.toInviteSender
import kotlinx.coroutines.CoroutineScope
@@ -55,7 +56,10 @@ class JoinRoomPresenter @AssistedInject constructor(
@Assisted private val roomId: RoomId,
@Assisted private val roomIdOrAlias: RoomIdOrAlias,
@Assisted private val roomDescription: Optional,
+ @Assisted private val serverNames: List,
+ @Assisted private val trigger: JoinedRoom.Trigger,
private val matrixClient: MatrixClient,
+ private val joinRoom: JoinRoom,
private val knockRoom: KnockRoom,
private val acceptDeclineInvitePresenter: Presenter,
private val buildMeta: BuildMeta,
@@ -65,6 +69,8 @@ class JoinRoomPresenter @AssistedInject constructor(
roomId: RoomId,
roomIdOrAlias: RoomIdOrAlias,
roomDescription: Optional,
+ serverNames: List,
+ trigger: JoinedRoom.Trigger,
): JoinRoomPresenter
}
@@ -73,6 +79,7 @@ class JoinRoomPresenter @AssistedInject constructor(
val coroutineScope = rememberCoroutineScope()
var retryCount by remember { mutableIntStateOf(0) }
val roomInfo by matrixClient.getRoomInfoFlow(roomId).collectAsState(initial = Optional.empty())
+ val joinAction: MutableState> = remember { mutableStateOf(AsyncAction.Uninitialized) }
val knockAction: MutableState> = remember { mutableStateOf(AsyncAction.Uninitialized) }
val contentState by produceState(
initialValue = ContentState.Loading(roomIdOrAlias),
@@ -88,7 +95,7 @@ class JoinRoomPresenter @AssistedInject constructor(
}
else -> {
value = ContentState.Loading(roomIdOrAlias)
- val result = matrixClient.getRoomPreview(roomId.toRoomIdOrAlias())
+ val result = matrixClient.getRoomPreviewFromRoomId(roomId, serverNames)
value = result.fold(
onSuccess = { roomPreview ->
roomPreview.toContentState()
@@ -108,16 +115,14 @@ class JoinRoomPresenter @AssistedInject constructor(
fun handleEvents(event: JoinRoomEvents) {
when (event) {
- JoinRoomEvents.AcceptInvite,
- JoinRoomEvents.JoinRoom -> {
+ JoinRoomEvents.JoinRoom -> coroutineScope.joinRoom(joinAction)
+ JoinRoomEvents.KnockRoom -> coroutineScope.knockRoom(knockAction)
+ JoinRoomEvents.AcceptInvite -> {
val inviteData = contentState.toInviteData() ?: return
acceptDeclineInviteState.eventSink(
AcceptDeclineInviteEvents.AcceptInvite(inviteData)
)
}
- JoinRoomEvents.KnockRoom -> {
- coroutineScope.knockRoom(roomId, knockAction)
- }
JoinRoomEvents.DeclineInvite -> {
val inviteData = contentState.toInviteData() ?: return
acceptDeclineInviteState.eventSink(
@@ -129,6 +134,7 @@ class JoinRoomPresenter @AssistedInject constructor(
}
JoinRoomEvents.ClearError -> {
knockAction.value = AsyncAction.Uninitialized
+ joinAction.value = AsyncAction.Uninitialized
}
}
}
@@ -136,13 +142,24 @@ class JoinRoomPresenter @AssistedInject constructor(
return JoinRoomState(
contentState = contentState,
acceptDeclineInviteState = acceptDeclineInviteState,
+ joinAction = joinAction.value,
knockAction = knockAction.value,
applicationName = buildMeta.applicationName,
eventSink = ::handleEvents
)
}
- private fun CoroutineScope.knockRoom(roomId: RoomId, knockAction: MutableState>) = launch {
+ private fun CoroutineScope.joinRoom(joinAction: MutableState>) = launch {
+ joinAction.runUpdatingState {
+ joinRoom.invoke(
+ roomId = roomId,
+ serverNames = serverNames,
+ trigger = trigger
+ )
+ }
+ }
+
+ private fun CoroutineScope.knockRoom(knockAction: MutableState>) = launch {
knockAction.runUpdatingState {
knockRoom(roomId)
}
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 9146b13513..0f849aac24 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
@@ -31,6 +31,7 @@ import io.element.android.libraries.matrix.ui.model.InviteSender
data class JoinRoomState(
val contentState: ContentState,
val acceptDeclineInviteState: AcceptDeclineInviteState,
+ val joinAction: AsyncAction,
val knockAction: AsyncAction,
val applicationName: String,
val eventSink: (JoinRoomEvents) -> Unit
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 ee08ee954a..f897026600 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
@@ -125,11 +125,13 @@ fun aLoadedContentState(
fun aJoinRoomState(
contentState: ContentState = aLoadedContentState(),
acceptDeclineInviteState: AcceptDeclineInviteState = anAcceptDeclineInviteState(),
+ joinAction: AsyncAction = AsyncAction.Uninitialized,
knockAction: AsyncAction = AsyncAction.Uninitialized,
eventSink: (JoinRoomEvents) -> Unit = {}
) = JoinRoomState(
contentState = contentState,
acceptDeclineInviteState = acceptDeclineInviteState,
+ joinAction = joinAction,
knockAction = knockAction,
applicationName = "AppName",
eventSink = eventSink
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 49541938d2..435cd1bf8b 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
@@ -66,6 +66,7 @@ import io.element.android.libraries.ui.strings.CommonStrings
fun JoinRoomView(
state: JoinRoomState,
onBackPressed: () -> Unit,
+ onJoinSuccess: () -> Unit,
onKnockSuccess: () -> Unit,
modifier: Modifier = Modifier,
) {
@@ -108,7 +109,11 @@ fun JoinRoomView(
}
)
}
-
+ AsyncActionView(
+ async = state.joinAction,
+ onSuccess = { onJoinSuccess() },
+ onErrorDismiss = { state.eventSink(JoinRoomEvents.ClearError) },
+ )
AsyncActionView(
async = state.knockAction,
onSuccess = { onKnockSuccess() },
@@ -323,6 +328,7 @@ internal fun JoinRoomViewPreview(@PreviewParameter(JoinRoomStateProvider::class)
JoinRoomView(
state = state,
onBackPressed = { },
+ onJoinSuccess = { },
onKnockSuccess = { },
)
}
diff --git a/features/joinroom/impl/src/main/kotlin/io/element/android/features/joinroom/impl/di/JoinRoomModule.kt b/features/joinroom/impl/src/main/kotlin/io/element/android/features/joinroom/impl/di/JoinRoomModule.kt
index c288021cdf..d1154eedae 100644
--- a/features/joinroom/impl/src/main/kotlin/io/element/android/features/joinroom/impl/di/JoinRoomModule.kt
+++ b/features/joinroom/impl/src/main/kotlin/io/element/android/features/joinroom/impl/di/JoinRoomModule.kt
@@ -19,6 +19,7 @@ package io.element.android.features.joinroom.impl.di
import com.squareup.anvil.annotations.ContributesTo
import dagger.Module
import dagger.Provides
+import im.vector.app.features.analytics.plan.JoinedRoom
import io.element.android.features.invite.api.response.AcceptDeclineInviteState
import io.element.android.features.joinroom.impl.JoinRoomPresenter
import io.element.android.features.roomdirectory.api.RoomDescription
@@ -28,6 +29,7 @@ import io.element.android.libraries.di.SessionScope
import io.element.android.libraries.matrix.api.MatrixClient
import io.element.android.libraries.matrix.api.core.RoomId
import io.element.android.libraries.matrix.api.core.RoomIdOrAlias
+import io.element.android.libraries.matrix.api.room.join.JoinRoom
import java.util.Optional
@Module
@@ -36,6 +38,7 @@ object JoinRoomModule {
@Provides
fun providesJoinRoomPresenterFactory(
client: MatrixClient,
+ joinRoom: JoinRoom,
knockRoom: KnockRoom,
acceptDeclineInvitePresenter: Presenter,
buildMeta: BuildMeta,
@@ -45,12 +48,17 @@ object JoinRoomModule {
roomId: RoomId,
roomIdOrAlias: RoomIdOrAlias,
roomDescription: Optional,
+ serverNames: List,
+ trigger: JoinedRoom.Trigger,
): JoinRoomPresenter {
return JoinRoomPresenter(
roomId = roomId,
roomIdOrAlias = roomIdOrAlias,
roomDescription = roomDescription,
+ serverNames = serverNames,
+ trigger = trigger,
matrixClient = client,
+ joinRoom = joinRoom,
knockRoom = knockRoom,
acceptDeclineInvitePresenter = acceptDeclineInvitePresenter,
buildMeta = buildMeta,
diff --git a/features/joinroom/impl/src/main/res/values-it/translations.xml b/features/joinroom/impl/src/main/res/values-it/translations.xml
new file mode 100644
index 0000000000..55af91d9d7
--- /dev/null
+++ b/features/joinroom/impl/src/main/res/values-it/translations.xml
@@ -0,0 +1,11 @@
+
+
+ "Entra nella stanza"
+ "Bussa per partecipare"
+ "%1$s non supporta ancora gli spazi. Puoi accedere agli spazi sul web."
+ "Gli spazi non sono ancora supportati"
+ "Clicca sul pulsante qui sotto e un amministratore della stanza riceverà una notifica. Potrai partecipare alla conversazione una volta approvato."
+ "Per visualizzare la cronologia dei messaggi devi essere un membro di questa stanza."
+ "Vuoi entrare in questa stanza?"
+ "L\'anteprima non è disponibile"
+
diff --git a/features/joinroom/impl/src/main/res/values-pt/translations.xml b/features/joinroom/impl/src/main/res/values-pt/translations.xml
new file mode 100644
index 0000000000..4dc482327e
--- /dev/null
+++ b/features/joinroom/impl/src/main/res/values-pt/translations.xml
@@ -0,0 +1,11 @@
+
+
+ "Entrar na sala"
+ "Bater à porta"
+ "A %1$s ainda não funciona com espaços. Podes usá-los na aplicação web."
+ "Os espaços ainda não estão implementados"
+ "Carrega no botão abaixo para notificar um administrador da sala. Poderás entrar quando te aprovarem."
+ "Apenas os participantes podem ver o histórico de mensagens."
+ "Queres entrar nesta sala?"
+ "Pré-visualização indisponível"
+
diff --git a/features/joinroom/impl/src/main/res/values-ro/translations.xml b/features/joinroom/impl/src/main/res/values-ro/translations.xml
new file mode 100644
index 0000000000..a31d63053c
--- /dev/null
+++ b/features/joinroom/impl/src/main/res/values-ro/translations.xml
@@ -0,0 +1,11 @@
+
+
+ "Alăturați-vă camerei"
+ "Bateți pentru a vă alătura"
+ "%1$s nu suporta încă spații. Puteți accesa spațiile pe web."
+ "Spațiile nu sunt încă suportate"
+ "Faceți clic pe butonul de mai jos și un administrator de cameră va fi notificat. Veți putea să vă alăturați conversației odată aprobată."
+ "Trebuie să fiți membru al acestei camere pentru a vizualiza istoricul mesajelor."
+ "Doriți să vă alăturați acestei camere?"
+ "Previzualizare indisponibilă"
+
diff --git a/features/joinroom/impl/src/main/res/values-ru/translations.xml b/features/joinroom/impl/src/main/res/values-ru/translations.xml
index cec44b1c8c..c01bea738c 100644
--- a/features/joinroom/impl/src/main/res/values-ru/translations.xml
+++ b/features/joinroom/impl/src/main/res/values-ru/translations.xml
@@ -2,6 +2,8 @@
"Присоединиться к комнате"
"Постучите, чтобы присоединиться"
+ "%1$s еще не поддерживает пространства. Вы можете получить к ним доступ в веб-версии."
+ "Пространства пока не поддерживаются"
"Нажмите кнопку ниже и администратор комнаты получит уведомление. После одобрения вы сможете присоединиться к обсуждению."
"Вы должны быть участником этой комнаты, чтобы просмотреть историю сообщений."
"Хотите присоединиться к этой комнате?"
diff --git a/features/joinroom/impl/src/main/res/values-zh/translations.xml b/features/joinroom/impl/src/main/res/values-zh/translations.xml
new file mode 100644
index 0000000000..02a9f290b8
--- /dev/null
+++ b/features/joinroom/impl/src/main/res/values-zh/translations.xml
@@ -0,0 +1,11 @@
+
+
+ "加入聊天室"
+ "加入房间"
+ "%1$s 尚不支持空间。您可以通过 Web 端访问空间"
+ "空间尚不支持"
+ "点击下面的按钮,系统将通知房间管理员。获得批准后,您将能够加入对话。"
+ "只有聊天室成员才能查看消息历史记录。"
+ "想加入这个房间吗?"
+ "预览不可用"
+
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 3928ca31e8..2a054b820f 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
@@ -17,6 +17,7 @@
package io.element.android.features.joinroom.impl
import com.google.common.truth.Truth.assertThat
+import im.vector.app.features.analytics.plan.JoinedRoom
import io.element.android.features.invite.api.response.AcceptDeclineInviteEvents
import io.element.android.features.invite.api.response.AcceptDeclineInviteState
import io.element.android.features.invite.api.response.anAcceptDeclineInviteState
@@ -36,10 +37,12 @@ import io.element.android.libraries.matrix.api.room.preview.RoomPreview
import io.element.android.libraries.matrix.test.AN_EXCEPTION
import io.element.android.libraries.matrix.test.A_ROOM_ID
import io.element.android.libraries.matrix.test.A_ROOM_NAME
+import io.element.android.libraries.matrix.test.A_SERVER_LIST
import io.element.android.libraries.matrix.test.FakeMatrixClient
import io.element.android.libraries.matrix.test.core.aBuildMeta
import io.element.android.libraries.matrix.test.room.aRoomInfo
import io.element.android.libraries.matrix.test.room.aRoomMember
+import io.element.android.libraries.matrix.test.room.join.FakeJoinRoom
import io.element.android.libraries.matrix.ui.model.toInviteSender
import io.element.android.tests.testutils.WarmUpRule
import io.element.android.tests.testutils.lambda.assert
@@ -174,6 +177,59 @@ class JoinRoomPresenterTest {
}
}
+ @Test
+ fun `present - when room is joined with success, all the parameters are provided`() = runTest {
+ val aTrigger = JoinedRoom.Trigger.MobilePermalink
+ val joinRoomLambda = lambdaRecorder { _: RoomId, _: List, _: JoinedRoom.Trigger ->
+ Result.success(Unit)
+ }
+ val presenter = createJoinRoomPresenter(
+ trigger = aTrigger,
+ serverNames = A_SERVER_LIST,
+ joinRoomLambda = joinRoomLambda,
+ )
+ presenter.test {
+ skipItems(1)
+ awaitItem().also { state ->
+ state.eventSink(JoinRoomEvents.JoinRoom)
+ }
+ awaitItem().also { state ->
+ assertThat(state.joinAction).isEqualTo(AsyncAction.Loading)
+ }
+ awaitItem().also { state ->
+ assertThat(state.joinAction).isEqualTo(AsyncAction.Success(Unit))
+ }
+ joinRoomLambda.assertions()
+ .isCalledOnce()
+ .with(value(A_ROOM_ID), value(A_SERVER_LIST), value(aTrigger))
+ }
+ }
+
+ @Test
+ fun `present - when room is joined with error, it is possible to clear the error`() = runTest {
+ val presenter = createJoinRoomPresenter(
+ joinRoomLambda = { _, _, _ ->
+ Result.failure(AN_EXCEPTION)
+ },
+ )
+ presenter.test {
+ skipItems(1)
+ awaitItem().also { state ->
+ state.eventSink(JoinRoomEvents.JoinRoom)
+ }
+ awaitItem().also { state ->
+ assertThat(state.joinAction).isEqualTo(AsyncAction.Loading)
+ }
+ awaitItem().also { state ->
+ assertThat(state.joinAction).isEqualTo(AsyncAction.Failure(AN_EXCEPTION))
+ state.eventSink(JoinRoomEvents.ClearError)
+ }
+ awaitItem().also { state ->
+ assertThat(state.joinAction).isEqualTo(AsyncAction.Uninitialized)
+ }
+ }
+ }
+
@Test
fun `present - when room is left and public then join authorization is equal to canJoin`() = runTest {
val roomInfo = aRoomInfo(currentUserMembership = CurrentUserMembership.LEFT, isPublic = true)
@@ -310,7 +366,7 @@ class JoinRoomPresenterTest {
@Test
fun `present - when room is not known RoomPreview is loaded`() = runTest {
val client = FakeMatrixClient(
- getRoomPreviewResult = {
+ getRoomPreviewFromRoomIdResult = { _, _ ->
Result.success(
RoomPreview(
roomId = A_ROOM_ID,
@@ -355,7 +411,7 @@ class JoinRoomPresenterTest {
@Test
fun `present - when room is not known RoomPreview is loaded with error`() = runTest {
val client = FakeMatrixClient(
- getRoomPreviewResult = {
+ getRoomPreviewFromRoomIdResult = { _, _ ->
Result.failure(AN_EXCEPTION)
}
)
@@ -393,7 +449,7 @@ class JoinRoomPresenterTest {
@Test
fun `present - when room is not known RoomPreview is loaded with error 403`() = runTest {
val client = FakeMatrixClient(
- getRoomPreviewResult = {
+ getRoomPreviewFromRoomIdResult = { _, _ ->
Result.failure(Exception("403"))
}
)
@@ -415,7 +471,12 @@ 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: (RoomId, List, JoinedRoom.Trigger) -> Result = { _, _, _ ->
+ Result.success(Unit)
+ },
knockRoom: KnockRoom = FakeKnockRoom(),
buildMeta: BuildMeta = aBuildMeta(applicationName = "AppName"),
acceptDeclineInvitePresenter: Presenter = Presenter { anAcceptDeclineInviteState() }
@@ -424,7 +485,10 @@ class JoinRoomPresenterTest {
roomId = roomId,
roomIdOrAlias = roomId.toRoomIdOrAlias(),
roomDescription = roomDescription,
+ serverNames = serverNames,
+ trigger = trigger,
matrixClient = matrixClient,
+ joinRoom = FakeJoinRoom(joinRoomLambda),
knockRoom = knockRoom,
buildMeta = buildMeta,
acceptDeclineInvitePresenter = acceptDeclineInvitePresenter
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 b4bd788286..bf4449be41 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
@@ -91,6 +91,34 @@ class JoinRoomViewTest {
eventsRecorder.assertSingle(JoinRoomEvents.ClearError)
}
+ @Test
+ fun `clicking on closing Join error emits the expected Event`() {
+ val eventsRecorder = EventsRecorder()
+ rule.setJoinRoomView(
+ aJoinRoomState(
+ contentState = aLoadedContentState(joinAuthorisationStatus = JoinAuthorisationStatus.CanKnock),
+ joinAction = AsyncAction.Failure(Exception("Error")),
+ eventSink = eventsRecorder,
+ ),
+ )
+ rule.clickOn(CommonStrings.action_ok)
+ eventsRecorder.assertSingle(JoinRoomEvents.ClearError)
+ }
+
+ @Test
+ fun `when joining room is successful, the expected callback is invoked`() {
+ val eventsRecorder = EventsRecorder(expectEvents = false)
+ ensureCalledOnce {
+ rule.setJoinRoomView(
+ aJoinRoomState(
+ joinAction = AsyncAction.Success(Unit),
+ eventSink = eventsRecorder,
+ ),
+ onJoinSuccess = it
+ )
+ }
+ }
+
@Test
fun `clicking on Accept invitation IsInvited room emits the expected Event`() {
val eventsRecorder = EventsRecorder()
@@ -149,12 +177,14 @@ class JoinRoomViewTest {
private fun AndroidComposeTestRule.setJoinRoomView(
state: JoinRoomState,
onBackPressed: () -> Unit = EnsureNeverCalled(),
+ onJoinSuccess: () -> Unit = EnsureNeverCalled(),
onKnockSuccess: () -> Unit = EnsureNeverCalled(),
) {
setContent {
JoinRoomView(
state = state,
onBackPressed = onBackPressed,
+ onJoinSuccess = onJoinSuccess,
onKnockSuccess = onKnockSuccess,
)
}
diff --git a/features/leaveroom/api/src/main/res/values-es/translations.xml b/features/leaveroom/api/src/main/res/values-es/translations.xml
index b996ec51f2..25c753201c 100644
--- a/features/leaveroom/api/src/main/res/values-es/translations.xml
+++ b/features/leaveroom/api/src/main/res/values-es/translations.xml
@@ -1,5 +1,6 @@
+ "¿Estás seguro de que quieres salir de esta conversación? Esta conversación no es pública y no podrás volver a unirte sin una invitación."
"¿Estás seguro de que quieres salir de esta sala? Eres la única persona aquí. Si te vas, nadie podrá unirse en el futuro, ni siquiera tú."
"¿Estás seguro de que quieres abandonar esta sala? Esta sala no es pública y no podrás volver a entrar sin una invitación."
"¿Seguro que quieres salir de la habitación?"
diff --git a/features/leaveroom/api/src/main/res/values-ka/translations.xml b/features/leaveroom/api/src/main/res/values-ka/translations.xml
new file mode 100644
index 0000000000..bb2c4e6ed0
--- /dev/null
+++ b/features/leaveroom/api/src/main/res/values-ka/translations.xml
@@ -0,0 +1,6 @@
+
+
+ "დარწმუნებული ბრძანდებით, რომ ამ ოთახის დატოვება გსურთ? თქვენ აქ მარტო ხართ და ჩატის დატოვებისას აქ თქვენს ჩათვლით ვერავინ ვერ გაწევრიანდება."
+ "დარწმუნებული ბრძანდებით, რომ ამ ოთახის დატოვება გსურთ? ეს ოთახი არ არის საჯარო და მოწვევის გარეშე ვერ შეძლებთ ხელახლა გაწევრიანებას."
+ "დარწმუნებული ბრძანდებით, რომ ოთახის დატოვება გსურთ?"
+
diff --git a/features/leaveroom/api/src/main/res/values-pt/translations.xml b/features/leaveroom/api/src/main/res/values-pt/translations.xml
new file mode 100644
index 0000000000..7547378598
--- /dev/null
+++ b/features/leaveroom/api/src/main/res/values-pt/translations.xml
@@ -0,0 +1,7 @@
+
+
+ "Tens a certeza que queres sair desta conversa? Não é pública, logo não poderás voltar a participar sem um convite."
+ "Tens a certeza que queres sair desta sala? És o único participante. Se saíres, ninguém mais poderá entrar, incluindo tu."
+ "Tens a certeza que queres sair desta sala? Atenta que não é pública e portanto não poderás voltar a entrar sem um novo convite."
+ "Tens a certeza que queres sair da sala?"
+
diff --git a/features/leaveroom/api/src/main/res/values-zh/translations.xml b/features/leaveroom/api/src/main/res/values-zh/translations.xml
new file mode 100644
index 0000000000..634c1f045a
--- /dev/null
+++ b/features/leaveroom/api/src/main/res/values-zh/translations.xml
@@ -0,0 +1,7 @@
+
+
+ "您确定要离开此对话吗?此对话不公开,未经邀请您将无法重新加入。"
+ "你确定要离开这个房间吗?这里只有你一个人,如果你走了,包括你在内的所有人都无法进入此房间。"
+ "你确定要离开这个房间吗?这个房间不是公开的,如果没有邀请,你将无法重新加入。"
+ "你确定要离开房间吗?"
+
diff --git a/features/lockscreen/api/src/main/kotlin/io/element/android/features/lockscreen/api/LockScreenEntryPoint.kt b/features/lockscreen/api/src/main/kotlin/io/element/android/features/lockscreen/api/LockScreenEntryPoint.kt
index 6a2fb0c72d..f31fc5af4a 100644
--- a/features/lockscreen/api/src/main/kotlin/io/element/android/features/lockscreen/api/LockScreenEntryPoint.kt
+++ b/features/lockscreen/api/src/main/kotlin/io/element/android/features/lockscreen/api/LockScreenEntryPoint.kt
@@ -16,17 +16,19 @@
package io.element.android.features.lockscreen.api
+import android.content.Context
+import android.content.Intent
import com.bumble.appyx.core.modality.BuildContext
import com.bumble.appyx.core.node.Node
import com.bumble.appyx.core.plugin.Plugin
import io.element.android.libraries.architecture.FeatureEntryPoint
interface LockScreenEntryPoint : FeatureEntryPoint {
- fun nodeBuilder(parentNode: Node, buildContext: BuildContext): NodeBuilder
+ fun nodeBuilder(parentNode: Node, buildContext: BuildContext, navTarget: Target): NodeBuilder
+ fun pinUnlockIntent(context: Context): Intent
interface NodeBuilder {
fun callback(callback: Callback): NodeBuilder
- fun target(target: Target): NodeBuilder
fun build(): Node
}
@@ -37,6 +39,5 @@ interface LockScreenEntryPoint : FeatureEntryPoint {
enum class Target {
Settings,
Setup,
- Unlock
}
}
diff --git a/features/lockscreen/impl/src/main/AndroidManifest.xml b/features/lockscreen/impl/src/main/AndroidManifest.xml
new file mode 100644
index 0000000000..083647d1c2
--- /dev/null
+++ b/features/lockscreen/impl/src/main/AndroidManifest.xml
@@ -0,0 +1,25 @@
+
+
+
+
+
+
+
+
+
diff --git a/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/DefaultLockScreenEntryPoint.kt b/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/DefaultLockScreenEntryPoint.kt
index 5065cdc7f2..a6889a96e7 100644
--- a/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/DefaultLockScreenEntryPoint.kt
+++ b/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/DefaultLockScreenEntryPoint.kt
@@ -16,18 +16,20 @@
package io.element.android.features.lockscreen.impl
+import android.content.Context
+import android.content.Intent
import com.bumble.appyx.core.modality.BuildContext
import com.bumble.appyx.core.node.Node
import com.squareup.anvil.annotations.ContributesBinding
import io.element.android.features.lockscreen.api.LockScreenEntryPoint
+import io.element.android.features.lockscreen.impl.unlock.activity.PinUnlockActivity
import io.element.android.libraries.architecture.createNode
import io.element.android.libraries.di.AppScope
import javax.inject.Inject
@ContributesBinding(AppScope::class)
class DefaultLockScreenEntryPoint @Inject constructor() : LockScreenEntryPoint {
- override fun nodeBuilder(parentNode: Node, buildContext: BuildContext): LockScreenEntryPoint.NodeBuilder {
- var innerTarget: LockScreenEntryPoint.Target = LockScreenEntryPoint.Target.Unlock
+ override fun nodeBuilder(parentNode: Node, buildContext: BuildContext, navTarget: LockScreenEntryPoint.Target): LockScreenEntryPoint.NodeBuilder {
val callbacks = mutableListOf()
return object : LockScreenEntryPoint.NodeBuilder {
@@ -36,15 +38,9 @@ class DefaultLockScreenEntryPoint @Inject constructor() : LockScreenEntryPoint {
return this
}
- override fun target(target: LockScreenEntryPoint.Target): LockScreenEntryPoint.NodeBuilder {
- innerTarget = target
- return this
- }
-
override fun build(): Node {
val inputs = LockScreenFlowNode.Inputs(
- when (innerTarget) {
- LockScreenEntryPoint.Target.Unlock -> LockScreenFlowNode.NavTarget.Unlock
+ when (navTarget) {
LockScreenEntryPoint.Target.Setup -> LockScreenFlowNode.NavTarget.Setup
LockScreenEntryPoint.Target.Settings -> LockScreenFlowNode.NavTarget.Settings
}
@@ -54,4 +50,8 @@ class DefaultLockScreenEntryPoint @Inject constructor() : LockScreenEntryPoint {
}
}
}
+
+ override fun pinUnlockIntent(context: Context): Intent {
+ return PinUnlockActivity.newIntent(context)
+ }
}
diff --git a/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/LockScreenFlowNode.kt b/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/LockScreenFlowNode.kt
index 8dd75fc65d..fcbb0336a4 100644
--- a/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/LockScreenFlowNode.kt
+++ b/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/LockScreenFlowNode.kt
@@ -30,7 +30,6 @@ import io.element.android.anvilannotations.ContributesNode
import io.element.android.features.lockscreen.api.LockScreenEntryPoint
import io.element.android.features.lockscreen.impl.settings.LockScreenSettingsFlowNode
import io.element.android.features.lockscreen.impl.setup.LockScreenSetupFlowNode
-import io.element.android.features.lockscreen.impl.unlock.PinUnlockNode
import io.element.android.libraries.architecture.BackstackView
import io.element.android.libraries.architecture.BaseFlowNode
import io.element.android.libraries.architecture.NodeInputs
@@ -44,20 +43,17 @@ class LockScreenFlowNode @AssistedInject constructor(
@Assisted plugins: List,
) : BaseFlowNode(
backstack = BackStack(
- initialElement = plugins.filterIsInstance(Inputs::class.java).first().initialNavTarget,
+ initialElement = plugins.filterIsInstance().first().initialNavTarget,
savedStateMap = buildContext.savedStateMap,
),
buildContext = buildContext,
plugins = plugins,
) {
data class Inputs(
- val initialNavTarget: NavTarget = NavTarget.Unlock,
+ val initialNavTarget: NavTarget,
) : NodeInputs
sealed interface NavTarget : Parcelable {
- @Parcelize
- data object Unlock : NavTarget
-
@Parcelize
data object Setup : NavTarget
@@ -75,10 +71,6 @@ class LockScreenFlowNode @AssistedInject constructor(
override fun resolve(navTarget: NavTarget, buildContext: BuildContext): Node {
return when (navTarget) {
- NavTarget.Unlock -> {
- val inputs = PinUnlockNode.Inputs(isInAppUnlock = false)
- createNode(buildContext, plugins = listOf(inputs))
- }
NavTarget.Setup -> {
val callback = OnSetupDoneCallback(plugins())
createNode(buildContext, plugins = listOf(callback))
diff --git a/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/settings/LockScreenSettingsFlowNode.kt b/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/settings/LockScreenSettingsFlowNode.kt
index 0890f38d1e..13fe1e62aa 100644
--- a/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/settings/LockScreenSettingsFlowNode.kt
+++ b/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/settings/LockScreenSettingsFlowNode.kt
@@ -103,13 +103,12 @@ class LockScreenSettingsFlowNode @AssistedInject constructor(
override fun resolve(navTarget: NavTarget, buildContext: BuildContext): Node {
return when (navTarget) {
NavTarget.Unlock -> {
- val inputs = PinUnlockNode.Inputs(isInAppUnlock = true)
val callback = object : PinUnlockNode.Callback {
override fun onUnlock() {
backstack.newRoot(NavTarget.Settings)
}
}
- createNode(buildContext, plugins = listOf(inputs, callback))
+ createNode(buildContext, plugins = listOf(callback))
}
NavTarget.SetupPin -> {
createNode(buildContext)
diff --git a/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/unlock/PinUnlockNode.kt b/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/unlock/PinUnlockNode.kt
index da6853a39c..f357869375 100644
--- a/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/unlock/PinUnlockNode.kt
+++ b/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/unlock/PinUnlockNode.kt
@@ -26,8 +26,6 @@ import com.bumble.appyx.core.plugin.plugins
import dagger.assisted.Assisted
import dagger.assisted.AssistedInject
import io.element.android.anvilannotations.ContributesNode
-import io.element.android.libraries.architecture.NodeInputs
-import io.element.android.libraries.architecture.inputs
import io.element.android.libraries.di.SessionScope
@ContributesNode(SessionScope::class)
@@ -40,12 +38,6 @@ class PinUnlockNode @AssistedInject constructor(
fun onUnlock()
}
- data class Inputs(
- val isInAppUnlock: Boolean
- ) : NodeInputs
-
- private val inputs: Inputs = inputs()
-
private fun onUnlock() {
plugins().forEach {
it.onUnlock()
@@ -62,7 +54,9 @@ class PinUnlockNode @AssistedInject constructor(
}
PinUnlockView(
state = state,
- isInAppUnlock = inputs.isInAppUnlock,
+ // UnlockNode is only used for in-app unlock, so we can safely set isInAppUnlock to true.
+ // It's set to false in PinUnlockActivity.
+ isInAppUnlock = true,
modifier = modifier
)
}
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 aebf95aa37..db56b8c17b 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
@@ -29,11 +29,11 @@ import io.element.android.features.lockscreen.impl.biometric.BiometricUnlockMana
import io.element.android.features.lockscreen.impl.pin.PinCodeManager
import io.element.android.features.lockscreen.impl.pin.model.PinEntry
import io.element.android.features.lockscreen.impl.unlock.keypad.PinKeypadModel
+import io.element.android.features.lockscreen.impl.unlock.signout.SignOut
import io.element.android.libraries.architecture.AsyncData
import io.element.android.libraries.architecture.Presenter
import io.element.android.libraries.architecture.runCatchingUpdatingState
import io.element.android.libraries.core.bool.orFalse
-import io.element.android.libraries.matrix.api.MatrixClient
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.launch
import javax.inject.Inject
@@ -41,7 +41,7 @@ import javax.inject.Inject
class PinUnlockPresenter @Inject constructor(
private val pinCodeManager: PinCodeManager,
private val biometricUnlockManager: BiometricUnlockManager,
- private val matrixClient: MatrixClient,
+ private val signOut: SignOut,
private val coroutineScope: CoroutineScope,
private val pinUnlockHelper: PinUnlockHelper,
) : Presenter {
@@ -179,7 +179,7 @@ class PinUnlockPresenter @Inject constructor(
private fun CoroutineScope.signOut(signOutAction: MutableState>) = launch {
suspend {
- matrixClient.logout(ignoreSdkError = true)
+ signOut()
}.runCatchingUpdatingState(signOutAction)
}
}
diff --git a/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/unlock/activity/PinUnlockActivity.kt b/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/unlock/activity/PinUnlockActivity.kt
new file mode 100644
index 0000000000..9c228b0736
--- /dev/null
+++ b/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/unlock/activity/PinUnlockActivity.kt
@@ -0,0 +1,71 @@
+/*
+ * Copyright (c) 2024 New Vector Ltd
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package io.element.android.features.lockscreen.impl.unlock.activity
+
+import android.content.Context
+import android.content.Intent
+import android.os.Bundle
+import androidx.activity.OnBackPressedCallback
+import androidx.activity.compose.setContent
+import androidx.activity.enableEdgeToEdge
+import androidx.appcompat.app.AppCompatActivity
+import androidx.lifecycle.lifecycleScope
+import io.element.android.compound.theme.ElementTheme
+import io.element.android.features.lockscreen.api.LockScreenLockState
+import io.element.android.features.lockscreen.api.LockScreenService
+import io.element.android.features.lockscreen.impl.unlock.PinUnlockPresenter
+import io.element.android.features.lockscreen.impl.unlock.PinUnlockView
+import io.element.android.features.lockscreen.impl.unlock.di.PinUnlockBindings
+import io.element.android.libraries.architecture.bindings
+import kotlinx.coroutines.launch
+import javax.inject.Inject
+
+class PinUnlockActivity : AppCompatActivity() {
+ internal companion object {
+ fun newIntent(context: Context): Intent {
+ return Intent(context, PinUnlockActivity::class.java)
+ }
+ }
+
+ @Inject lateinit var presenter: PinUnlockPresenter
+ @Inject lateinit var lockScreenService: LockScreenService
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ enableEdgeToEdge()
+ super.onCreate(savedInstanceState)
+ bindings().inject(this)
+ setContent {
+ ElementTheme {
+ val state = presenter.present()
+ PinUnlockView(state = state, isInAppUnlock = false)
+ }
+ }
+ lifecycleScope.launch {
+ lockScreenService.lockState.collect { state ->
+ if (state == LockScreenLockState.Unlocked) {
+ finish()
+ }
+ }
+ }
+ val onBackPressedCallback = object : OnBackPressedCallback(true) {
+ override fun handleOnBackPressed() {
+ moveTaskToBack(true)
+ }
+ }
+ onBackPressedDispatcher.addCallback(this, onBackPressedCallback)
+ }
+}
diff --git a/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/unlock/di/PinUnlockBindings.kt b/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/unlock/di/PinUnlockBindings.kt
new file mode 100644
index 0000000000..ddd62d2fb6
--- /dev/null
+++ b/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/unlock/di/PinUnlockBindings.kt
@@ -0,0 +1,26 @@
+/*
+ * Copyright (c) 2024 New Vector Ltd
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package io.element.android.features.lockscreen.impl.unlock.di
+
+import com.squareup.anvil.annotations.ContributesTo
+import io.element.android.features.lockscreen.impl.unlock.activity.PinUnlockActivity
+import io.element.android.libraries.di.AppScope
+
+@ContributesTo(AppScope::class)
+interface PinUnlockBindings {
+ fun inject(activity: PinUnlockActivity)
+}
diff --git a/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/unlock/signout/DefaultSignOut.kt b/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/unlock/signout/DefaultSignOut.kt
new file mode 100644
index 0000000000..2c541911e6
--- /dev/null
+++ b/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/unlock/signout/DefaultSignOut.kt
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2024 New Vector Ltd
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package io.element.android.features.lockscreen.impl.unlock.signout
+
+import com.squareup.anvil.annotations.ContributesBinding
+import io.element.android.libraries.di.AppScope
+import io.element.android.libraries.matrix.api.MatrixClientProvider
+import io.element.android.libraries.matrix.api.auth.MatrixAuthenticationService
+import javax.inject.Inject
+
+@ContributesBinding(AppScope::class)
+class DefaultSignOut @Inject constructor(
+ private val authenticationService: MatrixAuthenticationService,
+ private val matrixClientProvider: MatrixClientProvider,
+) : SignOut {
+ override suspend fun invoke(): String? {
+ val currentSession = authenticationService.getLatestSessionId()
+ return if (currentSession != null) {
+ matrixClientProvider.getOrRestore(currentSession)
+ .getOrThrow()
+ .logout(ignoreSdkError = true)
+ } else {
+ error("No session to sign out")
+ }
+ }
+}
diff --git a/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/unlock/signout/SignOut.kt b/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/unlock/signout/SignOut.kt
new file mode 100644
index 0000000000..f4c91aece6
--- /dev/null
+++ b/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/unlock/signout/SignOut.kt
@@ -0,0 +1,21 @@
+/*
+ * Copyright (c) 2024 New Vector Ltd
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package io.element.android.features.lockscreen.impl.unlock.signout
+
+interface SignOut {
+ suspend operator fun invoke(): String?
+}
diff --git a/features/lockscreen/impl/src/main/res/values-fr/translations.xml b/features/lockscreen/impl/src/main/res/values-fr/translations.xml
index 94e65cc6f0..e086a88e61 100644
--- a/features/lockscreen/impl/src/main/res/values-fr/translations.xml
+++ b/features/lockscreen/impl/src/main/res/values-fr/translations.xml
@@ -1,6 +1,6 @@
- "authentification biométrique"
+ "l’authentification biométrique"
"déverrouillage biométrique"
"Déverrouiller avec la biométrie"
"Code PIN oublié?"
diff --git a/features/lockscreen/impl/src/main/res/values-ka/translations.xml b/features/lockscreen/impl/src/main/res/values-ka/translations.xml
new file mode 100644
index 0000000000..26fd97b671
--- /dev/null
+++ b/features/lockscreen/impl/src/main/res/values-ka/translations.xml
@@ -0,0 +1,21 @@
+
+
+ "დაგავიწყდათ PIN?"
+ "PIN კოდის შეცვლა"
+ "ბიომეტრიული განბლოკვის დაშვება"
+ "პინ კოდის წაშლა"
+ "დარწმუნებული ხართ, რომ გსურთ PIN-ის წაშლა?"
+ "გსურთ PIN-ის წაშლა?"
+ "დაადასტურეთ PIN"
+ "გასაგრძელებლად საჭიროა ხელახლა შესვლა და ახალი PIN-ის შექმნა"
+ "თქვენ ახლა გადიხართ…"
+
+ - "თქვენ გაქვთ %1$d მცდელობა განსაბლოკად"
+ - "თქვენ გაქვთ %1$d მცდელობა განსაბლოკად"
+
+
+ - "არასწორი PIN. თქვენ %1$d შანსი დაგრჩათ"
+ - "არასწორი PIN. თქვენ %1$d შანსი დაგრჩათ"
+
+ "გასვლა…"
+
diff --git a/features/lockscreen/impl/src/main/res/values-pt/translations.xml b/features/lockscreen/impl/src/main/res/values-pt/translations.xml
new file mode 100644
index 0000000000..ab87d61955
--- /dev/null
+++ b/features/lockscreen/impl/src/main/res/values-pt/translations.xml
@@ -0,0 +1,37 @@
+
+
+ "autenticação biométrica"
+ "desbloqueio biométrico"
+ "Desbloquear com biometria"
+ "Esqueceste-te do PIN?"
+ "Altera o código PIN"
+ "Permitir o desbloqueio biométrico"
+ "Remover PIN"
+ "Tens a certeza que queres remover o PIN?"
+ "Remover o PIN?"
+ "Permitir %1$s"
+ "Prefiro usar o PIN"
+ "Poupa tempo e utiliza %1$s para desbloquear a aplicação"
+ "Escolher PIN"
+ "Confirmar PIN"
+ "Não podes escolher este código PIN por razões de segurança"
+ "Escolhe um PIN diferente"
+ "Bloqueia a %1$s para dar mais segurança às tuas conversas.
+
+Escolhe algo memorável. Se te esqueceres deste PIN, a tua sessão será terminada."
+ "Insere o mesmo PIN duas vezes"
+ "Os PINs não coincidem"
+ "Terás de voltar a iniciar sessão e criar um novo PIN para continuar"
+ "Estás a terminar a sessão"
+
+ - "Tens %1$d tentativa de desbloqueio"
+ - "Tens %1$d tentativas de desbloqueio"
+
+
+ - "PIN incorreto. Tens mais %1$d tentativa"
+ - "PIN incorreto. Tens mais %1$d tentativas"
+
+ "Utilizar biometria"
+ "Utilizar PIN"
+ "A terminar sessão…"
+
diff --git a/features/lockscreen/impl/src/main/res/values-zh/translations.xml b/features/lockscreen/impl/src/main/res/values-zh/translations.xml
new file mode 100644
index 0000000000..9d19208c6a
--- /dev/null
+++ b/features/lockscreen/impl/src/main/res/values-zh/translations.xml
@@ -0,0 +1,35 @@
+
+
+ "生物识别认证"
+ "生物识别解锁"
+ "使用生物识别解锁"
+ "忘记 PIN 码?"
+ "更改 PIN 码"
+ "允许生物识别解锁"
+ "移除 PIN 码"
+ "您确定要删除 PIN 码吗?"
+ "移除 PIN 码?"
+ "允许 %1$s"
+ "我宁愿使用 PIN 码"
+ "节省时间,用 %1$s 来解锁应用程序"
+ "选择 PIN 码"
+ "确认 PIN 码"
+ "出于安全原因,您不能选择这个 PIN 码"
+ "选择不同的 PIN 码"
+ "锁定 %1$s 以为聊天增加安全性。
+
+选择好记的 PIN 码。如果忘掉了这个 PIN 码,就不得不登出应用。"
+ "请输入两次相同的 PIN 码"
+ "PIN 码不匹配"
+ "您需要重新登录并创建新的 PIN 才能继续"
+ "您正在登出"
+
+ - "还剩 %1$d 次解锁机会"
+
+
+ - "PIN 码错误。还剩 %1$d 次机会"
+
+ "使用生物识别"
+ "使用 PIN 码"
+ "正在登出…"
+
diff --git a/features/lockscreen/impl/src/test/kotlin/io/element/android/features/lockscreen/impl/unlock/DefaultSignOutTest.kt b/features/lockscreen/impl/src/test/kotlin/io/element/android/features/lockscreen/impl/unlock/DefaultSignOutTest.kt
new file mode 100644
index 0000000000..6870a336d3
--- /dev/null
+++ b/features/lockscreen/impl/src/test/kotlin/io/element/android/features/lockscreen/impl/unlock/DefaultSignOutTest.kt
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 2024 New Vector Ltd
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package io.element.android.features.lockscreen.impl.unlock
+
+import com.google.common.truth.Truth.assertThat
+import io.element.android.features.lockscreen.impl.unlock.signout.DefaultSignOut
+import io.element.android.libraries.matrix.test.FakeMatrixClient
+import io.element.android.libraries.matrix.test.FakeMatrixClientProvider
+import io.element.android.libraries.matrix.test.auth.FakeAuthenticationService
+import io.element.android.tests.testutils.lambda.assert
+import io.element.android.tests.testutils.lambda.lambdaRecorder
+import kotlinx.coroutines.test.runTest
+import org.junit.Test
+
+class DefaultSignOutTest {
+ private val matrixClient = FakeMatrixClient()
+ private val authenticationService = FakeAuthenticationService()
+ private val matrixClientProvider = FakeMatrixClientProvider(getClient = { Result.success(matrixClient) })
+ private val sut = DefaultSignOut(authenticationService, matrixClientProvider)
+
+ @Test
+ fun `when no active session then it throws`() = runTest {
+ authenticationService.getLatestSessionIdLambda = { null }
+ val result = runCatching { sut.invoke() }
+ assertThat(result.isFailure).isTrue()
+ }
+
+ @Test
+ fun `with one active session and successful logout on client`() = runTest {
+ val logoutLambda = lambdaRecorder { _: Boolean -> null }
+ authenticationService.getLatestSessionIdLambda = { matrixClient.sessionId }
+ matrixClient.logoutLambda = logoutLambda
+ val result = runCatching { sut.invoke() }
+ assertThat(result.isSuccess).isTrue()
+ assert(logoutLambda).isCalledOnce()
+ }
+
+ @Test
+ fun `with one active session and and failed logout on client`() = runTest {
+ val logoutLambda = lambdaRecorder { _: Boolean -> error("Failed to logout") }
+ authenticationService.getLatestSessionIdLambda = { matrixClient.sessionId }
+ matrixClient.logoutLambda = logoutLambda
+ val result = runCatching { sut.invoke() }
+ assertThat(result.isFailure).isTrue()
+ assert(logoutLambda).isCalledOnce()
+ }
+}
diff --git a/features/lockscreen/impl/src/test/kotlin/io/element/android/features/lockscreen/impl/unlock/FakeSignOut.kt b/features/lockscreen/impl/src/test/kotlin/io/element/android/features/lockscreen/impl/unlock/FakeSignOut.kt
new file mode 100644
index 0000000000..883a5bf97b
--- /dev/null
+++ b/features/lockscreen/impl/src/test/kotlin/io/element/android/features/lockscreen/impl/unlock/FakeSignOut.kt
@@ -0,0 +1,28 @@
+/*
+ * Copyright (c) 2024 New Vector Ltd
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package io.element.android.features.lockscreen.impl.unlock
+
+import io.element.android.features.lockscreen.impl.unlock.signout.SignOut
+import io.element.android.tests.testutils.simulateLongTask
+
+class FakeSignOut(
+ var lambda: () -> String? = { null }
+) : SignOut {
+ override suspend fun invoke(): String? = simulateLongTask {
+ lambda()
+ }
+}
diff --git a/features/lockscreen/impl/src/test/kotlin/io/element/android/features/lockscreen/impl/unlock/PinUnlockPresenterTest.kt b/features/lockscreen/impl/src/test/kotlin/io/element/android/features/lockscreen/impl/unlock/PinUnlockPresenterTest.kt
index 6827055b2c..89d0e92ee2 100644
--- a/features/lockscreen/impl/src/test/kotlin/io/element/android/features/lockscreen/impl/unlock/PinUnlockPresenterTest.kt
+++ b/features/lockscreen/impl/src/test/kotlin/io/element/android/features/lockscreen/impl/unlock/PinUnlockPresenterTest.kt
@@ -28,8 +28,10 @@ import io.element.android.features.lockscreen.impl.pin.PinCodeManager
import io.element.android.features.lockscreen.impl.pin.model.PinEntry
import io.element.android.features.lockscreen.impl.pin.model.assertText
import io.element.android.features.lockscreen.impl.unlock.keypad.PinKeypadModel
+import io.element.android.features.lockscreen.impl.unlock.signout.SignOut
import io.element.android.libraries.architecture.AsyncData
-import io.element.android.libraries.matrix.test.FakeMatrixClient
+import io.element.android.tests.testutils.lambda.assert
+import io.element.android.tests.testutils.lambda.lambdaRecorder
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.test.runTest
import org.junit.Test
@@ -104,7 +106,9 @@ class PinUnlockPresenterTest {
@Test
fun `present - forgot pin flow`() = runTest {
- val presenter = createPinUnlockPresenter(this)
+ val signOutLambda = lambdaRecorder { null }
+ val signOut = FakeSignOut(signOutLambda)
+ val presenter = createPinUnlockPresenter(this, signOut = signOut)
moleculeFlow(RecompositionMode.Immediate) {
presenter.present()
}.test {
@@ -131,6 +135,7 @@ class PinUnlockPresenterTest {
awaitItem().also { state ->
assertThat(state.signOutAction).isInstanceOf(AsyncData.Success::class.java)
}
+ assert(signOutLambda).isCalledOnce().withNoParameter()
}
}
@@ -142,6 +147,7 @@ class PinUnlockPresenterTest {
scope: CoroutineScope,
biometricUnlockManager: BiometricUnlockManager = FakeBiometricUnlockManager(),
callback: PinCodeManager.Callback = DefaultPinCodeManagerCallback(),
+ signOut: SignOut = FakeSignOut(),
): PinUnlockPresenter {
val pinCodeManager = aPinCodeManager().apply {
addCallback(callback)
@@ -150,7 +156,7 @@ class PinUnlockPresenterTest {
return PinUnlockPresenter(
pinCodeManager = pinCodeManager,
biometricUnlockManager = biometricUnlockManager,
- matrixClient = FakeMatrixClient(),
+ signOut = signOut,
coroutineScope = scope,
pinUnlockHelper = PinUnlockHelper(biometricUnlockManager, pinCodeManager),
)
diff --git a/features/login/impl/src/main/res/values-es/translations.xml b/features/login/impl/src/main/res/values-es/translations.xml
index 28e003edc6..31df1a3d04 100644
--- a/features/login/impl/src/main/res/values-es/translations.xml
+++ b/features/login/impl/src/main/res/values-es/translations.xml
@@ -14,6 +14,8 @@
"Usa un proveedor de cuenta diferente, como tu propio servidor privado o una cuenta de trabajo."
"Cambiar el proveedor de la cuenta"
"No hemos podido acceder a este servidor. Comprueba que has introducido correctamente la dirección del servidor. Si la dirección es correcta, ponte en contacto con el administrador del servidor para obtener más ayuda."
+ "Sliding sync no está disponible debido a un problema en el archivo well-known:
+%1$s"
"Este servidor no soporta sliding sync."
"Dirección del homeserver"
"Solo puedes conectarte a un servidor que soporte sliding sync. El administrador de tu servidor tendrá que configurarlo. %1$s"
@@ -22,6 +24,7 @@
"Esta cuenta ha sido desactivada."
"Usuario y/o contraseña incorrectos"
"Este no es un id de usuario válido. Formato esperado: \'@user:homeserver.org\'"
+ "Este servidor está configurado para utilizar tokens de actualización. Estos no son compatibles cuando se utiliza el inicio de sesión basado en contraseña."
"El servidor seleccionado no admite contraseñas ni inicio de sesión OIDC. Póngase en contacto con su administrador o elija otro homeserver."
"Introduce tus datos"
"Matrix es una red abierta para una comunicación segura y descentralizada."
diff --git a/features/login/impl/src/main/res/values-ka/translations.xml b/features/login/impl/src/main/res/values-ka/translations.xml
new file mode 100644
index 0000000000..2187fc9e95
--- /dev/null
+++ b/features/login/impl/src/main/res/values-ka/translations.xml
@@ -0,0 +1,42 @@
+
+
+ "ანგარიშის მიმწოდებლის შეცვლა"
+ "სახლის სერვერის მისამართი"
+ "შეიყვანეთ საძიებო სიტყვა ან დომენის მისამართი."
+ "მოძებნეთ კომპანია, საზოგადოება ან კერძო სერვერი."
+ "ანგარიშის მომწოდებლის მოძებნა"
+ "აქ იქნება თქვენი საუბრები - ისევე, როგორც თქვენ ელ. ფოსტაში ინახება თქვენი ელ.წერილები."
+ "თქვენ აპირებთ შესვლას %s-ში"
+ "აქ იქნება თქვენი საუბრები - ისევე, როგორც თქვენ ელ. ფოსტაში ინახება თქვენი ელ.წერილები."
+ "თქვენ აპირებთ ანგარიშის შექმნას %s-ში"
+ "Matrix.org არის დიდი, უფასო სერვერი საჯარო Matrix ქსელში უსაფრთხო, დეცენტრალიზებული კომუნიკაციისთვის, რომელსაც მართავს Matrix.org ფონდი."
+ "სხვა"
+ "გამოიყენეთ სხვა ანგარიშის პროვაიდერი, როგორიცაა თქვენი პირადი სერვერი ან სამუშაო ანგარიში."
+ "შეცვალეთ ანგარიშის მომწოდებელი"
+ "ჩვენ ვერ მივაღწიეთ ამ სახლის სერვერს. გთხოვთ, შეამოწმოთ, რომ სწორად შეიყვანეთ სახლის სერვერის URL. თუ URL სწორია, დაუკავშირდით თქვენი სახლის სერვერის ადმინისტრატორს დამატებითი დახმარებისთვის."
+ "ამჟამად ეს სერვერი მხარს არ უჭერს \"sliding sync\"-ს."
+ "სახლის სერვერის URL"
+ "თქვენ შეგიძლიათ დაუკავშირდეთ მხოლოდ იმ სერვერს, რომელიც მხარს უჭერს \"sliding sync\"-ს. თქვენი სახლის სერვერის ადმინისტრატორს დასჭირდება მისი კონფიგურაცია.%1$s"
+ "რა არის თქვენი სერვერის მისამართი?"
+ "აირჩიეთ თქვენი სერვერი"
+ "ეს ანგარიში დეაქტივირებულია."
+ "არასწორი მომხმარებლის სახელი და/ან პაროლი"
+ "მოცემული მომხმარებლის იდენტიფიკატორი არასწორია. დასაშვები ფორმატი: ‘@user:homeserver.org’"
+ "მოცემული სახლის სერვერი მხარს არ უჭერს პაროლით ან OIDC-ით შესვლას. გთხოვთ, დაუკავშირდეთ თქვენს ადმინისტრატორს ან აარჩიეთ სხვა სახლის სერვერი."
+ "შეიყვანეთ თქვენი დეტალები"
+ "Matrix არის ღია ქსელი უსაფრთხო, დეცენტრალიზებული კომუნიკაციისთვის."
+ "კეთილი იყოს თქვენი მობრძანება!"
+ "შესვლა %1$s-ში"
+ "შეცვალეთ ანგარიშის მომწოდებელი"
+ "კერძო სერვერი Element-ის თანამშრომლებისთვის."
+ "Matrix არის ღია ქსელი უსაფრთხო, დეცენტრალიზებული კომუნიკაციისთვის."
+ "აქ იქნება თქვენი საუბრები - ისევე, როგორც თქვენ ელ. ფოსტაში ინახება თქვენი ელ.წერილები."
+ "თქვენ აპირებთ შესვლას %1$s-ში"
+ "თქვენ აპირებთ ანგარიშის შექმნას %1$s-ში"
+ "ახლა დიდი მოთხოვნაა %1$s-ზე %2$s-ში. დაბრუნდით რამდენიმე დღეში და სცადეთ ერთხელაც.
+
+მადლობა მოთმენისათვის!"
+ "კეთილი იყოს თქვენი მობრძანება %1$s-ში!"
+ "თითქმის მზადაა."
+ "თქვენ შეხვედით."
+
diff --git a/features/login/impl/src/main/res/values-pt/translations.xml b/features/login/impl/src/main/res/values-pt/translations.xml
new file mode 100644
index 0000000000..09e8b8ba01
--- /dev/null
+++ b/features/login/impl/src/main/res/values-pt/translations.xml
@@ -0,0 +1,45 @@
+
+
+ "Alterar operador de conta"
+ "Endereço do servidor"
+ "Insira um termo para pesquisa ou um endereço."
+ "Pesquisar por uma empresa, comunidade ou servidor privado."
+ "Encontrar um operador de conta"
+ "É aqui que as tuas conversas vão ficar — tal como num serviço de e-mail."
+ "Irás iniciar sessão em %s"
+ "É aqui que as tuas conversas vão ficar — tal como num serviço de e-mail."
+ "Irás criar uma conta em %s"
+ "O Matrix.org é um servidor grande e gratuito na rede pública Matrix para comunicação segura e descentralizada, gerido pela Fundação Matrix.org."
+ "Outro"
+ "Utiliza um operador de conta diferente, como o teu próprio servidor privado ou uma conta de trabalho."
+ "Alterar operador de conta"
+ "Não foi possível comunicar com este servidor. Por favor, verifica se introduziste o seu URL corretamente. Se sim, contacta o administrador para obteres mais ajuda."
+ "A sincronização deslizante (sliding sync) não está disponível devido a um problema no ficheiro \"well-known\":
+%1$s"
+ "Este servidor não suporta sincronização deslizante (sliding sync)."
+ "URL do servidor"
+ "Só te podes ligar a um servidor existente que suporte a sincronização deslizante (sliding sync). O administrador do teu servidor terá de a configurar. %1$s"
+ "Qual é o endereço do teu servidor?"
+ "Seleciona o teu servidor"
+ "Esta conta foi desativada."
+ "Nome de utilizador ou senha incorretos"
+ "Identificador de utilizador inválido. Formato esperado: ‘@utilizador:servidor.org’"
+ "Este servidor está configurado para utilizar \"tokens\" de atualização. Estes não são suportados quando utilizas o início de sessão por senha."
+ "O servidor selecionado não suporta início de sessão por senha nem por OIDC. Por favor, contacta o teu administrador ou escolhe outro servidor."
+ "Insere o teus detalhes"
+ "A Matrix é uma rede aberta de comunicação descentralizada e segura."
+ "Bem-vindo(a) de volta!"
+ "Iniciar sessão em %1$s"
+ "Alterar operador de conta"
+ "Um servidor privado para funcionários da Element."
+ "A Matrix é uma rede aberta de comunicação descentralizada e segura."
+ "É aqui que as tuas conversas vão ficar — tal como num serviço de e-mail."
+ "Irás iniciar sessão em %1$s"
+ "Irás criar uma conta em %1$s"
+ "Há uma grande procura pela %1$s no %2$s, de momento. Volta à aplicação daqui a uns dias e tenta novamente.
+
+Obrigado!"
+ "Bem-vindo à %1$s!"
+ "Estás quase lá."
+ "Está dentro"
+
diff --git a/features/login/impl/src/main/res/values-ro/translations.xml b/features/login/impl/src/main/res/values-ro/translations.xml
index 3f384a8764..8087fc7c44 100644
--- a/features/login/impl/src/main/res/values-ro/translations.xml
+++ b/features/login/impl/src/main/res/values-ro/translations.xml
@@ -14,6 +14,8 @@
"Utilizați un alt furnizor de cont, cum ar fi propriul server privat sau un cont de serviciu."
"Schimbați furnizorul contului"
"Nu am putut accesa acest homeserver. Te rugăm să verifici că ai introdus corect adresa URL a homeserver-ului. Dacă adresa URL este corectă, contactează administratorul homeserver-ului pentru ajutor suplimentar."
+ "Sliding sync nu este disponibil din cauza unei probleme în fișierul well-known:
+%1$s"
"Momentan acest server nu oferă suport pentru sliding sync."
"Adresa URL a homeserver-ului"
"Vă putețo conecta numai la un server existent care oferă suport pentru sliding sync. Administratorul homeserver-ului dumneavoastră va trebui să îl configureze. %1$s"
@@ -22,6 +24,7 @@
"Acest cont a fost dezactivat."
"Utilizator și/sau parolă incorecte"
"Acesta nu este un identificator de utilizator valid. Format așteptat: „@user:homeserver.org”"
+ "Acest server este configurat pentru a utiliza token-uri de reîmprospătare. Acestea nu sunt acceptate atunci când utilizați autentificare bazată pe parolă."
"Homeserver-ul selectat nu acceptă autentificarea prin parola sau OIDC. Te rugăm să contactezi administratorul sau să alegi un alt homeserver."
"Introduceți detaliile"
"Matrix este o rețea deschisă pentru o comunicare sigură și descentralizată."
diff --git a/features/login/impl/src/main/res/values-zh/translations.xml b/features/login/impl/src/main/res/values-zh/translations.xml
new file mode 100644
index 0000000000..76bbabb021
--- /dev/null
+++ b/features/login/impl/src/main/res/values-zh/translations.xml
@@ -0,0 +1,45 @@
+
+
+ "更改账户提供者"
+ "服务器地址"
+ "输入搜索词或域名地址。"
+ "搜索公司、社区或私人服务器。"
+ "查找账户提供者"
+ "这是您的对话将进行的地方,就像您使用电子邮件提供商来保存电子邮件一样。"
+ "您即将登录%s"
+ "这是您的对话将进行的地方,就像您使用电子邮件提供商来保存电子邮件一样。"
+ "您即将在 %s 上创建一个帐户"
+ "Matrix.org 由 Matrix.org 基金会运营,是用于安全、去中心化的通信的公共 Matrix 网络上的大型免费服务器。"
+ "其他"
+ "使用其他帐户提供者,例如您自己的私人服务器或工作帐户。"
+ "更改账户提供者"
+ "我们无法访问此主服务器。请检查您输入的主服务器网址是否正确。如果 URL 正确,请联系您的主服务器管理员寻求进一步帮助。"
+ "由于 Well Known 文件中的问题,Sliding Sync 不可用:
+%1$s"
+ "该服务器目前不支持sliding sync。"
+ "主服务器网址"
+ "您只能连接到支持sliding sync的现有服务器。您的主服务器管理员需要对其进行配置。%1$s"
+ "您的服务器地址是什么?"
+ "选择服务器"
+ "该账户已被停用。"
+ "错误的用户名和/或密码"
+ "这不是合法的用户 ID。期望格式:‘@user:homeserver.org’。"
+ "此服务器使用刷新令牌。使用密码登录时不支持这些功能。"
+ "该服务器不支持密码登录和 OIDC 第三方账户登录。请联系服务器管理员,或选择别的服务器。"
+ "输入您的详细信息"
+ "Matrix 是一个用于安全、去中心化通信的开放网络。"
+ "欢迎回来!"
+ "登录到 %1$s"
+ "更改账户提供者"
+ "专为 Element 员工提供的私人服务器。"
+ "Matrix 是一个用于安全、去中心化通信的开放网络。"
+ "这是您的对话将进行的地方,就像您使用电子邮件提供商来保存电子邮件一样。"
+ "你即将登录 %1$s"
+ "你即将在 %1$s 上创建一个账户"
+ "目前 %1$s 上 %2$s 的负载很大。过几天再回来试试吧。
+
+感谢您的耐心!"
+ "欢迎使用 %1$s"
+ "马上就好。"
+ "您已加入。"
+
diff --git a/features/logout/impl/build.gradle.kts b/features/logout/impl/build.gradle.kts
index 699d6c93b8..1383384c84 100644
--- a/features/logout/impl/build.gradle.kts
+++ b/features/logout/impl/build.gradle.kts
@@ -55,7 +55,6 @@ dependencies {
testImplementation(libs.test.truth)
testImplementation(libs.test.turbine)
testImplementation(libs.test.robolectric)
- testImplementation(libs.test.junitext)
testImplementation(libs.androidx.compose.ui.test.junit)
testReleaseImplementation(libs.androidx.compose.ui.test.manifest)
testImplementation(projects.libraries.matrix.test)
diff --git a/features/logout/impl/src/main/res/values-ka/translations.xml b/features/logout/impl/src/main/res/values-ka/translations.xml
new file mode 100644
index 0000000000..2226fd240f
--- /dev/null
+++ b/features/logout/impl/src/main/res/values-ka/translations.xml
@@ -0,0 +1,8 @@
+
+
+ "დარწმუნებული ხართ, რომ გსურთ გამოსვლა?"
+ "გამოსვლა"
+ "გამოსვლა"
+ "გასვლა…"
+ "გამოსვლა"
+
diff --git a/features/logout/impl/src/main/res/values-pt/translations.xml b/features/logout/impl/src/main/res/values-pt/translations.xml
new file mode 100644
index 0000000000..b8a7161c21
--- /dev/null
+++ b/features/logout/impl/src/main/res/values-pt/translations.xml
@@ -0,0 +1,18 @@
+
+
+ "Tens a certeza que queres terminar a sessão?"
+ "Terminar sessão"
+ "Terminar sessão"
+ "A terminar sessão…"
+ "Estás prestes a terminar a tua última sessão. Se continuares, perderás o acesso às tuas mensagens cifradas."
+ "Desativaste a cópia de segurança"
+ "As tuas chaves ainda estavam a ser guardadas quando ficaste desligado. Volta a ligar-te para que as tuas chaves possam ser guardadas antes de encerrares a sessão."
+ "As tuas chaves ainda estão a ser guardadas"
+ "Por favor, aguarda a conclusão desta operação antes de terminares a sessão."
+ "As tuas chaves ainda estão a ser guardadas"
+ "Terminar sessão"
+ "Estás prestes a terminar a tua última sessão. Se continuares, perderás o acesso às tuas mensagens cifradas."
+ "Recuperação não configurada"
+ "Estás prestes a terminar a tua última sessão. Se continuares, poderás perder o acesso às tuas mensagens cifradas."
+ "Guardaste a tua chave de recuperação?"
+
diff --git a/features/logout/impl/src/main/res/values-zh/translations.xml b/features/logout/impl/src/main/res/values-zh/translations.xml
new file mode 100644
index 0000000000..be1d740130
--- /dev/null
+++ b/features/logout/impl/src/main/res/values-zh/translations.xml
@@ -0,0 +1,18 @@
+
+
+ "确定要登出吗?"
+ "登出"
+ "登出"
+ "正在登出…"
+ "您即将登出最后一个会话。如果现在登出,你将无法访问加密的消息。"
+ "您已关闭备份"
+ "当你离线时,你的密钥仍在备份中。重新连接,以便在登出之前备份密钥。"
+ "您的密钥仍在备份中"
+ "请等待此操作完成后再登出。"
+ "您的密钥仍在备份中"
+ "登出"
+ "您即将登出最后一个会话。如果现在登出,你将无法访问加密的消息。"
+ "未设置恢复"
+ "您即将登出最后一个会话。如果现在登出,你将无法访问加密的消息。"
+ "您保存了恢复密钥吗?"
+
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 9531ea8886..70b346ba8d 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
@@ -144,7 +144,9 @@ class LogoutPresenterTest {
@Test
fun `present - logout with error then cancel`() = runTest {
val matrixClient = FakeMatrixClient().apply {
- givenLogoutError(A_THROWABLE)
+ logoutLambda = { _ ->
+ throw A_THROWABLE
+ }
}
val presenter = createLogoutPresenter(
matrixClient,
@@ -170,7 +172,13 @@ class LogoutPresenterTest {
@Test
fun `present - logout with error then force`() = runTest {
val matrixClient = FakeMatrixClient().apply {
- givenLogoutError(A_THROWABLE)
+ logoutLambda = { ignoreSdkError ->
+ if (!ignoreSdkError) {
+ throw A_THROWABLE
+ } else {
+ null
+ }
+ }
}
val presenter = createLogoutPresenter(
matrixClient,
diff --git a/features/logout/impl/src/test/kotlin/io/element/android/features/logout/impl/direct/DefaultDirectLogoutPresenterTest.kt b/features/logout/impl/src/test/kotlin/io/element/android/features/logout/impl/direct/DefaultDirectLogoutPresenterTest.kt
index bf3df93731..14d340570c 100644
--- a/features/logout/impl/src/test/kotlin/io/element/android/features/logout/impl/direct/DefaultDirectLogoutPresenterTest.kt
+++ b/features/logout/impl/src/test/kotlin/io/element/android/features/logout/impl/direct/DefaultDirectLogoutPresenterTest.kt
@@ -125,7 +125,9 @@ class DefaultDirectLogoutPresenterTest {
@Test
fun `present - logout with error then cancel`() = runTest {
val matrixClient = FakeMatrixClient().apply {
- givenLogoutError(A_THROWABLE)
+ logoutLambda = { _ ->
+ throw A_THROWABLE
+ }
}
val presenter = createDefaultDirectLogoutPresenter(
matrixClient,
@@ -151,7 +153,13 @@ class DefaultDirectLogoutPresenterTest {
@Test
fun `present - logout with error then force`() = runTest {
val matrixClient = FakeMatrixClient().apply {
- givenLogoutError(A_THROWABLE)
+ logoutLambda = { ignoreSdkError ->
+ if (!ignoreSdkError) {
+ throw A_THROWABLE
+ } else {
+ null
+ }
+ }
}
val presenter = createDefaultDirectLogoutPresenter(
matrixClient,
diff --git a/features/messages/impl/build.gradle.kts b/features/messages/impl/build.gradle.kts
index 2de95dff48..df0c4dff7a 100644
--- a/features/messages/impl/build.gradle.kts
+++ b/features/messages/impl/build.gradle.kts
@@ -99,7 +99,6 @@ dependencies {
testImplementation(projects.libraries.mediaviewer.test)
testImplementation(projects.libraries.testtags)
testImplementation(libs.test.mockk)
- testImplementation(libs.test.junitext)
testImplementation(libs.test.robolectric)
testImplementation(projects.features.poll.test)
testImplementation(projects.features.poll.impl)
diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/MessagesNode.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/MessagesNode.kt
index f3c3462cd8..cbdd20c770 100644
--- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/MessagesNode.kt
+++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/MessagesNode.kt
@@ -47,6 +47,7 @@ import io.element.android.libraries.architecture.inputs
import io.element.android.libraries.core.bool.orFalse
import io.element.android.libraries.di.ApplicationContext
import io.element.android.libraries.di.RoomScope
+import io.element.android.libraries.matrix.api.analytics.toAnalyticsViewRoom
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
@@ -57,7 +58,6 @@ import io.element.android.libraries.matrix.api.room.alias.matches
import io.element.android.libraries.matrix.api.timeline.item.TimelineItemDebugInfo
import io.element.android.libraries.mediaplayer.api.MediaPlayer
import io.element.android.services.analytics.api.AnalyticsService
-import io.element.android.services.analytics.api.extensions.toAnalyticsViewRoom
import kotlinx.collections.immutable.ImmutableList
@ContributesNode(RoomScope::class)
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 e5127ea865..579ea87868 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
@@ -31,6 +31,7 @@ import androidx.compose.runtime.setValue
import dagger.assisted.Assisted
import dagger.assisted.AssistedFactory
import dagger.assisted.AssistedInject
+import io.element.android.appconfig.MessageComposerConfig
import io.element.android.features.messages.api.timeline.HtmlConverterProvider
import io.element.android.features.messages.impl.actionlist.ActionListEvents
import io.element.android.features.messages.impl.actionlist.ActionListPresenter
@@ -66,7 +67,6 @@ import io.element.android.features.messages.impl.utils.messagesummary.MessageSum
import io.element.android.features.messages.impl.voicemessages.composer.VoiceMessageComposerPresenter
import io.element.android.features.networkmonitor.api.NetworkMonitor
import io.element.android.features.networkmonitor.api.NetworkStatus
-import io.element.android.features.preferences.api.store.AppPreferencesStore
import io.element.android.libraries.androidutils.clipboard.ClipboardHelper
import io.element.android.libraries.architecture.AsyncData
import io.element.android.libraries.architecture.Presenter
@@ -113,7 +113,6 @@ class MessagesPresenter @AssistedInject constructor(
private val messageSummaryFormatter: MessageSummaryFormatter,
private val dispatchers: CoroutineDispatchers,
private val clipboardHelper: ClipboardHelper,
- private val appPreferencesStore: AppPreferencesStore,
private val featureFlagsService: FeatureFlagService,
private val htmlConverterProvider: HtmlConverterProvider,
@Assisted private val navigator: MessagesNavigator,
@@ -171,17 +170,15 @@ class MessagesPresenter @AssistedInject constructor(
val inviteProgress = remember { mutableStateOf>(AsyncData.Uninitialized) }
var showReinvitePrompt by remember { mutableStateOf(false) }
- LaunchedEffect(hasDismissedInviteDialog, composerState.hasFocus, syncUpdateFlow.value) {
+ LaunchedEffect(hasDismissedInviteDialog, composerState.textEditorState.hasFocus(), syncUpdateFlow.value) {
withContext(dispatchers.io) {
- showReinvitePrompt = !hasDismissedInviteDialog && composerState.hasFocus && room.isDirect && room.activeMemberCount == 1L
+ showReinvitePrompt = !hasDismissedInviteDialog && composerState.textEditorState.hasFocus() && room.isDirect && room.activeMemberCount == 1L
}
}
val networkConnectionStatus by networkMonitor.connectivity.collectAsState()
val snackbarMessage by snackbarDispatcher.collectSnackbarMessageAsState()
- val enableTextFormatting by appPreferencesStore.isRichTextEditorEnabledFlow().collectAsState(initial = true)
-
var enableVoiceMessages by remember { mutableStateOf(false) }
LaunchedEffect(featureFlagsService) {
enableVoiceMessages = featureFlagsService.isFeatureEnabled(FeatureFlags.VoiceMessages)
@@ -194,7 +191,7 @@ class MessagesPresenter @AssistedInject constructor(
action = event.action,
targetEvent = event.event,
composerState = composerState,
- enableTextFormatting = enableTextFormatting,
+ enableTextFormatting = composerState.showTextFormatting,
timelineState = timelineState,
)
}
@@ -239,7 +236,7 @@ class MessagesPresenter @AssistedInject constructor(
snackbarMessage = snackbarMessage,
showReinvitePrompt = showReinvitePrompt,
inviteProgress = inviteProgress.value,
- enableTextFormatting = enableTextFormatting,
+ enableTextFormatting = MessageComposerConfig.ENABLE_RICH_TEXT_EDITING,
enableVoiceMessages = enableVoiceMessages,
appName = buildMeta.applicationName,
callState = callState,
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 acd7e86d58..fd00eba04b 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
@@ -45,6 +45,7 @@ import io.element.android.libraries.designsystem.components.avatar.AvatarSize
import io.element.android.libraries.matrix.api.core.RoomId
import io.element.android.libraries.textcomposer.aRichTextEditorState
import io.element.android.libraries.textcomposer.model.MessageComposerMode
+import io.element.android.libraries.textcomposer.model.TextEditorState
import kotlinx.collections.immutable.persistentListOf
import kotlinx.collections.immutable.persistentSetOf
@@ -99,9 +100,9 @@ fun aMessagesState(
userHasPermissionToRedactOther: Boolean = false,
userHasPermissionToSendReaction: Boolean = true,
composerState: MessageComposerState = aMessageComposerState(
- richTextEditorState = aRichTextEditorState(initialText = "Hello", initialFocus = true),
- isFullScreen = false,
- mode = MessageComposerMode.Normal,
+ textEditorState = TextEditorState.Rich(aRichTextEditorState(initialText = "Hello", initialFocus = true)),
+ isFullScreen = false,
+ mode = MessageComposerMode.Normal,
),
voiceMessageComposerState: VoiceMessageComposerState = aVoiceMessageComposerState(),
timelineState: TimelineState = aTimelineState(
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 597fd4b8c9..e7b65f353f 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
@@ -362,7 +362,7 @@ private fun MessagesViewContent(
// Any state change that should trigger a height size should be added to the list of remembered values here.
val sheetResizeContentKey = remember { mutableIntStateOf(0) }
LaunchedEffect(
- state.composerState.richTextEditorState.lineCount,
+ state.composerState.textEditorState.lineCount,
state.composerState.showTextFormatting,
) {
sheetResizeContentKey.intValue = Random.nextInt()
@@ -439,7 +439,6 @@ private fun MessagesViewComposerBottomSheetContents(
state = state.composerState,
voiceMessageState = state.voiceMessageComposerState,
subcomposing = subcomposing,
- enableTextFormatting = state.enableTextFormatting,
enableVoiceMessages = state.enableVoiceMessages,
modifier = Modifier.fillMaxWidth(),
)
diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/mentions/MentionSuggestionsPickerView.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/mentions/MentionSuggestionsPickerView.kt
index cf48ea1478..6639910ec9 100644
--- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/mentions/MentionSuggestionsPickerView.kt
+++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/mentions/MentionSuggestionsPickerView.kt
@@ -43,6 +43,7 @@ import io.element.android.libraries.matrix.api.core.RoomId
import io.element.android.libraries.matrix.api.core.UserId
import io.element.android.libraries.matrix.api.room.RoomMember
import io.element.android.libraries.matrix.api.room.RoomMembershipState
+import io.element.android.libraries.textcomposer.mentions.ResolvedMentionSuggestion
import kotlinx.collections.immutable.ImmutableList
import kotlinx.collections.immutable.persistentListOf
@@ -51,8 +52,8 @@ fun MentionSuggestionsPickerView(
roomId: RoomId,
roomName: String?,
roomAvatarData: AvatarData?,
- memberSuggestions: ImmutableList,
- onSuggestionSelected: (MentionSuggestion) -> Unit,
+ memberSuggestions: ImmutableList,
+ onSuggestionSelected: (ResolvedMentionSuggestion) -> Unit,
modifier: Modifier = Modifier,
) {
LazyColumn(
@@ -62,8 +63,8 @@ fun MentionSuggestionsPickerView(
memberSuggestions,
key = { suggestion ->
when (suggestion) {
- is MentionSuggestion.Room -> "@room"
- is MentionSuggestion.Member -> suggestion.roomMember.userId.value
+ is ResolvedMentionSuggestion.AtRoom -> "@room"
+ is ResolvedMentionSuggestion.Member -> suggestion.roomMember.userId.value
}
}
) {
@@ -84,18 +85,18 @@ fun MentionSuggestionsPickerView(
@Composable
private fun RoomMemberSuggestionItemView(
- memberSuggestion: MentionSuggestion,
+ memberSuggestion: ResolvedMentionSuggestion,
roomId: String,
roomName: String?,
roomAvatar: AvatarData?,
- onSuggestionSelected: (MentionSuggestion) -> Unit,
+ onSuggestionSelected: (ResolvedMentionSuggestion) -> Unit,
modifier: Modifier = Modifier,
) {
Row(modifier = modifier.clickable { onSuggestionSelected(memberSuggestion) }, horizontalArrangement = Arrangement.spacedBy(16.dp)) {
val avatarSize = AvatarSize.TimelineRoom
val avatarData = when (memberSuggestion) {
- is MentionSuggestion.Room -> roomAvatar?.copy(size = avatarSize) ?: AvatarData(roomId, roomName, null, avatarSize)
- is MentionSuggestion.Member -> AvatarData(
+ is ResolvedMentionSuggestion.AtRoom -> roomAvatar?.copy(size = avatarSize) ?: AvatarData(roomId, roomName, null, avatarSize)
+ is ResolvedMentionSuggestion.Member -> AvatarData(
memberSuggestion.roomMember.userId.value,
memberSuggestion.roomMember.displayName,
memberSuggestion.roomMember.avatarUrl,
@@ -103,13 +104,13 @@ private fun RoomMemberSuggestionItemView(
)
}
val title = when (memberSuggestion) {
- is MentionSuggestion.Room -> stringResource(R.string.screen_room_mentions_at_room_title)
- is MentionSuggestion.Member -> memberSuggestion.roomMember.displayName
+ is ResolvedMentionSuggestion.AtRoom -> stringResource(R.string.screen_room_mentions_at_room_title)
+ is ResolvedMentionSuggestion.Member -> memberSuggestion.roomMember.displayName
}
val subtitle = when (memberSuggestion) {
- is MentionSuggestion.Room -> "@room"
- is MentionSuggestion.Member -> memberSuggestion.roomMember.userId.value
+ is ResolvedMentionSuggestion.AtRoom -> "@room"
+ is ResolvedMentionSuggestion.Member -> memberSuggestion.roomMember.userId.value
}
Avatar(avatarData = avatarData, modifier = Modifier.padding(start = 16.dp, top = 12.dp, bottom = 12.dp))
@@ -159,9 +160,9 @@ internal fun MentionSuggestionsPickerViewPreview() {
roomName = "Room",
roomAvatarData = null,
memberSuggestions = persistentListOf(
- MentionSuggestion.Room,
- MentionSuggestion.Member(roomMember),
- MentionSuggestion.Member(roomMember.copy(userId = UserId("@bob:server.org"), displayName = "Bob")),
+ ResolvedMentionSuggestion.AtRoom,
+ ResolvedMentionSuggestion.Member(roomMember),
+ ResolvedMentionSuggestion.Member(roomMember.copy(userId = UserId("@bob:server.org"), displayName = "Bob")),
),
onSuggestionSelected = {}
)
diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/mentions/MentionSuggestionsProcessor.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/mentions/MentionSuggestionsProcessor.kt
index 696f0fe93e..f0e89c1148 100644
--- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/mentions/MentionSuggestionsProcessor.kt
+++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/mentions/MentionSuggestionsProcessor.kt
@@ -22,6 +22,7 @@ import io.element.android.libraries.matrix.api.room.MatrixRoomMembersState
import io.element.android.libraries.matrix.api.room.RoomMember
import io.element.android.libraries.matrix.api.room.RoomMembershipState
import io.element.android.libraries.matrix.api.room.roomMembers
+import io.element.android.libraries.textcomposer.mentions.ResolvedMentionSuggestion
import io.element.android.libraries.textcomposer.model.Suggestion
import io.element.android.libraries.textcomposer.model.SuggestionType
@@ -45,7 +46,7 @@ object MentionSuggestionsProcessor {
roomMembersState: MatrixRoomMembersState,
currentUserId: UserId,
canSendRoomMention: suspend () -> Boolean,
- ): List {
+ ): List {
val members = roomMembersState.roomMembers()
return when {
members.isNullOrEmpty() || suggestion == null -> {
@@ -78,7 +79,7 @@ object MentionSuggestionsProcessor {
roomMembers: List?,
currentUserId: UserId,
canSendRoomMention: Boolean,
- ): List {
+ ): List {
return if (roomMembers.isNullOrEmpty()) {
emptyList()
} else {
@@ -96,10 +97,10 @@ object MentionSuggestionsProcessor {
.filterUpTo(MAX_BATCH_ITEMS) { member ->
isJoinedMemberAndNotSelf(member) && memberMatchesQuery(member, query)
}
- .map(MentionSuggestion::Member)
+ .map(ResolvedMentionSuggestion::Member)
if ("room".contains(query) && canSendRoomMention) {
- listOf(MentionSuggestion.Room) + matchingMembers
+ listOf(ResolvedMentionSuggestion.AtRoom) + matchingMembers
} else {
matchingMembers
}
diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/messagecomposer/AttachmentsBottomSheet.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/messagecomposer/AttachmentsBottomSheet.kt
index c2ed969a92..8845854602 100644
--- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/messagecomposer/AttachmentsBottomSheet.kt
+++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/messagecomposer/AttachmentsBottomSheet.kt
@@ -106,18 +106,6 @@ private fun AttachmentSourcePickerMenu(
.navigationBarsPadding()
.imePadding()
) {
- ListItem(
- modifier = Modifier.clickable { state.eventSink(MessageComposerEvents.PickAttachmentSource.FromGallery) },
- leadingContent = ListItemContent.Icon(IconSource.Vector(CompoundIcons.Image())),
- headlineContent = { Text(stringResource(R.string.screen_room_attachment_source_gallery)) },
- style = ListItemStyle.Primary,
- )
- ListItem(
- modifier = Modifier.clickable { state.eventSink(MessageComposerEvents.PickAttachmentSource.FromFiles) },
- leadingContent = ListItemContent.Icon(IconSource.Vector(CompoundIcons.Attachment())),
- headlineContent = { Text(stringResource(R.string.screen_room_attachment_source_files)) },
- style = ListItemStyle.Primary,
- )
ListItem(
modifier = Modifier.clickable { state.eventSink(MessageComposerEvents.PickAttachmentSource.PhotoFromCamera) },
leadingContent = ListItemContent.Icon(IconSource.Vector(CompoundIcons.TakePhoto())),
@@ -130,6 +118,18 @@ private fun AttachmentSourcePickerMenu(
headlineContent = { Text(stringResource(R.string.screen_room_attachment_source_camera_video)) },
style = ListItemStyle.Primary,
)
+ ListItem(
+ modifier = Modifier.clickable { state.eventSink(MessageComposerEvents.PickAttachmentSource.FromGallery) },
+ leadingContent = ListItemContent.Icon(IconSource.Vector(CompoundIcons.Image())),
+ headlineContent = { Text(stringResource(R.string.screen_room_attachment_source_gallery)) },
+ style = ListItemStyle.Primary,
+ )
+ ListItem(
+ modifier = Modifier.clickable { state.eventSink(MessageComposerEvents.PickAttachmentSource.FromFiles) },
+ leadingContent = ListItemContent.Icon(IconSource.Vector(CompoundIcons.Attachment())),
+ headlineContent = { Text(stringResource(R.string.screen_room_attachment_source_files)) },
+ style = ListItemStyle.Primary,
+ )
if (state.canShareLocation) {
ListItem(
modifier = Modifier.clickable {
diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/messagecomposer/MessageComposerEvents.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/messagecomposer/MessageComposerEvents.kt
index 9ddf1f7aae..19ca038bd2 100644
--- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/messagecomposer/MessageComposerEvents.kt
+++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/messagecomposer/MessageComposerEvents.kt
@@ -18,15 +18,14 @@ package io.element.android.features.messages.impl.messagecomposer
import android.net.Uri
import androidx.compose.runtime.Immutable
-import io.element.android.features.messages.impl.mentions.MentionSuggestion
-import io.element.android.libraries.textcomposer.model.Message
+import io.element.android.libraries.textcomposer.mentions.ResolvedMentionSuggestion
import io.element.android.libraries.textcomposer.model.MessageComposerMode
import io.element.android.libraries.textcomposer.model.Suggestion
@Immutable
sealed interface MessageComposerEvents {
data object ToggleFullScreenState : MessageComposerEvents
- data class SendMessage(val message: Message) : MessageComposerEvents
+ data object SendMessage : MessageComposerEvents
data class SendUri(val uri: Uri) : MessageComposerEvents
data object CloseSpecialMode : MessageComposerEvents
data class SetMode(val composerMode: MessageComposerMode) : MessageComposerEvents
@@ -45,5 +44,5 @@ sealed interface MessageComposerEvents {
data class Error(val error: Throwable) : MessageComposerEvents
data class TypingNotice(val isTyping: Boolean) : MessageComposerEvents
data class SuggestionReceived(val suggestion: Suggestion?) : MessageComposerEvents
- data class InsertMention(val mention: MentionSuggestion) : MessageComposerEvents
+ data class InsertMention(val mention: ResolvedMentionSuggestion) : MessageComposerEvents
}
diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/messagecomposer/MessageComposerPresenter.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/messagecomposer/MessageComposerPresenter.kt
index 30bdadcbe5..2c4e180bd7 100644
--- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/messagecomposer/MessageComposerPresenter.kt
+++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/messagecomposer/MessageComposerPresenter.kt
@@ -19,6 +19,7 @@ package io.element.android.features.messages.impl.messagecomposer
import android.Manifest
import android.annotation.SuppressLint
import android.net.Uri
+import androidx.annotation.VisibleForTesting
import androidx.compose.runtime.Composable
import androidx.compose.runtime.DisposableEffect
import androidx.compose.runtime.LaunchedEffect
@@ -29,6 +30,7 @@ import androidx.compose.runtime.mutableStateListOf
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberCoroutineScope
+import androidx.compose.runtime.rememberUpdatedState
import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.runtime.setValue
import androidx.media3.common.MimeTypes
@@ -36,7 +38,6 @@ import androidx.media3.common.util.UnstableApi
import im.vector.app.features.analytics.plan.Composer
import io.element.android.features.messages.impl.attachments.Attachment
import io.element.android.features.messages.impl.attachments.preview.error.sendAttachmentError
-import io.element.android.features.messages.impl.mentions.MentionSuggestion
import io.element.android.features.messages.impl.mentions.MentionSuggestionsProcessor
import io.element.android.features.messages.impl.timeline.TimelineController
import io.element.android.features.preferences.api.store.SessionPreferencesStore
@@ -59,17 +60,21 @@ import io.element.android.libraries.mediaupload.api.MediaSender
import io.element.android.libraries.mediaviewer.api.local.LocalMediaFactory
import io.element.android.libraries.permissions.api.PermissionsEvents
import io.element.android.libraries.permissions.api.PermissionsPresenter
+import io.element.android.libraries.textcomposer.mentions.ResolvedMentionSuggestion
+import io.element.android.libraries.textcomposer.mentions.rememberMentionSpanProvider
+import io.element.android.libraries.textcomposer.model.MarkdownTextEditorState
import io.element.android.libraries.textcomposer.model.Message
import io.element.android.libraries.textcomposer.model.MessageComposerMode
import io.element.android.libraries.textcomposer.model.Suggestion
+import io.element.android.libraries.textcomposer.model.TextEditorState
import io.element.android.services.analytics.api.AnalyticsService
-import io.element.android.wysiwyg.compose.RichTextEditorState
import kotlinx.collections.immutable.persistentListOf
import kotlinx.collections.immutable.toPersistentList
import kotlinx.coroutines.CancellationException
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.FlowPreview
import kotlinx.coroutines.Job
+import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.collect
import kotlinx.coroutines.flow.combine
@@ -108,12 +113,27 @@ class MessageComposerPresenter @Inject constructor(
private val suggestionSearchTrigger = MutableStateFlow(null)
+ // Used to disable some UI related elements in tests
+ @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE)
+ internal var isTesting: Boolean = false
+
+ @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE)
+ internal var showTextFormatting: Boolean by mutableStateOf(false)
+
@OptIn(FlowPreview::class)
@SuppressLint("UnsafeOptInUsageError")
@Composable
override fun present(): MessageComposerState {
val localCoroutineScope = rememberCoroutineScope()
+ // Initially disabled so we don't set focus and text twice
+ var applyFormattingModeChanges by remember { mutableStateOf(false) }
+ val richTextEditorState = richTextEditorStateFactory.remember()
+ if (isTesting) {
+ richTextEditorState.isReadyToProcessActions = true
+ }
+ val markdownTextEditorState = remember { MarkdownTextEditorState(initialText = null, initialFocus = false) }
+
var isMentionsEnabled by remember { mutableStateOf(false) }
LaunchedEffect(Unit) {
isMentionsEnabled = featureFlagService.isFeatureEnabled(FeatureFlags.Mentions)
@@ -149,18 +169,20 @@ class MessageComposerPresenter @Inject constructor(
val isFullScreen = rememberSaveable {
mutableStateOf(false)
}
- val richTextEditorState = richTextEditorStateFactory.create()
val ongoingSendAttachmentJob = remember { mutableStateOf(null) }
var showAttachmentSourcePicker: Boolean by remember { mutableStateOf(false) }
- var showTextFormatting: Boolean by remember { mutableStateOf(false) }
val sendTypingNotifications by sessionPreferencesStore.isSendTypingNotificationsEnabled().collectAsState(initial = true)
LaunchedEffect(messageComposerContext.composerMode) {
when (val modeValue = messageComposerContext.composerMode) {
is MessageComposerMode.Edit ->
- richTextEditorState.setHtml(modeValue.defaultContent)
+ if (showTextFormatting) {
+ richTextEditorState.setHtml(modeValue.defaultContent)
+ } else {
+ markdownTextEditorState.text.update(modeValue.defaultContent, true)
+ }
else -> Unit
}
}
@@ -188,7 +210,7 @@ class MessageComposerPresenter @Inject constructor(
}
}
- val memberSuggestions = remember { mutableStateListOf() }
+ val memberSuggestions = remember { mutableStateListOf() }
LaunchedEffect(isMentionsEnabled) {
if (!isMentionsEnabled) return@LaunchedEffect
val currentUserId = currentSessionIdHolder.current
@@ -229,22 +251,69 @@ class MessageComposerPresenter @Inject constructor(
}
}
+ val textEditorState by rememberUpdatedState(
+ if (showTextFormatting) {
+ TextEditorState.Rich(richTextEditorState)
+ } else {
+ TextEditorState.Markdown(markdownTextEditorState)
+ }
+ )
+
+ LaunchedEffect(showTextFormatting) {
+ if (!applyFormattingModeChanges) {
+ applyFormattingModeChanges = true
+ return@LaunchedEffect
+ }
+ if (showTextFormatting) {
+ val markdown = markdownTextEditorState.getMessageMarkdown(permalinkBuilder)
+ richTextEditorState.setMarkdown(markdown)
+ richTextEditorState.requestFocus()
+ } else {
+ val markdown = richTextEditorState.messageMarkdown
+ markdownTextEditorState.text.update(markdown, true)
+ // Give some time for the focus of the previous editor to be cleared
+ delay(100)
+ markdownTextEditorState.requestFocusAction()
+ }
+ }
+
+ val mentionSpanProvider = if (isTesting) {
+ null
+ } else {
+ rememberMentionSpanProvider(
+ currentUserId = room.sessionId,
+ permalinkParser = permalinkParser,
+ )
+ }
+
fun handleEvents(event: MessageComposerEvents) {
when (event) {
MessageComposerEvents.ToggleFullScreenState -> isFullScreen.value = !isFullScreen.value
MessageComposerEvents.CloseSpecialMode -> {
if (messageComposerContext.composerMode is MessageComposerMode.Edit) {
localCoroutineScope.launch {
- richTextEditorState.setHtml("")
+ textEditorState.reset()
}
}
messageComposerContext.composerMode = MessageComposerMode.Normal
}
- is MessageComposerEvents.SendMessage -> appCoroutineScope.sendMessage(
- message = event.message,
- updateComposerMode = { messageComposerContext.composerMode = it },
- richTextEditorState = richTextEditorState,
- )
+ is MessageComposerEvents.SendMessage -> {
+ val html = if (showTextFormatting) {
+ richTextEditorState.messageHtml
+ } else {
+ null
+ }
+ val markdown = if (showTextFormatting) {
+ richTextEditorState.messageMarkdown
+ } else {
+ markdownTextEditorState.getMessageMarkdown(permalinkBuilder)
+ }
+ appCoroutineScope.sendMessage(
+ message = Message(html = html, markdown = markdown),
+ updateComposerMode = { messageComposerContext.composerMode = it },
+ textEditorState = textEditorState,
+ )
+ }
is MessageComposerEvents.SendUri -> appCoroutineScope.sendAttachment(
attachment = Attachment.Media(
localMedia = localMediaFactory.createFromUri(
@@ -335,15 +404,26 @@ class MessageComposerPresenter @Inject constructor(
}
is MessageComposerEvents.InsertMention -> {
localCoroutineScope.launch {
- when (val mention = event.mention) {
- is MentionSuggestion.Room -> {
- richTextEditorState.insertAtRoomMentionAtSuggestion()
+ if (showTextFormatting) {
+ when (val mention = event.mention) {
+ is ResolvedMentionSuggestion.AtRoom -> {
+ richTextEditorState.insertAtRoomMentionAtSuggestion()
+ }
+ is ResolvedMentionSuggestion.Member -> {
+ val text = mention.roomMember.displayName?.prependIndent("@") ?: mention.roomMember.userId.value
+ val link = permalinkBuilder.permalinkForUser(mention.roomMember.userId).getOrNull() ?: return@launch
+ richTextEditorState.insertMentionAtSuggestion(text = text, link = link)
+ }
}
- is MentionSuggestion.Member -> {
- val text = mention.roomMember.displayName?.prependIndent("@") ?: mention.roomMember.userId.value
- val link = permalinkBuilder.permalinkForUser(mention.roomMember.userId).getOrNull() ?: return@launch
- richTextEditorState.insertMentionAtSuggestion(text = text, link = link)
+ } else if (markdownTextEditorState.currentMentionSuggestion != null) {
+ mentionSpanProvider?.let {
+ markdownTextEditorState.insertMention(
+ mention = event.mention,
+ mentionSpanProvider = it,
+ permalinkBuilder = permalinkBuilder,
+ )
}
+ suggestionSearchTrigger.value = null
}
}
}
@@ -351,7 +431,7 @@ class MessageComposerPresenter @Inject constructor(
}
return MessageComposerState(
- richTextEditorState = richTextEditorState,
+ textEditorState = textEditorState,
permalinkParser = permalinkParser,
isFullScreen = isFullScreen.value,
mode = messageComposerContext.composerMode,
@@ -369,21 +449,26 @@ class MessageComposerPresenter @Inject constructor(
private fun CoroutineScope.sendMessage(
message: Message,
updateComposerMode: (newComposerMode: MessageComposerMode) -> Unit,
- richTextEditorState: RichTextEditorState,
+ textEditorState: TextEditorState,
) = launch {
val capturedMode = messageComposerContext.composerMode
- val mentions = richTextEditorState.mentionsState?.let { state ->
- buildList {
- if (state.hasAtRoomMention) {
- add(Mention.AtRoom)
- }
- for (userId in state.userIds) {
- add(Mention.User(UserId(userId)))
- }
+ val mentions = when (textEditorState) {
+ is TextEditorState.Rich -> {
+ textEditorState.richTextEditorState.mentionsState?.let { state ->
+ buildList {
+ if (state.hasAtRoomMention) {
+ add(Mention.AtRoom)
+ }
+ for (userId in state.userIds) {
+ add(Mention.User(UserId(userId)))
+ }
+ }
+ }.orEmpty()
}
- }.orEmpty()
+ is TextEditorState.Markdown -> textEditorState.state.getMentions()
+ }
// Reset composer right away
- richTextEditorState.setHtml("")
+ textEditorState.reset()
updateComposerMode(MessageComposerMode.Normal)
when (capturedMode) {
is MessageComposerMode.Normal -> room.sendMessage(body = message.markdown, htmlBody = message.html, mentions = mentions)
diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/messagecomposer/MessageComposerState.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/messagecomposer/MessageComposerState.kt
index 194ce1914c..4ac69ed3d6 100644
--- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/messagecomposer/MessageComposerState.kt
+++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/messagecomposer/MessageComposerState.kt
@@ -19,16 +19,16 @@ package io.element.android.features.messages.impl.messagecomposer
import androidx.compose.runtime.Immutable
import androidx.compose.runtime.Stable
import io.element.android.features.messages.impl.attachments.Attachment
-import io.element.android.features.messages.impl.mentions.MentionSuggestion
import io.element.android.libraries.matrix.api.core.UserId
import io.element.android.libraries.matrix.api.permalink.PermalinkParser
+import io.element.android.libraries.textcomposer.mentions.ResolvedMentionSuggestion
import io.element.android.libraries.textcomposer.model.MessageComposerMode
-import io.element.android.wysiwyg.compose.RichTextEditorState
+import io.element.android.libraries.textcomposer.model.TextEditorState
import kotlinx.collections.immutable.ImmutableList
@Stable
data class MessageComposerState(
- val richTextEditorState: RichTextEditorState,
+ val textEditorState: TextEditorState,
val permalinkParser: PermalinkParser,
val isFullScreen: Boolean,
val mode: MessageComposerMode,
@@ -37,12 +37,10 @@ data class MessageComposerState(
val canShareLocation: Boolean,
val canCreatePoll: Boolean,
val attachmentsState: AttachmentsState,
- val memberSuggestions: ImmutableList,
+ val memberSuggestions: ImmutableList,
val currentUserId: UserId,
val eventSink: (MessageComposerEvents) -> Unit,
-) {
- val hasFocus: Boolean = richTextEditorState.hasFocus
-}
+)
@Immutable
sealed interface AttachmentsState {
diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/messagecomposer/MessageComposerStateProvider.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/messagecomposer/MessageComposerStateProvider.kt
index 340f7328f3..7ec47f4ef5 100644
--- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/messagecomposer/MessageComposerStateProvider.kt
+++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/messagecomposer/MessageComposerStateProvider.kt
@@ -17,13 +17,13 @@
package io.element.android.features.messages.impl.messagecomposer
import androidx.compose.ui.tooling.preview.PreviewParameterProvider
-import io.element.android.features.messages.impl.mentions.MentionSuggestion
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.permalink.PermalinkParser
import io.element.android.libraries.textcomposer.aRichTextEditorState
+import io.element.android.libraries.textcomposer.mentions.ResolvedMentionSuggestion
import io.element.android.libraries.textcomposer.model.MessageComposerMode
-import io.element.android.wysiwyg.compose.RichTextEditorState
+import io.element.android.libraries.textcomposer.model.TextEditorState
import kotlinx.collections.immutable.ImmutableList
import kotlinx.collections.immutable.persistentListOf
@@ -35,7 +35,7 @@ open class MessageComposerStateProvider : PreviewParameterProvider = persistentListOf(),
+ memberSuggestions: ImmutableList = persistentListOf(),
) = MessageComposerState(
- richTextEditorState = richTextEditorState,
+ textEditorState = textEditorState,
permalinkParser = object : PermalinkParser {
override fun parse(uriString: String): PermalinkData = TODO()
},
diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/messagecomposer/MessageComposerView.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/messagecomposer/MessageComposerView.kt
index e68cf29844..207d811707 100644
--- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/messagecomposer/MessageComposerView.kt
+++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/messagecomposer/MessageComposerView.kt
@@ -33,7 +33,6 @@ import io.element.android.features.messages.impl.voicemessages.composer.aVoiceMe
import io.element.android.libraries.designsystem.preview.ElementPreview
import io.element.android.libraries.designsystem.preview.PreviewsDayNight
import io.element.android.libraries.textcomposer.TextComposer
-import io.element.android.libraries.textcomposer.model.Message
import io.element.android.libraries.textcomposer.model.Suggestion
import io.element.android.libraries.textcomposer.model.VoiceMessagePlayerEvent
import io.element.android.libraries.textcomposer.model.VoiceMessageRecorderEvent
@@ -44,13 +43,12 @@ internal fun MessageComposerView(
state: MessageComposerState,
voiceMessageState: VoiceMessageComposerState,
subcomposing: Boolean,
- enableTextFormatting: Boolean,
enableVoiceMessages: Boolean,
modifier: Modifier = Modifier,
) {
val view = LocalView.current
- fun sendMessage(message: Message) {
- state.eventSink(MessageComposerEvents.SendMessage(message))
+ fun sendMessage() {
+ state.eventSink(MessageComposerEvents.SendMessage)
}
fun sendUri(uri: Uri) {
@@ -85,7 +83,7 @@ internal fun MessageComposerView(
val coroutineScope = rememberCoroutineScope()
fun onRequestFocus() {
coroutineScope.launch {
- state.richTextEditorState.requestFocus()
+ state.textEditorState.requestFocus()
}
}
@@ -107,7 +105,7 @@ internal fun MessageComposerView(
TextComposer(
modifier = modifier,
- state = state.richTextEditorState,
+ state = state.textEditorState,
voiceMessageState = voiceMessageState.voiceMessageState,
permalinkParser = state.permalinkParser,
subcomposing = subcomposing,
@@ -118,7 +116,6 @@ internal fun MessageComposerView(
onResetComposerMode = ::onCloseSpecialMode,
onAddAttachment = ::onAddAttachment,
onDismissTextFormatting = ::onDismissTextFormatting,
- enableTextFormatting = enableTextFormatting,
enableVoiceMessages = enableVoiceMessages,
onVoiceRecorderEvent = onVoiceRecorderEvent,
onVoicePlayerEvent = onVoicePlayerEvent,
@@ -142,7 +139,6 @@ internal fun MessageComposerViewPreview(
modifier = Modifier.height(IntrinsicSize.Min),
state = state,
voiceMessageState = aVoiceMessageComposerState(),
- enableTextFormatting = true,
enableVoiceMessages = true,
subcomposing = false,
)
@@ -150,7 +146,6 @@ internal fun MessageComposerViewPreview(
modifier = Modifier.height(200.dp),
state = state,
voiceMessageState = aVoiceMessageComposerState(),
- enableTextFormatting = true,
enableVoiceMessages = true,
subcomposing = false,
)
@@ -167,7 +162,6 @@ internal fun MessageComposerViewVoicePreview(
modifier = Modifier.height(IntrinsicSize.Min),
state = aMessageComposerState(),
voiceMessageState = state,
- enableTextFormatting = true,
enableVoiceMessages = true,
subcomposing = false,
)
diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/messagecomposer/RichTextEditorStateFactory.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/messagecomposer/RichTextEditorStateFactory.kt
index 52fff81c31..4ce09e800d 100644
--- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/messagecomposer/RichTextEditorStateFactory.kt
+++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/messagecomposer/RichTextEditorStateFactory.kt
@@ -25,13 +25,13 @@ import javax.inject.Inject
interface RichTextEditorStateFactory {
@Composable
- fun create(): RichTextEditorState
+ fun remember(): RichTextEditorState
}
@ContributesBinding(AppScope::class)
class DefaultRichTextEditorStateFactory @Inject constructor() : RichTextEditorStateFactory {
@Composable
- override fun create(): RichTextEditorState {
+ override fun remember(): RichTextEditorState {
return rememberRichTextEditorState()
}
}
diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/factories/event/TimelineItemContentMessageFactory.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/factories/event/TimelineItemContentMessageFactory.kt
index 2aba9c3669..5c0623b480 100644
--- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/factories/event/TimelineItemContentMessageFactory.kt
+++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/factories/event/TimelineItemContentMessageFactory.kt
@@ -268,12 +268,16 @@ class TimelineItemContentMessageFactory @Inject constructor(
}
// Find and set as URLSpans any links present in the text
LinkifyCompat.addLinks(this, Linkify.WEB_URLS or Linkify.PHONE_NUMBERS or Linkify.EMAIL_ADDRESSES)
- // Restore old spans if they don't conflict with the new ones
+ // Restore old spans, remove new ones if there is a conflict
for ((urlSpan, location) in oldURLSpans) {
val (start, end) = location
- if (getSpans(start, end).isEmpty()) {
- setSpan(urlSpan, start, end, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE)
+ val addedSpans = getSpans(start, end).orEmpty()
+ if (addedSpans.isNotEmpty()) {
+ for (span in addedSpans) {
+ removeSpan(span)
+ }
}
+ setSpan(urlSpan, start, end, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE)
}
return this
}
diff --git a/features/messages/impl/src/main/res/values-es/translations.xml b/features/messages/impl/src/main/res/values-es/translations.xml
index 2f4fdca67d..8404cc6ec6 100644
--- a/features/messages/impl/src/main/res/values-es/translations.xml
+++ b/features/messages/impl/src/main/res/values-es/translations.xml
@@ -41,4 +41,13 @@
- "%1$d cambio en la sala"
- "%1$d cambios en la sala"
+
+ - "%1$s, %2$s y %3$d otro"
+ - "%1$s, %2$s y %3$d otros"
+
+
+ - "%1$s está escribiendo"
+ - "%1$s están escribiendo"
+
+ "%1$s y %2$s"
diff --git a/features/messages/impl/src/main/res/values-ka/translations.xml b/features/messages/impl/src/main/res/values-ka/translations.xml
new file mode 100644
index 0000000000..080696776f
--- /dev/null
+++ b/features/messages/impl/src/main/res/values-ka/translations.xml
@@ -0,0 +1,42 @@
+
+
+ "აქტივობები"
+ "დროშები"
+ "Საჭმელ-სასმელი"
+ "ცხოველები & ბუნება"
+ "ობიექტები"
+ "ღიმილები & ხალხი"
+ "მოგზაურობა და ადგილები"
+ "სიმბოლოები"
+ "მომხმარებლის დაბლოკვა"
+ "შეამოწმეთ, გსურთ თუ არა ამ მომხმარებლის ყველა მიმდინარე და მომავალი შეტყობინების დამალვა"
+ "ეს შეტყობინება გაგზავნილი იქნება თქვენი სახლის სერვერის ადმინისტრატორისადმი. მას არ ექნება დაშიფვრული შეტყობინებების წაკითხვის შესაძლებლობა."
+ "ამ კონტენტის დარეპორტების მიზეზი"
+ "კამერა"
+ "ფოტოს გადაღება"
+ "ვიდეოს ჩაწერა"
+ "დანართი"
+ "ფოტოსა და ვიდეოს ბიბლიოთეკა"
+ "ადგილმდებარეობა"
+ "გამოკითხვა"
+ "ტექსტის ფორმატირება"
+ "შეტყობინებების ისტორია ამჟამად მიუწვდომელია."
+ "გსურთ მათი კვლავ მოწვევა?"
+ "თქვენ მარტო ხართ ამ ჩატში"
+ "ყველა"
+ "Ხელახლა გაგზავნა"
+ "თქვენი შეტყობინების გაგზავნა ვერ მოხერხდა"
+ "ემოჯის დამატება"
+ "ეს არის %1$s-ს დასაწყისი."
+ "ეს არის ამ საუბრის დასაწყისი."
+ "ნაკლების ჩვენება"
+ "შეტყობინება დაკოპირდა"
+ "თქვენ არ გაქვთ ამ ოთახში გამოქვეყნების ნებართვა"
+ "ნაკლების ჩვენება"
+ "მეტის ჩვენება"
+ "ახალი"
+
+ - "%1$dოთახის ცვლილება"
+ - "%1$dოთახის ცვლილებები"
+
+
diff --git a/features/messages/impl/src/main/res/values-pt/translations.xml b/features/messages/impl/src/main/res/values-pt/translations.xml
new file mode 100644
index 0000000000..0dc4293f2d
--- /dev/null
+++ b/features/messages/impl/src/main/res/values-pt/translations.xml
@@ -0,0 +1,53 @@
+
+
+ "Atividades"
+ "Bandeiras"
+ "Comidas e Bebidas"
+ "Animais e Natureza"
+ "Objetos"
+ "Caras e Pessoas"
+ "Viagens e Lugares"
+ "Símbolos"
+ "Bloquear utilizador"
+ "Ativar para esconder todas as atuais e futuras mensagens deste utilizador"
+ "Esta mensagem será denunciada ao administrador do teu servidor. Porém, não lhe será possível ler quaisquer mensagens cifradas."
+ "Razão de denúncia"
+ "Câmara"
+ "Tirar foto"
+ "Gravar vídeo"
+ "Anexo"
+ "Biblioteca de fotos e vídeos"
+ "Localização"
+ "Sondagem"
+ "Formatação de texto"
+ "De momento, o histórico de mensagens está indisponível."
+ "O histórico de mensagens não está disponível nesta sala. Verifica este dispositivo para veres o histórico."
+ "Gostarias de convidá-lo de volta?"
+ "Estás sozinho nesta conversa"
+ "Notificar toda a sala"
+ "Toda a gente"
+ "Enviar novamente"
+ "Falha ao enviar a tua mensagem"
+ "Adicionar emoji"
+ "%1$s começou aqui."
+ "Esta conversa começou aqui."
+ "Mostrar menos"
+ "Mensagem copiada"
+ "Não tens permissão para publicar nesta sala"
+ "Mostrar menos"
+ "Mostrar mais"
+ "Novas"
+
+ - "%1$d alteração à sala"
+ - "%1$d alterações à sala"
+
+
+ - "%1$s, %2$s e %3$d outro"
+ - "%1$s, %2$s e %3$d outros"
+
+
+ - "%1$s está a escrever"
+ - "%1$s estão a escrever"
+
+ "%1$s e %2$s"
+
diff --git a/features/messages/impl/src/main/res/values-ro/translations.xml b/features/messages/impl/src/main/res/values-ro/translations.xml
index 98520ece20..9b44893ce2 100644
--- a/features/messages/impl/src/main/res/values-ro/translations.xml
+++ b/features/messages/impl/src/main/res/values-ro/translations.xml
@@ -48,9 +48,9 @@
- "%1$s, %2$s și încă %3$d"
- - "%1$s scrie"
- - "%1$s scriu"
- - "%1$s scriu"
+ - "%1$s tastează"
+ - "%1$s tastează"
+ - "%1$s tastează"
"%1$s și %2$s"
diff --git a/features/messages/impl/src/main/res/values-zh/translations.xml b/features/messages/impl/src/main/res/values-zh/translations.xml
new file mode 100644
index 0000000000..8e2e049453
--- /dev/null
+++ b/features/messages/impl/src/main/res/values-zh/translations.xml
@@ -0,0 +1,50 @@
+
+
+ "活动"
+ "旗帜"
+ "食物和饮料"
+ "动物和自然"
+ "物品"
+ "表情和人物"
+ "旅行和地点"
+ "符号"
+ "封禁用户"
+ "请确认是否要隐藏该用户当前和未来的所有信息"
+ "此消息将举报给您的主服务器管理员。他们无法读取任何加密消息。"
+ "举报此内容的原因"
+ "相机"
+ "拍摄照片"
+ "录制视频"
+ "附件"
+ "照片和视频库"
+ "位置"
+ "投票"
+ "文本格式化"
+ "消息历史记录当前不可用。"
+ "此聊天室无法查看消息历史记录。请验证此设备以查看之。"
+ "您想邀请他们回来吗?"
+ "聊天中只有你一个人"
+ "通知整个房间"
+ "所有人"
+ "重新发送"
+ "消息发送失败"
+ "添加表情符号"
+ "这是 %1$s 聊天室的开始。"
+ "这是本对话的开始。"
+ "折叠"
+ "消息已复制"
+ "您无权在此房间发言"
+ "折叠"
+ "展开"
+ "新消息"
+
+ - "%1$d 聊天室变更"
+
+
+ - "%1$s,%2$s 和其他 %3$d 个人"
+
+
+ - "%1$s 正在输入"
+
+ "%1$s 和 %2$s"
+
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 3adc7059b0..14eb3616ad 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
@@ -69,12 +69,14 @@ import io.element.android.libraries.matrix.api.room.MatrixRoom
import io.element.android.libraries.matrix.api.room.MatrixRoomMembersState
import io.element.android.libraries.matrix.api.room.MessageEventType
import io.element.android.libraries.matrix.api.room.RoomMembershipState
+import io.element.android.libraries.matrix.api.timeline.item.event.LocalEventSendState
import io.element.android.libraries.matrix.api.user.CurrentSessionIdHolder
import io.element.android.libraries.matrix.test.AN_AVATAR_URL
import io.element.android.libraries.matrix.test.AN_EVENT_ID
import io.element.android.libraries.matrix.test.A_ROOM_ID
import io.element.android.libraries.matrix.test.A_SESSION_ID
import io.element.android.libraries.matrix.test.A_SESSION_ID_2
+import io.element.android.libraries.matrix.test.A_TRANSACTION_ID
import io.element.android.libraries.matrix.test.FakeMatrixClient
import io.element.android.libraries.matrix.test.core.aBuildMeta
import io.element.android.libraries.matrix.test.permalink.FakePermalinkBuilder
@@ -456,6 +458,31 @@ class MessagesPresenterTest {
}
}
+ @Test
+ fun `present - handle action redact message in error, in this case the message is just cancelled`() = runTest {
+ val coroutineDispatchers = testCoroutineDispatchers(useUnconfinedTestDispatcher = true)
+ val matrixRoom = FakeMatrixRoom()
+ val presenter = createMessagesPresenter(matrixRoom = matrixRoom, coroutineDispatchers = coroutineDispatchers)
+ moleculeFlow(RecompositionMode.Immediate) {
+ presenter.present()
+ }.test {
+ skipItems(1)
+ val initialState = awaitItem()
+ initialState.eventSink.invoke(
+ MessagesEvents.HandleAction(
+ action = TimelineItemAction.Redact,
+ event = aMessageEvent(
+ transactionId = A_TRANSACTION_ID,
+ sendState = LocalEventSendState.SendingFailed("Failed to send message")
+ )
+ )
+ )
+ assertThat(matrixRoom.cancelSendCount).isEqualTo(1)
+ assertThat(matrixRoom.redactEventEventIdParam).isNull()
+ assertThat(awaitItem().actionListState.target).isEqualTo(ActionListState.Target.None)
+ }
+ }
+
@Test
fun `present - handle action report content`() = runTest {
val navigator = FakeMessagesNavigator()
@@ -511,7 +538,7 @@ class MessagesPresenterTest {
// Initially the composer doesn't have focus, so we don't show the alert
assertThat(initialState.showReinvitePrompt).isFalse()
// When the input field is focused we show the alert
- initialState.composerState.richTextEditorState.requestFocus()
+ initialState.composerState.textEditorState.requestFocus()
val focusedState = consumeItemsUntilPredicate(timeout = 250.milliseconds) { state ->
state.showReinvitePrompt
}.last()
@@ -534,7 +561,7 @@ class MessagesPresenterTest {
}.test {
val initialState = awaitFirstItem()
assertThat(initialState.showReinvitePrompt).isFalse()
- initialState.composerState.richTextEditorState.requestFocus()
+ initialState.composerState.textEditorState.requestFocus()
val focusedState = awaitItem()
assertThat(focusedState.showReinvitePrompt).isFalse()
}
@@ -549,7 +576,7 @@ class MessagesPresenterTest {
}.test {
val initialState = awaitFirstItem()
assertThat(initialState.showReinvitePrompt).isFalse()
- initialState.composerState.richTextEditorState.requestFocus()
+ initialState.composerState.textEditorState.requestFocus()
val focusedState = awaitItem()
assertThat(focusedState.showReinvitePrompt).isFalse()
}
@@ -754,7 +781,7 @@ class MessagesPresenterTest {
): MessagesPresenter {
val mediaSender = MediaSender(FakeMediaPreProcessor(), matrixRoom)
val permissionsPresenterFactory = FakePermissionsPresenterFactory(permissionsPresenter)
- val appPreferencesStore = InMemoryAppPreferencesStore(isRichTextEditorEnabled = true)
+ val appPreferencesStore = InMemoryAppPreferencesStore()
val sessionPreferencesStore = InMemorySessionPreferencesStore()
val messageComposerPresenter = MessageComposerPresenter(
appCoroutineScope = this,
@@ -773,7 +800,10 @@ class MessagesPresenterTest {
permalinkParser = FakePermalinkParser(),
permalinkBuilder = FakePermalinkBuilder(),
timelineController = TimelineController(matrixRoom),
- )
+ ).apply {
+ showTextFormatting = true
+ isTesting = true
+ }
val voiceMessageComposerPresenter = VoiceMessageComposerPresenter(
this,
FakeVoiceRecorder(),
@@ -826,7 +856,6 @@ class MessagesPresenterTest {
messageSummaryFormatter = FakeMessageSummaryFormatter(),
navigator = navigator,
clipboardHelper = clipboardHelper,
- appPreferencesStore = appPreferencesStore,
featureFlagsService = FakeFeatureFlagService(),
buildMeta = aBuildMeta(),
dispatchers = coroutineDispatchers,
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 b959ff151f..b6a605bdbf 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
@@ -28,6 +28,7 @@ import io.element.android.features.messages.impl.timeline.model.event.TimelineIt
import io.element.android.libraries.designsystem.components.avatar.AvatarData
import io.element.android.libraries.designsystem.components.avatar.AvatarSize
import io.element.android.libraries.matrix.api.core.EventId
+import io.element.android.libraries.matrix.api.core.TransactionId
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.test.AN_EVENT_ID
@@ -38,6 +39,7 @@ import kotlinx.collections.immutable.toImmutableList
internal fun aMessageEvent(
eventId: EventId? = AN_EVENT_ID,
+ transactionId: TransactionId? = null,
isMine: Boolean = true,
isEditable: Boolean = true,
content: TimelineItemEventContent = TimelineItemTextContent(body = A_MESSAGE, htmlDocument = null, formattedBody = null, isEdited = false),
@@ -48,6 +50,7 @@ internal fun aMessageEvent(
) = TimelineItem.Event(
id = eventId?.value.orEmpty(),
eventId = eventId,
+ transactionId = transactionId,
senderId = A_USER_ID,
senderProfile = aProfileTimelineDetailsReady(displayName = A_USER_NAME),
senderAvatar = AvatarData(A_USER_ID.value, A_USER_NAME, size = AvatarSize.TimelineSender),
diff --git a/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/textcomposer/MessageComposerPresenterTest.kt b/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/textcomposer/MessageComposerPresenterTest.kt
index 7274027059..f0bf4c42ef 100644
--- a/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/textcomposer/MessageComposerPresenterTest.kt
+++ b/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/textcomposer/MessageComposerPresenterTest.kt
@@ -26,7 +26,6 @@ import app.cash.turbine.ReceiveTurbine
import app.cash.turbine.test
import com.google.common.truth.Truth.assertThat
import im.vector.app.features.analytics.plan.Composer
-import io.element.android.features.messages.impl.mentions.MentionSuggestion
import io.element.android.features.messages.impl.messagecomposer.AttachmentsState
import io.element.android.features.messages.impl.messagecomposer.MessageComposerContextImpl
import io.element.android.features.messages.impl.messagecomposer.MessageComposerEvents
@@ -77,10 +76,11 @@ import io.element.android.libraries.permissions.api.PermissionsPresenter
import io.element.android.libraries.permissions.test.FakePermissionsPresenter
import io.element.android.libraries.permissions.test.FakePermissionsPresenterFactory
import io.element.android.libraries.preferences.test.InMemorySessionPreferencesStore
-import io.element.android.libraries.textcomposer.model.Message
+import io.element.android.libraries.textcomposer.mentions.ResolvedMentionSuggestion
import io.element.android.libraries.textcomposer.model.MessageComposerMode
import io.element.android.libraries.textcomposer.model.Suggestion
import io.element.android.libraries.textcomposer.model.SuggestionType
+import io.element.android.libraries.textcomposer.model.TextEditorState
import io.element.android.services.analytics.test.FakeAnalyticsService
import io.element.android.tests.testutils.WarmUpRule
import io.element.android.tests.testutils.lambda.any
@@ -127,7 +127,7 @@ class MessageComposerPresenterTest {
}.test {
val initialState = awaitFirstItem()
assertThat(initialState.isFullScreen).isFalse()
- assertThat(initialState.richTextEditorState.messageHtml).isEqualTo("")
+ assertThat(initialState.textEditorState.messageHtml()).isEqualTo("")
assertThat(initialState.mode).isEqualTo(MessageComposerMode.Normal)
assertThat(initialState.showAttachmentSourcePicker).isFalse()
assertThat(initialState.canShareLocation).isTrue()
@@ -158,10 +158,10 @@ class MessageComposerPresenterTest {
presenter.present()
}.test {
val initialState = awaitFirstItem()
- initialState.richTextEditorState.setHtml(A_MESSAGE)
- assertThat(initialState.richTextEditorState.messageHtml).isEqualTo(A_MESSAGE)
- initialState.richTextEditorState.setHtml("")
- assertThat(initialState.richTextEditorState.messageHtml).isEqualTo("")
+ initialState.textEditorState.setHtml(A_MESSAGE)
+ assertThat(initialState.textEditorState.messageHtml()).isEqualTo(A_MESSAGE)
+ initialState.textEditorState.setHtml("")
+ assertThat(initialState.textEditorState.messageHtml()).isEqualTo("")
}
}
@@ -170,7 +170,7 @@ class MessageComposerPresenterTest {
val presenter = createPresenter(this)
moleculeFlow(RecompositionMode.Immediate) {
val state = presenter.present()
- remember(state, state.richTextEditorState.messageHtml) { state }
+ remember(state, state.textEditorState.messageHtml()) { state }
}.test {
var state = awaitFirstItem()
val mode = anEditMode()
@@ -178,11 +178,11 @@ class MessageComposerPresenterTest {
state = awaitItem()
assertThat(state.mode).isEqualTo(mode)
state = awaitItem()
- assertThat(state.richTextEditorState.messageHtml).isEqualTo(A_MESSAGE)
+ assertThat(state.textEditorState.messageHtml()).isEqualTo(A_MESSAGE)
state = backToNormalMode(state, skipCount = 1)
// The message that was being edited is cleared
- assertThat(state.richTextEditorState.messageHtml).isEqualTo("")
+ assertThat(state.textEditorState.messageHtml()).isEqualTo("")
}
}
@@ -197,7 +197,7 @@ class MessageComposerPresenterTest {
state.eventSink.invoke(MessageComposerEvents.SetMode(mode))
state = awaitItem()
assertThat(state.mode).isEqualTo(mode)
- assertThat(state.richTextEditorState.messageHtml).isEqualTo("")
+ assertThat(state.textEditorState.messageHtml()).isEqualTo("")
backToNormalMode(state)
}
}
@@ -213,11 +213,11 @@ class MessageComposerPresenterTest {
state.eventSink.invoke(MessageComposerEvents.SetMode(mode))
state = awaitItem()
assertThat(state.mode).isEqualTo(mode)
- state.richTextEditorState.setHtml(A_REPLY)
+ state.textEditorState.setHtml(A_REPLY)
state = backToNormalMode(state)
// The message typed while replying is not cleared
- assertThat(state.richTextEditorState.messageHtml).isEqualTo(A_REPLY)
+ assertThat(state.textEditorState.messageHtml()).isEqualTo(A_REPLY)
}
}
@@ -232,25 +232,54 @@ class MessageComposerPresenterTest {
state.eventSink.invoke(MessageComposerEvents.SetMode(mode))
state = awaitItem()
assertThat(state.mode).isEqualTo(mode)
- assertThat(state.richTextEditorState.messageHtml).isEqualTo("")
+ assertThat(state.textEditorState.messageHtml()).isEqualTo("")
backToNormalMode(state)
}
}
@Test
- fun `present - send message`() = runTest {
+ fun `present - send message with rich text enabled`() = runTest {
val presenter = createPresenter(this)
moleculeFlow(RecompositionMode.Immediate) {
val state = presenter.present()
- remember(state, state.richTextEditorState.messageHtml) { state }
+ remember(state, state.textEditorState.messageHtml()) { state }
}.test {
val initialState = awaitFirstItem()
- initialState.richTextEditorState.setHtml(A_MESSAGE)
+ initialState.textEditorState.setHtml(A_MESSAGE)
val withMessageState = awaitItem()
- assertThat(withMessageState.richTextEditorState.messageHtml).isEqualTo(A_MESSAGE)
- withMessageState.eventSink.invoke(MessageComposerEvents.SendMessage(A_MESSAGE.toMessage()))
+ assertThat(withMessageState.textEditorState.messageHtml()).isEqualTo(A_MESSAGE)
+ withMessageState.eventSink.invoke(MessageComposerEvents.SendMessage)
val messageSentState = awaitItem()
- assertThat(messageSentState.richTextEditorState.messageHtml).isEqualTo("")
+ assertThat(messageSentState.textEditorState.messageHtml()).isEqualTo("")
+ waitForPredicate { analyticsService.capturedEvents.size == 1 }
+ assertThat(analyticsService.capturedEvents).containsExactly(
+ Composer(
+ inThread = false,
+ isEditing = false,
+ isReply = false,
+ messageType = Composer.MessageType.Text,
+ )
+ )
+ }
+ }
+
+ @Test
+ fun `present - send message with plain text enabled`() = runTest {
+ val permalinkBuilder = FakePermalinkBuilder(result = { Result.success("") })
+ val presenter = createPresenter(this, isRichTextEditorEnabled = false)
+ moleculeFlow(RecompositionMode.Immediate) {
+ val state = presenter.present()
+ val messageMarkdown = state.textEditorState.messageMarkdown(permalinkBuilder)
+ remember(state, messageMarkdown) { state }
+ }.test {
+ val initialState = awaitFirstItem()
+ initialState.textEditorState.setMarkdown(A_MESSAGE)
+ val withMessageState = awaitItem()
+ assertThat(withMessageState.textEditorState.messageMarkdown(permalinkBuilder)).isEqualTo(A_MESSAGE)
+ assertThat(withMessageState.textEditorState.messageHtml()).isNull()
+ withMessageState.eventSink.invoke(MessageComposerEvents.SendMessage)
+ val messageSentState = awaitItem()
+ assertThat(messageSentState.textEditorState.messageMarkdown(permalinkBuilder)).isEqualTo("")
waitForPredicate { analyticsService.capturedEvents.size == 1 }
assertThat(analyticsService.capturedEvents).containsExactly(
Composer(
@@ -278,23 +307,23 @@ class MessageComposerPresenterTest {
)
moleculeFlow(RecompositionMode.Immediate) {
val state = presenter.present()
- remember(state, state.richTextEditorState.messageHtml) { state }
+ remember(state, state.textEditorState.messageHtml()) { state }
}.test {
val initialState = awaitFirstItem()
- assertThat(initialState.richTextEditorState.messageHtml).isEqualTo("")
+ assertThat(initialState.textEditorState.messageHtml()).isEqualTo("")
val mode = anEditMode()
initialState.eventSink.invoke(MessageComposerEvents.SetMode(mode))
skipItems(1)
val withMessageState = awaitItem()
assertThat(withMessageState.mode).isEqualTo(mode)
- assertThat(withMessageState.richTextEditorState.messageHtml).isEqualTo(A_MESSAGE)
- withMessageState.richTextEditorState.setHtml(ANOTHER_MESSAGE)
+ assertThat(withMessageState.textEditorState.messageHtml()).isEqualTo(A_MESSAGE)
+ withMessageState.textEditorState.setHtml(ANOTHER_MESSAGE)
val withEditedMessageState = awaitItem()
- assertThat(withEditedMessageState.richTextEditorState.messageHtml).isEqualTo(ANOTHER_MESSAGE)
- withEditedMessageState.eventSink.invoke(MessageComposerEvents.SendMessage(ANOTHER_MESSAGE.toMessage()))
+ assertThat(withEditedMessageState.textEditorState.messageHtml()).isEqualTo(ANOTHER_MESSAGE)
+ withEditedMessageState.eventSink.invoke(MessageComposerEvents.SendMessage)
skipItems(1)
val messageSentState = awaitItem()
- assertThat(messageSentState.richTextEditorState.messageHtml).isEqualTo("")
+ assertThat(messageSentState.textEditorState.messageHtml()).isEqualTo("")
advanceUntilIdle()
@@ -328,23 +357,23 @@ class MessageComposerPresenterTest {
)
moleculeFlow(RecompositionMode.Immediate) {
val state = presenter.present()
- remember(state, state.richTextEditorState.messageHtml) { state }
+ remember(state, state.textEditorState.messageHtml()) { state }
}.test {
val initialState = awaitFirstItem()
- assertThat(initialState.richTextEditorState.messageHtml).isEqualTo("")
+ assertThat(initialState.textEditorState.messageHtml()).isEqualTo("")
val mode = anEditMode(eventId = null, transactionId = A_TRANSACTION_ID)
initialState.eventSink.invoke(MessageComposerEvents.SetMode(mode))
skipItems(1)
val withMessageState = awaitItem()
assertThat(withMessageState.mode).isEqualTo(mode)
- assertThat(withMessageState.richTextEditorState.messageHtml).isEqualTo(A_MESSAGE)
- withMessageState.richTextEditorState.setHtml(ANOTHER_MESSAGE)
+ assertThat(withMessageState.textEditorState.messageHtml()).isEqualTo(A_MESSAGE)
+ withMessageState.textEditorState.setHtml(ANOTHER_MESSAGE)
val withEditedMessageState = awaitItem()
- assertThat(withEditedMessageState.richTextEditorState.messageHtml).isEqualTo(ANOTHER_MESSAGE)
- withEditedMessageState.eventSink.invoke(MessageComposerEvents.SendMessage(ANOTHER_MESSAGE.toMessage()))
+ assertThat(withEditedMessageState.textEditorState.messageHtml()).isEqualTo(ANOTHER_MESSAGE)
+ withEditedMessageState.eventSink.invoke(MessageComposerEvents.SendMessage)
skipItems(1)
val messageSentState = awaitItem()
- assertThat(messageSentState.richTextEditorState.messageHtml).isEqualTo("")
+ assertThat(messageSentState.textEditorState.messageHtml()).isEqualTo("")
advanceUntilIdle()
@@ -380,17 +409,17 @@ class MessageComposerPresenterTest {
presenter.present()
}.test {
val initialState = awaitFirstItem()
- assertThat(initialState.richTextEditorState.messageHtml).isEqualTo("")
+ assertThat(initialState.textEditorState.messageHtml()).isEqualTo("")
val mode = aReplyMode()
initialState.eventSink.invoke(MessageComposerEvents.SetMode(mode))
val state = awaitItem()
assertThat(state.mode).isEqualTo(mode)
- assertThat(state.richTextEditorState.messageHtml).isEqualTo("")
- state.richTextEditorState.setHtml(A_REPLY)
- assertThat(state.richTextEditorState.messageHtml).isEqualTo(A_REPLY)
- state.eventSink.invoke(MessageComposerEvents.SendMessage(A_REPLY.toMessage()))
+ assertThat(state.textEditorState.messageHtml()).isEqualTo("")
+ state.textEditorState.setHtml(A_REPLY)
+ assertThat(state.textEditorState.messageHtml()).isEqualTo(A_REPLY)
+ state.eventSink.invoke(MessageComposerEvents.SendMessage)
val messageSentState = awaitItem()
- assertThat(messageSentState.richTextEditorState.messageHtml).isEqualTo("")
+ assertThat(messageSentState.textEditorState.messageHtml()).isEqualTo("")
advanceUntilIdle()
@@ -725,7 +754,7 @@ class MessageComposerPresenterTest {
@Test
fun `present - ToggleTextFormatting toggles text formatting`() = runTest {
- val presenter = createPresenter(this)
+ val presenter = createPresenter(this, isRichTextEditorEnabled = false)
moleculeFlow(RecompositionMode.Immediate) {
presenter.present()
}.test {
@@ -735,11 +764,12 @@ class MessageComposerPresenterTest {
val composerOptions = awaitItem()
assertThat(composerOptions.showAttachmentSourcePicker).isTrue()
composerOptions.eventSink(MessageComposerEvents.ToggleTextFormatting(true))
- awaitItem() // composer options closed
+ skipItems(2) // composer options closed
val showTextFormatting = awaitItem()
assertThat(showTextFormatting.showAttachmentSourcePicker).isFalse()
assertThat(showTextFormatting.showTextFormatting).isTrue()
showTextFormatting.eventSink(MessageComposerEvents.ToggleTextFormatting(false))
+ skipItems(1)
val finished = awaitItem()
assertThat(finished.showTextFormatting).isFalse()
}
@@ -781,19 +811,19 @@ class MessageComposerPresenterTest {
// An empty suggestion returns the room and joined members that are not the current user
initialState.eventSink(MessageComposerEvents.SuggestionReceived(Suggestion(0, 0, SuggestionType.Mention, "")))
assertThat(awaitItem().memberSuggestions)
- .containsExactly(MentionSuggestion.Room, MentionSuggestion.Member(bob), MentionSuggestion.Member(david))
+ .containsExactly(ResolvedMentionSuggestion.AtRoom, ResolvedMentionSuggestion.Member(bob), ResolvedMentionSuggestion.Member(david))
// A suggestion containing a part of "room" will also return the room mention
initialState.eventSink(MessageComposerEvents.SuggestionReceived(Suggestion(0, 0, SuggestionType.Mention, "roo")))
- assertThat(awaitItem().memberSuggestions).containsExactly(MentionSuggestion.Room)
+ assertThat(awaitItem().memberSuggestions).containsExactly(ResolvedMentionSuggestion.AtRoom)
// A non-empty suggestion will return those joined members whose user id matches it
initialState.eventSink(MessageComposerEvents.SuggestionReceived(Suggestion(0, 0, SuggestionType.Mention, "bob")))
- assertThat(awaitItem().memberSuggestions).containsExactly(MentionSuggestion.Member(bob))
+ assertThat(awaitItem().memberSuggestions).containsExactly(ResolvedMentionSuggestion.Member(bob))
// A non-empty suggestion will return those joined members whose display name matches it
initialState.eventSink(MessageComposerEvents.SuggestionReceived(Suggestion(0, 0, SuggestionType.Mention, "dave")))
- assertThat(awaitItem().memberSuggestions).containsExactly(MentionSuggestion.Member(david))
+ assertThat(awaitItem().memberSuggestions).containsExactly(ResolvedMentionSuggestion.Member(david))
// If the suggestion isn't a mention, no suggestions are returned
initialState.eventSink(MessageComposerEvents.SuggestionReceived(Suggestion(0, 0, SuggestionType.Command, "")))
@@ -803,7 +833,7 @@ class MessageComposerPresenterTest {
room.givenCanTriggerRoomNotification(Result.success(false))
initialState.eventSink(MessageComposerEvents.SuggestionReceived(Suggestion(0, 0, SuggestionType.Mention, "")))
assertThat(awaitItem().memberSuggestions)
- .containsExactly(MentionSuggestion.Member(bob), MentionSuggestion.Member(david))
+ .containsExactly(ResolvedMentionSuggestion.Member(bob), ResolvedMentionSuggestion.Member(david))
// If room is a DM, `RoomMemberSuggestion.Room` is not returned
room.givenCanTriggerRoomNotification(Result.success(true))
@@ -844,7 +874,7 @@ class MessageComposerPresenterTest {
initialState.eventSink(MessageComposerEvents.SuggestionReceived(Suggestion(0, 0, SuggestionType.Mention, "")))
skipItems(1)
assertThat(awaitItem().memberSuggestions)
- .containsExactly(MentionSuggestion.Member(bob), MentionSuggestion.Member(david))
+ .containsExactly(ResolvedMentionSuggestion.Member(bob), ResolvedMentionSuggestion.Member(david))
}
}
@@ -862,10 +892,10 @@ class MessageComposerPresenterTest {
presenter.present()
}.test {
val initialState = awaitFirstItem()
- initialState.richTextEditorState.setHtml("Hey @bo")
- initialState.eventSink(MessageComposerEvents.InsertMention(MentionSuggestion.Member(aRoomMember(userId = A_USER_ID_2))))
+ initialState.textEditorState.setHtml("Hey @bo")
+ initialState.eventSink(MessageComposerEvents.InsertMention(ResolvedMentionSuggestion.Member(aRoomMember(userId = A_USER_ID_2))))
- assertThat(initialState.richTextEditorState.messageHtml)
+ assertThat(initialState.textEditorState.messageHtml())
.isEqualTo("Hey ${A_USER_ID_2.value}")
}
}
@@ -892,14 +922,14 @@ class MessageComposerPresenterTest {
// Check intentional mentions on message sent
val mentionUser1 = listOf(A_USER_ID.value)
- initialState.richTextEditorState.mentionsState = MentionsState(
+ (initialState.textEditorState as? TextEditorState.Rich)?.richTextEditorState?.mentionsState = MentionsState(
userIds = mentionUser1,
roomIds = emptyList(),
roomAliases = emptyList(),
hasAtRoomMention = false
)
- initialState.richTextEditorState.setHtml(A_MESSAGE)
- initialState.eventSink(MessageComposerEvents.SendMessage(A_MESSAGE.toMessage()))
+ initialState.textEditorState.setHtml(A_MESSAGE)
+ initialState.eventSink(MessageComposerEvents.SendMessage)
advanceUntilIdle()
@@ -908,14 +938,14 @@ class MessageComposerPresenterTest {
// Check intentional mentions on reply sent
initialState.eventSink(MessageComposerEvents.SetMode(aReplyMode()))
val mentionUser2 = listOf(A_USER_ID_2.value)
- awaitItem().richTextEditorState.mentionsState = MentionsState(
+ (awaitItem().textEditorState as? TextEditorState.Rich)?.richTextEditorState?.mentionsState = MentionsState(
userIds = mentionUser2,
roomIds = emptyList(),
roomAliases = emptyList(),
hasAtRoomMention = false
)
- initialState.eventSink(MessageComposerEvents.SendMessage(A_MESSAGE.toMessage()))
+ initialState.eventSink(MessageComposerEvents.SendMessage)
advanceUntilIdle()
assert(replyMessageLambda)
@@ -926,14 +956,14 @@ class MessageComposerPresenterTest {
skipItems(1)
initialState.eventSink(MessageComposerEvents.SetMode(anEditMode()))
val mentionUser3 = listOf(A_USER_ID_3.value)
- awaitItem().richTextEditorState.mentionsState = MentionsState(
+ (awaitItem().textEditorState as? TextEditorState.Rich)?.richTextEditorState?.mentionsState = MentionsState(
userIds = mentionUser3,
roomIds = emptyList(),
roomAliases = emptyList(),
hasAtRoomMention = false
)
- initialState.eventSink(MessageComposerEvents.SendMessage(A_MESSAGE.toMessage()))
+ initialState.eventSink(MessageComposerEvents.SendMessage)
advanceUntilIdle()
assert(editMessageLambda)
@@ -949,7 +979,7 @@ class MessageComposerPresenterTest {
val presenter = createPresenter(this)
moleculeFlow(RecompositionMode.Immediate) {
val state = presenter.present()
- remember(state, state.richTextEditorState.messageHtml) { state }
+ remember(state, state.textEditorState.messageHtml()) { state }
}.test {
val initialState = awaitFirstItem()
initialState.eventSink.invoke(MessageComposerEvents.SendUri(Uri.parse("content://uri")))
@@ -1007,7 +1037,8 @@ class MessageComposerPresenterTest {
mediaPreProcessor: MediaPreProcessor = this.mediaPreProcessor,
snackbarDispatcher: SnackbarDispatcher = this.snackbarDispatcher,
permissionPresenter: PermissionsPresenter = FakePermissionsPresenter(),
- permalinkBuilder: PermalinkBuilder = FakePermalinkBuilder()
+ permalinkBuilder: PermalinkBuilder = FakePermalinkBuilder(),
+ isRichTextEditorEnabled: Boolean = true,
) = MessageComposerPresenter(
coroutineScope,
room,
@@ -1025,7 +1056,10 @@ class MessageComposerPresenterTest {
permalinkParser = FakePermalinkParser(),
permalinkBuilder = permalinkBuilder,
timelineController = TimelineController(room),
- )
+ ).apply {
+ isTesting = true
+ showTextFormatting = isRichTextEditorEnabled
+ }
private suspend fun ReceiveTurbine.awaitFirstItem(): T {
// Skip 2 item if Mentions feature is enabled, else 1
@@ -1043,7 +1077,10 @@ fun anEditMode(
fun aReplyMode() = MessageComposerMode.Reply(A_USER_NAME, null, false, AN_EVENT_ID, A_MESSAGE)
fun aQuoteMode() = MessageComposerMode.Quote(AN_EVENT_ID, A_MESSAGE)
-private fun String.toMessage() = Message(
- html = this,
- markdown = this,
-)
+private suspend fun TextEditorState.setHtml(html: String) {
+ (this as? TextEditorState.Rich)?.richTextEditorState?.setHtml(html) ?: error("TextEditorState is not Rich")
+}
+
+private fun TextEditorState.setMarkdown(markdown: String) {
+ (this as? TextEditorState.Markdown)?.state?.text?.update(markdown, needsDisplaying = false) ?: error("TextEditorState is not Markdown")
+}
diff --git a/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/textcomposer/TestRichTextEditorStateFactory.kt b/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/textcomposer/TestRichTextEditorStateFactory.kt
index 17e1c65daf..921a7331fd 100644
--- a/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/textcomposer/TestRichTextEditorStateFactory.kt
+++ b/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/textcomposer/TestRichTextEditorStateFactory.kt
@@ -23,7 +23,7 @@ import io.element.android.wysiwyg.compose.rememberRichTextEditorState
class TestRichTextEditorStateFactory : RichTextEditorStateFactory {
@Composable
- override fun create(): RichTextEditorState {
+ override fun remember(): RichTextEditorState {
return rememberRichTextEditorState("", fake = true)
}
}
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 35de78f65b..6d8fb1ad9a 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
@@ -16,7 +16,9 @@
package io.element.android.features.messages.impl.timeline.factories.event
+import android.net.Uri
import android.text.SpannableString
+import android.text.SpannableStringBuilder
import android.text.Spanned
import android.text.style.URLSpan
import androidx.core.text.buildSpannedString
@@ -46,6 +48,7 @@ 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.media.ThumbnailInfo
import io.element.android.libraries.matrix.api.media.VideoInfo
+import io.element.android.libraries.matrix.api.permalink.PermalinkData
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.FileMessageType
@@ -75,6 +78,7 @@ import org.robolectric.RobolectricTestRunner
import kotlin.time.Duration
import kotlin.time.Duration.Companion.minutes
+@Suppress("LargeClass")
@RunWith(RobolectricTestRunner::class)
class TimelineItemContentMessageFactoryTest {
@Test
@@ -641,6 +645,31 @@ class TimelineItemContentMessageFactoryTest {
assertThat((result as TimelineItemEmoteContent).formattedBody).isEqualTo(SpannableString("* Bob formatted"))
}
+ @Test
+ fun `a message with existing URLSpans keeps it after linkification`() = runTest {
+ val expectedSpanned = SpannableStringBuilder().apply {
+ append("Test ")
+ inSpans(URLSpan("https://www.example.org")) {
+ append("me@matrix.org")
+ }
+ }
+ val sut = createTimelineItemContentMessageFactory(
+ htmlConverterTransform = { expectedSpanned },
+ permalinkParser = FakePermalinkParser { PermalinkData.FallbackLink(Uri.EMPTY) }
+ )
+ val result = sut.create(
+ content = createMessageContent(
+ type = TextMessageType(
+ body = "Test [me@matrix.org](https://www.example.org)",
+ formatted = FormattedBody(MessageFormat.HTML, "Test me@matrix.org")
+ )
+ ),
+ senderDisambiguatedDisplayName = "Bob",
+ eventId = AN_EVENT_ID,
+ )
+ assertThat((result as TimelineItemTextContent).formattedBody).isEqualTo(expectedSpanned)
+ }
+
private fun createMessageContent(
body: String = "Body",
inReplyTo: InReplyTo? = null,
@@ -660,12 +689,13 @@ class TimelineItemContentMessageFactoryTest {
private fun createTimelineItemContentMessageFactory(
featureFlagService: FeatureFlagService = FakeFeatureFlagService(),
htmlConverterTransform: (String) -> CharSequence = { it },
+ permalinkParser: FakePermalinkParser = FakePermalinkParser(),
) = TimelineItemContentMessageFactory(
fileSizeFormatter = FakeFileSizeFormatter(),
fileExtensionExtractor = FileExtensionExtractorWithoutValidation(),
featureFlagService = featureFlagService,
htmlConverterProvider = FakeHtmlConverterProvider(htmlConverterTransform),
- permalinkParser = FakePermalinkParser(),
+ permalinkParser = permalinkParser,
)
private fun createStickerContent(
diff --git a/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/timeline/model/InReplyToDetailTest.kt b/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/timeline/model/InReplyToDetailTest.kt
index d73f7246c9..b103cc8e68 100644
--- a/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/timeline/model/InReplyToDetailTest.kt
+++ b/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/timeline/model/InReplyToDetailTest.kt
@@ -58,6 +58,7 @@ class InReplyToDetailTest {
senderProfile = aProfileTimelineDetails(),
content = RoomMembershipContent(
userId = A_USER_ID,
+ userDisplayName = null,
change = MembershipChange.INVITED,
)
)
diff --git a/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/timeline/model/InReplyToMetadataKtTest.kt b/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/timeline/model/InReplyToMetadataKtTest.kt
index b56d871704..c155325444 100644
--- a/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/timeline/model/InReplyToMetadataKtTest.kt
+++ b/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/timeline/model/InReplyToMetadataKtTest.kt
@@ -380,7 +380,7 @@ class InReplyToMetadataKtTest {
fun `room membership content`() = runTest {
moleculeFlow(RecompositionMode.Immediate) {
anInReplyToDetailsReady(
- eventContent = RoomMembershipContent(A_USER_ID, null)
+ eventContent = RoomMembershipContent(A_USER_ID, null, null)
).metadata()
}.test {
awaitItem().let {
diff --git a/features/onboarding/impl/src/main/res/values-ka/translations.xml b/features/onboarding/impl/src/main/res/values-ka/translations.xml
new file mode 100644
index 0000000000..e75edfdefa
--- /dev/null
+++ b/features/onboarding/impl/src/main/res/values-ka/translations.xml
@@ -0,0 +1,9 @@
+
+
+ "ხელით შესვლა"
+ "შესვლა QR კოდით"
+ "ანგარიშის შექმნა"
+ "კეთილი იყოს თქვენი მობრძანება უსწრაფეს %1$s-ში. დამუხტულია სიჩქარისა და სიმარტივისათვის."
+ "კეთილი იყოს თქვენი მობრძანება %1$s-ში! დამუხტული სიჩქარისა და სიმარტივისთვის."
+ "იყავი შენს element-ში"
+
diff --git a/features/onboarding/impl/src/main/res/values-pt/translations.xml b/features/onboarding/impl/src/main/res/values-pt/translations.xml
new file mode 100644
index 0000000000..311343ef9f
--- /dev/null
+++ b/features/onboarding/impl/src/main/res/values-pt/translations.xml
@@ -0,0 +1,9 @@
+
+
+ "Iniciar sessão manualmente"
+ "Iniciar sessão com código QR"
+ "Criar conta"
+ "Bem-vindo(a) à %1$s mais rápida de sempre. Super rápida e simples."
+ "Bem-vindo(a) à %1$s. Revitalizado, rápido e simples."
+ "A liberdade do teu elemento"
+
diff --git a/features/onboarding/impl/src/main/res/values-zh/translations.xml b/features/onboarding/impl/src/main/res/values-zh/translations.xml
new file mode 100644
index 0000000000..f8b53c3369
--- /dev/null
+++ b/features/onboarding/impl/src/main/res/values-zh/translations.xml
@@ -0,0 +1,9 @@
+
+
+ "手动登录"
+ "使用二维码登录"
+ "创建账户"
+ "欢迎使用 %1$s,快而简约的消息应用。"
+ "欢迎使用 %1$s,速度与简洁的极致。"
+ "融入您的 Element"
+
diff --git a/features/poll/impl/src/main/res/values-ka/translations.xml b/features/poll/impl/src/main/res/values-ka/translations.xml
new file mode 100644
index 0000000000..c2417983af
--- /dev/null
+++ b/features/poll/impl/src/main/res/values-ka/translations.xml
@@ -0,0 +1,11 @@
+
+
+ "ვარიანტის დამატება"
+ "შედეგების ჩვენება მხოლოდ გამოკითხვის დასრულების შემდეგ"
+ "ხმების დამალვა"
+ "ვარიანტი %1$d"
+ "კითხვა ან თემა"
+ "რას ეხება გამოკითხვა?"
+ "გამოკითხვის შექმნა"
+ "გამოკითხვის რედაქტირება"
+
diff --git a/features/poll/impl/src/main/res/values-pt/translations.xml b/features/poll/impl/src/main/res/values-pt/translations.xml
new file mode 100644
index 0000000000..456b03b317
--- /dev/null
+++ b/features/poll/impl/src/main/res/values-pt/translations.xml
@@ -0,0 +1,19 @@
+
+
+ "Adicionar opção"
+ "Mostrar resultados só após o da sondagem"
+ "Ocultar votos"
+ "Opção %1$d"
+ "As tuas alterações não foram guardadas. Tens a certeza que queres voltar atrás?"
+ "Pergunta ou tópico"
+ "De que trata a sondagem?"
+ "Criar sondagem"
+ "Tens a certeza que queres apagar esta sondagem?"
+ "Eliminar sondagem"
+ "Editar sondagem"
+ "Não foi possível encontrar nenhuma sondagem em curso."
+ "Não foi possível encontrar nenhuma sondagem anterior."
+ "Em curso"
+ "Passado"
+ "Sondagens"
+
diff --git a/features/poll/impl/src/main/res/values-zh/translations.xml b/features/poll/impl/src/main/res/values-zh/translations.xml
new file mode 100644
index 0000000000..a951a5ebb6
--- /dev/null
+++ b/features/poll/impl/src/main/res/values-zh/translations.xml
@@ -0,0 +1,19 @@
+
+
+ "添加选项"
+ "仅在投票结束后显示结果"
+ "隐藏投票"
+ "选项 %1$d"
+ "您的更改尚未保存。确定要返回吗?"
+ "问题或话题"
+ "投票的内容是什么?"
+ "创建投票"
+ "您确定要删除此投票吗?"
+ "删除投票"
+ "编辑投票"
+ "无法找到正在进行的投票。"
+ "无法找到历史投票"
+ "正在进行"
+ "历史"
+ "投票"
+
diff --git a/features/preferences/impl/build.gradle.kts b/features/preferences/impl/build.gradle.kts
index edfb275f17..44616d0566 100644
--- a/features/preferences/impl/build.gradle.kts
+++ b/features/preferences/impl/build.gradle.kts
@@ -57,6 +57,7 @@ dependencies {
implementation(projects.libraries.mediaupload.api)
implementation(projects.libraries.permissions.api)
implementation(projects.libraries.push.api)
+ implementation(projects.libraries.pushproviders.api)
implementation(projects.features.rageshake.api)
implementation(projects.features.lockscreen.api)
implementation(projects.features.analytics.api)
@@ -90,6 +91,7 @@ dependencies {
testImplementation(projects.features.rageshake.test)
testImplementation(projects.features.rageshake.impl)
testImplementation(projects.libraries.indicator.impl)
+ testImplementation(projects.libraries.pushproviders.test)
testImplementation(projects.features.logout.impl)
testImplementation(projects.services.analytics.test)
testImplementation(projects.services.toolbox.test)
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 b93e02dd39..ac8a881348 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
@@ -212,9 +212,7 @@ class PreferencesFlowNode @AssistedInject constructor(
createNode(buildContext, listOf(inputs))
}
NavTarget.LockScreenSettings -> {
- lockScreenEntryPoint.nodeBuilder(this, buildContext)
- .target(LockScreenEntryPoint.Target.Settings)
- .build()
+ lockScreenEntryPoint.nodeBuilder(this, buildContext, LockScreenEntryPoint.Target.Settings).build()
}
NavTarget.BlockedUsers -> {
createNode(buildContext)
diff --git a/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/advanced/AdvancedSettingsEvents.kt b/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/advanced/AdvancedSettingsEvents.kt
index 8ee433f630..4ed4277599 100644
--- a/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/advanced/AdvancedSettingsEvents.kt
+++ b/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/advanced/AdvancedSettingsEvents.kt
@@ -19,10 +19,12 @@ package io.element.android.features.preferences.impl.advanced
import io.element.android.compound.theme.Theme
sealed interface AdvancedSettingsEvents {
- data class SetRichTextEditorEnabled(val enabled: Boolean) : AdvancedSettingsEvents
data class SetDeveloperModeEnabled(val enabled: Boolean) : AdvancedSettingsEvents
data class SetSharePresenceEnabled(val enabled: Boolean) : AdvancedSettingsEvents
data object ChangeTheme : AdvancedSettingsEvents
data object CancelChangeTheme : AdvancedSettingsEvents
data class SetTheme(val theme: Theme) : AdvancedSettingsEvents
+ data object ChangePushProvider : AdvancedSettingsEvents
+ data object CancelChangePushProvider : AdvancedSettingsEvents
+ data class SetPushProvider(val index: Int) : AdvancedSettingsEvents
}
diff --git a/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/advanced/AdvancedSettingsPresenter.kt b/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/advanced/AdvancedSettingsPresenter.kt
index 2f0c2b7417..21d84567e1 100644
--- a/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/advanced/AdvancedSettingsPresenter.kt
+++ b/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/advanced/AdvancedSettingsPresenter.kt
@@ -17,8 +17,10 @@
package io.element.android.features.preferences.impl.advanced
import androidx.compose.runtime.Composable
+import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
+import androidx.compose.runtime.mutableIntStateOf
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberCoroutineScope
@@ -27,20 +29,26 @@ import io.element.android.compound.theme.Theme
import io.element.android.compound.theme.mapToTheme
import io.element.android.features.preferences.api.store.AppPreferencesStore
import io.element.android.features.preferences.api.store.SessionPreferencesStore
+import io.element.android.libraries.architecture.AsyncAction
import io.element.android.libraries.architecture.Presenter
+import io.element.android.libraries.matrix.api.MatrixClient
+import io.element.android.libraries.push.api.PushService
+import io.element.android.libraries.pushproviders.api.Distributor
+import io.element.android.libraries.pushproviders.api.PushProvider
+import kotlinx.collections.immutable.toImmutableList
+import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.launch
import javax.inject.Inject
class AdvancedSettingsPresenter @Inject constructor(
private val appPreferencesStore: AppPreferencesStore,
private val sessionPreferencesStore: SessionPreferencesStore,
+ private val matrixClient: MatrixClient,
+ private val pushService: PushService,
) : Presenter {
@Composable
override fun present(): AdvancedSettingsState {
val localCoroutineScope = rememberCoroutineScope()
- val isRichTextEditorEnabled by appPreferencesStore
- .isRichTextEditorEnabledFlow()
- .collectAsState(initial = false)
val isDeveloperModeEnabled by appPreferencesStore
.isDeveloperModeEnabledFlow()
.collectAsState(initial = false)
@@ -52,11 +60,64 @@ class AdvancedSettingsPresenter @Inject constructor(
}
.collectAsState(initial = Theme.System)
var showChangeThemeDialog by remember { mutableStateOf(false) }
+
+ // List of PushProvider -> Distributor
+ val distributors = remember {
+ pushService.getAvailablePushProviders()
+ .flatMap { pushProvider ->
+ pushProvider.getDistributors().map { distributor ->
+ pushProvider to distributor
+ }
+ }
+ }
+ // List of Distributor names
+ val distributorNames = remember {
+ distributors.map { it.second.name }
+ }
+
+ var currentDistributorName by remember { mutableStateOf>(AsyncAction.Uninitialized) }
+ var refreshPushProvider by remember { mutableIntStateOf(0) }
+
+ LaunchedEffect(refreshPushProvider) {
+ val p = pushService.getCurrentPushProvider()
+ val name = p?.getCurrentDistributor(matrixClient)?.name
+ currentDistributorName = if (name != null) {
+ AsyncAction.Success(name)
+ } else {
+ AsyncAction.Failure(Exception("Failed to get current push provider"))
+ }
+ }
+
+ var showChangePushProviderDialog by remember { mutableStateOf(false) }
+
+ fun CoroutineScope.changePushProvider(
+ data: Pair?
+ ) = launch {
+ showChangePushProviderDialog = false
+ data ?: return@launch
+ // No op if the value is the same.
+ if (data.second.name == currentDistributorName.dataOrNull()) return@launch
+ currentDistributorName = AsyncAction.Loading
+ data.let { (pushProvider, distributor) ->
+ pushService.registerWith(
+ matrixClient = matrixClient,
+ pushProvider = pushProvider,
+ distributor = distributor
+ )
+ .fold(
+ {
+ currentDistributorName = AsyncAction.Success(distributor.name)
+ refreshPushProvider++
+ },
+ {
+ currentDistributorName = AsyncAction.Failure(it)
+ }
+ )
+ }
+ }
+
fun handleEvents(event: AdvancedSettingsEvents) {
when (event) {
- is AdvancedSettingsEvents.SetRichTextEditorEnabled -> localCoroutineScope.launch {
- appPreferencesStore.setRichTextEditorEnabled(event.enabled)
- }
is AdvancedSettingsEvents.SetDeveloperModeEnabled -> localCoroutineScope.launch {
appPreferencesStore.setDeveloperModeEnabled(event.enabled)
}
@@ -69,15 +130,20 @@ class AdvancedSettingsPresenter @Inject constructor(
appPreferencesStore.setTheme(event.theme.name)
showChangeThemeDialog = false
}
+ AdvancedSettingsEvents.ChangePushProvider -> showChangePushProviderDialog = true
+ AdvancedSettingsEvents.CancelChangePushProvider -> showChangePushProviderDialog = false
+ is AdvancedSettingsEvents.SetPushProvider -> localCoroutineScope.changePushProvider(distributors.getOrNull(event.index))
}
}
return AdvancedSettingsState(
- isRichTextEditorEnabled = isRichTextEditorEnabled,
isDeveloperModeEnabled = isDeveloperModeEnabled,
isSharePresenceEnabled = isSharePresenceEnabled,
theme = theme,
showChangeThemeDialog = showChangeThemeDialog,
+ currentPushDistributor = currentDistributorName,
+ availablePushDistributors = distributorNames.toImmutableList(),
+ showChangePushProviderDialog = showChangePushProviderDialog,
eventSink = { handleEvents(it) }
)
}
diff --git a/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/advanced/AdvancedSettingsState.kt b/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/advanced/AdvancedSettingsState.kt
index 469f8a630c..23de2fda13 100644
--- a/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/advanced/AdvancedSettingsState.kt
+++ b/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/advanced/AdvancedSettingsState.kt
@@ -17,12 +17,16 @@
package io.element.android.features.preferences.impl.advanced
import io.element.android.compound.theme.Theme
+import io.element.android.libraries.architecture.AsyncAction
+import kotlinx.collections.immutable.ImmutableList
data class AdvancedSettingsState(
- val isRichTextEditorEnabled: Boolean,
val isDeveloperModeEnabled: Boolean,
val isSharePresenceEnabled: Boolean,
val theme: Theme,
val showChangeThemeDialog: Boolean,
+ val currentPushDistributor: AsyncAction,
+ val availablePushDistributors: ImmutableList,
+ val showChangePushProviderDialog: Boolean,
val eventSink: (AdvancedSettingsEvents) -> Unit
)
diff --git a/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/advanced/AdvancedSettingsStateProvider.kt b/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/advanced/AdvancedSettingsStateProvider.kt
index 5e255fc091..5e6af364f2 100644
--- a/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/advanced/AdvancedSettingsStateProvider.kt
+++ b/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/advanced/AdvancedSettingsStateProvider.kt
@@ -18,28 +18,37 @@ package io.element.android.features.preferences.impl.advanced
import androidx.compose.ui.tooling.preview.PreviewParameterProvider
import io.element.android.compound.theme.Theme
+import io.element.android.libraries.architecture.AsyncAction
+import kotlinx.collections.immutable.toImmutableList
open class AdvancedSettingsStateProvider : PreviewParameterProvider {
override val values: Sequence
get() = sequenceOf(
aAdvancedSettingsState(),
- aAdvancedSettingsState(isRichTextEditorEnabled = true),
aAdvancedSettingsState(isDeveloperModeEnabled = true),
aAdvancedSettingsState(showChangeThemeDialog = true),
aAdvancedSettingsState(isSendPublicReadReceiptsEnabled = true),
+ aAdvancedSettingsState(showChangePushProviderDialog = true),
+ aAdvancedSettingsState(currentPushDistributor = AsyncAction.Loading),
+ aAdvancedSettingsState(currentPushDistributor = AsyncAction.Failure(Exception("Failed to change distributor"))),
)
}
fun aAdvancedSettingsState(
- isRichTextEditorEnabled: Boolean = false,
isDeveloperModeEnabled: Boolean = false,
isSendPublicReadReceiptsEnabled: Boolean = false,
showChangeThemeDialog: Boolean = false,
+ currentPushDistributor: AsyncAction = AsyncAction.Success("Firebase"),
+ availablePushDistributors: List = listOf("Firebase", "ntfy"),
+ showChangePushProviderDialog: Boolean = false,
+ eventSink: (AdvancedSettingsEvents) -> Unit = {},
) = AdvancedSettingsState(
- isRichTextEditorEnabled = isRichTextEditorEnabled,
isDeveloperModeEnabled = isDeveloperModeEnabled,
isSharePresenceEnabled = isSendPublicReadReceiptsEnabled,
theme = Theme.System,
showChangeThemeDialog = showChangeThemeDialog,
- eventSink = {}
+ currentPushDistributor = currentPushDistributor,
+ availablePushDistributors = availablePushDistributors.toImmutableList(),
+ showChangePushProviderDialog = showChangePushProviderDialog,
+ eventSink = eventSink
)
diff --git a/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/advanced/AdvancedSettingsView.kt b/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/advanced/AdvancedSettingsView.kt
index 9e739c3a00..9b82a87bbc 100644
--- a/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/advanced/AdvancedSettingsView.kt
+++ b/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/advanced/AdvancedSettingsView.kt
@@ -16,19 +16,24 @@
package io.element.android.features.preferences.impl.advanced
+import androidx.compose.foundation.layout.size
+import androidx.compose.foundation.progressSemantics
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.Theme
import io.element.android.compound.theme.themes
import io.element.android.features.preferences.impl.R
+import io.element.android.libraries.architecture.AsyncAction
import io.element.android.libraries.designsystem.components.dialogs.ListOption
import io.element.android.libraries.designsystem.components.dialogs.SingleSelectionDialog
import io.element.android.libraries.designsystem.components.list.ListItemContent
import io.element.android.libraries.designsystem.components.preferences.PreferencePage
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.ListItem
import io.element.android.libraries.designsystem.theme.components.Text
import io.element.android.libraries.ui.strings.CommonStrings
@@ -57,18 +62,6 @@ fun AdvancedSettingsView(
state.eventSink(AdvancedSettingsEvents.ChangeTheme)
}
)
- ListItem(
- headlineContent = {
- Text(text = stringResource(id = CommonStrings.common_rich_text_editor))
- },
- supportingContent = {
- Text(text = stringResource(id = R.string.screen_advanced_settings_rich_text_editor_description))
- },
- trailingContent = ListItemContent.Switch(
- checked = state.isRichTextEditorEnabled,
- ),
- onClick = { state.eventSink(AdvancedSettingsEvents.SetRichTextEditorEnabled(!state.isRichTextEditorEnabled)) }
- )
ListItem(
headlineContent = {
Text(text = stringResource(id = CommonStrings.action_view_source))
@@ -93,6 +86,34 @@ fun AdvancedSettingsView(
),
onClick = { state.eventSink(AdvancedSettingsEvents.SetSharePresenceEnabled(!state.isSharePresenceEnabled)) }
)
+ ListItem(
+ headlineContent = {
+ Text(text = stringResource(id = R.string.screen_advanced_settings_push_provider_android))
+ },
+ trailingContent = when (state.currentPushDistributor) {
+ AsyncAction.Uninitialized,
+ AsyncAction.Confirming,
+ AsyncAction.Loading -> ListItemContent.Custom {
+ CircularProgressIndicator(
+ modifier = Modifier
+ .progressSemantics()
+ .size(20.dp),
+ strokeWidth = 2.dp
+ )
+ }
+ is AsyncAction.Failure -> ListItemContent.Text(
+ stringResource(id = CommonStrings.common_error)
+ )
+ is AsyncAction.Success -> ListItemContent.Text(
+ state.currentPushDistributor.dataOrNull() ?: ""
+ )
+ },
+ onClick = {
+ if (state.currentPushDistributor.isReady()) {
+ state.eventSink(AdvancedSettingsEvents.ChangePushProvider)
+ }
+ }
+ )
}
if (state.showChangeThemeDialog) {
@@ -109,6 +130,22 @@ fun AdvancedSettingsView(
onDismissRequest = { state.eventSink(AdvancedSettingsEvents.CancelChangeTheme) },
)
}
+
+ if (state.showChangePushProviderDialog) {
+ SingleSelectionDialog(
+ title = stringResource(id = R.string.screen_advanced_settings_choose_distributor_dialog_title_android),
+ options = state.availablePushDistributors.map {
+ ListOption(title = it)
+ }.toImmutableList(),
+ initialSelection = state.availablePushDistributors.indexOf(state.currentPushDistributor.dataOrNull()),
+ onOptionSelected = { index ->
+ state.eventSink(
+ AdvancedSettingsEvents.SetPushProvider(index)
+ )
+ },
+ onDismissRequest = { state.eventSink(AdvancedSettingsEvents.CancelChangePushProvider) },
+ )
+ }
}
@Composable
diff --git a/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/root/PreferencesRootPresenter.kt b/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/root/PreferencesRootPresenter.kt
index 20c28427a8..86992d4ac7 100644
--- a/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/root/PreferencesRootPresenter.kt
+++ b/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/root/PreferencesRootPresenter.kt
@@ -74,7 +74,7 @@ class PreferencesRootPresenter @Inject constructor(
}
// We should display the 'complete verification' option if the current session can be verified
- val canVerifyUserSession by sessionVerificationService.canVerifySessionFlow.collectAsState(false)
+ val canVerifyUserSession by sessionVerificationService.needsSessionVerification.collectAsState(false)
val showSecureBackupIndicator by indicatorService.showSettingChatBackupIndicator()
diff --git a/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/user/editprofile/EditUserProfileState.kt b/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/user/editprofile/EditUserProfileState.kt
index c37dba8c3a..d85936d5d8 100644
--- a/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/user/editprofile/EditUserProfileState.kt
+++ b/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/user/editprofile/EditUserProfileState.kt
@@ -24,7 +24,7 @@ import io.element.android.libraries.permissions.api.PermissionsState
import kotlinx.collections.immutable.ImmutableList
data class EditUserProfileState(
- val userId: UserId?,
+ val userId: UserId,
val displayName: String,
val userAvatarUrl: Uri?,
val avatarActions: ImmutableList,
diff --git a/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/user/editprofile/EditUserProfileView.kt b/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/user/editprofile/EditUserProfileView.kt
index a0d0fcfad6..389d7c5b08 100644
--- a/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/user/editprofile/EditUserProfileView.kt
+++ b/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/user/editprofile/EditUserProfileView.kt
@@ -25,12 +25,10 @@ import androidx.compose.foundation.layout.navigationBarsPadding
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.verticalScroll
-import androidx.compose.material.ExperimentalMaterialApi
-import androidx.compose.material.ModalBottomSheetValue
-import androidx.compose.material.rememberModalBottomSheetState
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.runtime.Composable
-import androidx.compose.runtime.rememberCoroutineScope
+import androidx.compose.runtime.mutableStateOf
+import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalFocusManager
@@ -57,9 +55,8 @@ import io.element.android.libraries.matrix.ui.components.AvatarActionBottomSheet
import io.element.android.libraries.matrix.ui.components.EditableAvatarView
import io.element.android.libraries.permissions.api.PermissionsView
import io.element.android.libraries.ui.strings.CommonStrings
-import kotlinx.coroutines.launch
-@OptIn(ExperimentalMaterialApi::class, ExperimentalMaterial3Api::class)
+@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun EditUserProfileView(
state: EditUserProfileState,
@@ -67,17 +64,12 @@ fun EditUserProfileView(
onProfileEdited: () -> Unit,
modifier: Modifier = Modifier,
) {
- val coroutineScope = rememberCoroutineScope()
val focusManager = LocalFocusManager.current
- val itemActionsBottomSheetState = rememberModalBottomSheetState(
- initialValue = ModalBottomSheetValue.Hidden,
- )
+ val isAvatarActionsSheetVisible = remember { mutableStateOf(false) }
fun onAvatarClicked() {
focusManager.clearFocus()
- coroutineScope.launch {
- itemActionsBottomSheetState.show()
- }
+ isAvatarActionsSheetVisible.value = true
}
Scaffold(
@@ -114,7 +106,7 @@ fun EditUserProfileView(
) {
Spacer(modifier = Modifier.height(24.dp))
EditableAvatarView(
- userId = state.userId?.value,
+ matrixId = state.userId.value,
displayName = state.displayName,
avatarUrl = state.userAvatarUrl,
avatarSize = AvatarSize.RoomHeader,
@@ -122,14 +114,12 @@ fun EditUserProfileView(
modifier = Modifier.align(Alignment.CenterHorizontally),
)
Spacer(modifier = Modifier.height(16.dp))
- state.userId?.let {
- Text(
- modifier = Modifier.fillMaxWidth(),
- text = it.value,
- style = ElementTheme.typography.fontBodyLgRegular,
- textAlign = TextAlign.Center,
- )
- }
+ Text(
+ modifier = Modifier.fillMaxWidth(),
+ text = state.userId.value,
+ style = ElementTheme.typography.fontBodyLgRegular,
+ textAlign = TextAlign.Center,
+ )
Spacer(modifier = Modifier.height(40.dp))
LabelledOutlinedTextField(
label = stringResource(R.string.screen_edit_profile_display_name),
@@ -142,7 +132,8 @@ fun EditUserProfileView(
AvatarActionBottomSheet(
actions = state.avatarActions,
- modalBottomSheetState = itemActionsBottomSheetState,
+ isVisible = isAvatarActionsSheetVisible.value,
+ onDismiss = { isAvatarActionsSheetVisible.value = false },
onActionSelected = { state.eventSink(EditUserProfileEvents.HandleAvatarAction(it)) }
)
diff --git a/features/preferences/impl/src/main/res/values-be/translations.xml b/features/preferences/impl/src/main/res/values-be/translations.xml
index 450a47ce61..33d1b2706e 100644
--- a/features/preferences/impl/src/main/res/values-be/translations.xml
+++ b/features/preferences/impl/src/main/res/values-be/translations.xml
@@ -1,10 +1,12 @@
+ "Выберыце спосаб атрымання апавяшчэнняў"
"Рэжым распрацоўшчыка"
"Падайце распрацоўнікам доступ да функцый і функцыянальным магчымасцям."
"Базавы URL сервера званкоў Element"
"Задайце свой сервер Element Call."
"Адрас пазначаны няправільна, пераканайцеся, што вы ўказалі пратакол (http/https) і правільны адрас."
+ "Пастаўшчык push-апавяшчэнняў"
"Адключыць рэдактар фарматаванага тэксту і ўключыць Markdown."
"Апавяшчэнні аб чытанні"
"Калі выключыць, вашы пасведчанні аб прачытанні нікому не будуць адпраўляцца. Вы па-ранейшаму будзеце атрымліваць пасведчанні аб прачытанні ад іншых карыстальнікаў."
diff --git a/features/preferences/impl/src/main/res/values-cs/translations.xml b/features/preferences/impl/src/main/res/values-cs/translations.xml
index 60bc4b2b3e..ba19d3541f 100644
--- a/features/preferences/impl/src/main/res/values-cs/translations.xml
+++ b/features/preferences/impl/src/main/res/values-cs/translations.xml
@@ -1,5 +1,6 @@
+ "Vyberte, jak chcete přijímat oznámení"
"Vývojářský režim"
"Povolením získáte přístup k funkcím a funkcím pro vývojáře."
"Vlastní URL pro Element Call"
diff --git a/features/preferences/impl/src/main/res/values-de/translations.xml b/features/preferences/impl/src/main/res/values-de/translations.xml
index 1faac8c4eb..3013315b21 100644
--- a/features/preferences/impl/src/main/res/values-de/translations.xml
+++ b/features/preferences/impl/src/main/res/values-de/translations.xml
@@ -1,5 +1,6 @@
+ "Wähle aus, wie du Benachrichtigungen erhalten möchtest"
"Entwickler-Modus"
"Aktivieren, um Zugriff auf Features und Funktionen für Entwickler zu aktivieren."
"Benutzerdefinierte Element-Aufruf-Basis-URL"
diff --git a/features/preferences/impl/src/main/res/values-es/translations.xml b/features/preferences/impl/src/main/res/values-es/translations.xml
index 2a6de80c05..db20929504 100644
--- a/features/preferences/impl/src/main/res/values-es/translations.xml
+++ b/features/preferences/impl/src/main/res/values-es/translations.xml
@@ -1,15 +1,22 @@
+ "Elige cómo recibir las notificaciones"
"Modo desarrollador"
"Habilita para tener acceso a características y funcionalidades para desarrolladores."
"URL base personalizada de Element Call"
"Define una URL base personalizada para Element Call."
"URL no válida, asegúrate de incluir el protocolo (http/https) y la dirección correcta."
"Desactiva el editor de texto enriquecido para escribir Markdown manualmente."
+ "Confirmaciones de lectura"
+ "Si se desactiva, las confirmaciones de lectura no se enviarán a nadie. Seguirás recibiendo confirmaciones de lectura de otros usuarios."
+ "Compartir presencia"
+ "Si se desactiva, no podrás enviar ni recibir confirmaciones de lectura ni notificaciones de escritura"
"Habilita la opción para ver el contenido en bruto del mensaje en la cronología."
+ "No tienes usuarios bloqueados"
"Desbloquear"
"Podrás ver todos sus mensajes de nuevo."
"Desbloquear usuario"
+ "Desbloqueando…"
"Nombre público"
"Tu nombre visible"
"Se encontró un error desconocido y no se pudo cambiar la información."
diff --git a/features/preferences/impl/src/main/res/values-fr/translations.xml b/features/preferences/impl/src/main/res/values-fr/translations.xml
index 9c415fea2d..14d30f16b7 100644
--- a/features/preferences/impl/src/main/res/values-fr/translations.xml
+++ b/features/preferences/impl/src/main/res/values-fr/translations.xml
@@ -1,5 +1,6 @@
+ "Choisissez le mode de réception des notifications"
"Mode développeur"
"Activer pour pouvoir accéder aux fonctionnalités destinées aux développeurs."
"URL de base pour Element Call personnalisée"
diff --git a/features/preferences/impl/src/main/res/values-hu/translations.xml b/features/preferences/impl/src/main/res/values-hu/translations.xml
index 841695edcf..964e2dc58e 100644
--- a/features/preferences/impl/src/main/res/values-hu/translations.xml
+++ b/features/preferences/impl/src/main/res/values-hu/translations.xml
@@ -1,5 +1,6 @@
+ "Válassza ki az értesítések fogadási módját"
"Fejlesztői mód"
"Engedélyezze, hogy elérje a fejlesztőknek szánt funkciókat."
"Egyéni Element Call alapwebcím"
diff --git a/features/preferences/impl/src/main/res/values-in/translations.xml b/features/preferences/impl/src/main/res/values-in/translations.xml
index 8bca603eeb..2068782846 100644
--- a/features/preferences/impl/src/main/res/values-in/translations.xml
+++ b/features/preferences/impl/src/main/res/values-in/translations.xml
@@ -1,5 +1,6 @@
+ "Pilih cara menerima notifikasi"
"Mode pengembang"
"Aktifkan untuk mengakses fitur dan fungsi untuk para pengembang."
"URL dasar Element Call khusus"
diff --git a/features/preferences/impl/src/main/res/values-it/translations.xml b/features/preferences/impl/src/main/res/values-it/translations.xml
index e15213218c..b8a483d290 100644
--- a/features/preferences/impl/src/main/res/values-it/translations.xml
+++ b/features/preferences/impl/src/main/res/values-it/translations.xml
@@ -1,5 +1,6 @@
+ "Scegli come ricevere le notifiche"
"Modalità sviluppatore"
"Attiva per avere accesso alle funzionalità per sviluppatori."
"URL base di Element Call personalizzato"
diff --git a/features/preferences/impl/src/main/res/values-ka/translations.xml b/features/preferences/impl/src/main/res/values-ka/translations.xml
new file mode 100644
index 0000000000..f27eac6d40
--- /dev/null
+++ b/features/preferences/impl/src/main/res/values-ka/translations.xml
@@ -0,0 +1,44 @@
+
+
+ "აირჩიეთ, თუ როგორ გსურთ შეტყობინებების მიღება"
+ "დეველოპერის რეჟიმი"
+ "ჩართეთ დეველოპერების ფუნქციებზე წვდომა."
+ "მორგებული Element-ის ზარის საბაზისო URL"
+ "დააყენეთ საბაზისო URL Element-ის ზარებისათვის."
+ "არასწორი URL, გთხოვთ, დარწმუნდეთ, რომ შეიტანეთ პროტოკოლი (http/https) და სწორი მისამართი."
+ "გამორთეთ მდიდარი ტექსტის რედაქტორი, რათა ხელით აკრიფოთ Markdown."
+ "განბლოკვა"
+ "თქვენ კვლავ შეძლებთ მათგან ყველა შეტყობინების ნახვას."
+ "Მომხმარებლის განბლოკვა"
+ "ნაჩვენები სახელი"
+ "თქვენი ნაჩვენები სახელი"
+ "დაფიქსირდა უცნობი შეცდომა და ინფორმაციის შეცვლა ვერ მოხერხდა."
+ "პროფილის განახლება ვერ მოხერხდა"
+ "Პროფილის რედაქტირება"
+ "პროფილის განახლება…"
+ "დამატებითი პარამეტრები"
+ "აუდიო და ვიდეო ზარები"
+ "კონფიგურაციის შეუსაბამობა"
+ "ჩვენ გავამარტივეთ შეტყობინებების პარამეტრები, რათა გაგიადვილოთ ვარიანტების პოვნა.
+
+თქვენ მიერ წარსულში არჩეული ზოგიერთი მორგებული პარამეტრი აქ არ არის ნაჩვენები, მაგრამ ისინი კვლავ აქტიურია. თუ გააგრძელებთ, თქვენი ზოგიერთი პარამეტრი შეიძლება შეიცვალოს."
+ "პირდაპირი ჩატები"
+ "მორგებული პარამეტრი ჩატზე"
+ "შეტყობინებების პარამეტრის განახლებისას მოხდა შეცდომა."
+ "ყველა შეტყობინება"
+ "მხოლოდ ხსენებები და საკვანძო სიტყვები"
+ "პირდაპირ ჩატებზე, შემატყობინეთ:"
+ "ჯგუფურ ჩატებზე, შემატყობინეთ:"
+ "შეტყობინებების ჩართვა ამ მოწყობილობაზე"
+ "კონფიგურაცია არ გამოსწორებულა, გთხოვთ, კვლავ სცადოთ."
+ "ჯგუფური ჩატები"
+ "ხსენებები"
+ "ყველა"
+ "ხსენებები"
+ "ჩემი შეტყობინება შემდეგისთვის:"
+ "ჩემი შეტყობინება @room-ზე"
+ "შეტყობინებების მისაღებად გთხოვთ შეცვალოთ %1$s."
+ "სისტემის პარამეტრები"
+ "სისტემის შეტყობინებები გამორთულია"
+ "შეტყობინებები"
+
diff --git a/features/preferences/impl/src/main/res/values-pt/translations.xml b/features/preferences/impl/src/main/res/values-pt/translations.xml
new file mode 100644
index 0000000000..8ebe95071a
--- /dev/null
+++ b/features/preferences/impl/src/main/res/values-pt/translations.xml
@@ -0,0 +1,55 @@
+
+
+ "Escolhe como receber notificações"
+ "Modo de programador"
+ "Permite o acesso a funcionalidades para programadores."
+ "URL base para Element Call personalizado"
+ "Define um URL base para a Element Call."
+ "URL inválido, certifica-te de que incluis o protocolo (http/https) e o endereço correto."
+ "Desativa o editor de texto rico para poderes escrever Markdown manualmente."
+ "Recibos de leitura"
+ "Se desativada, os teus recibos de leitura não serão enviados a ninguém. Continuas a receber recibos de leitura de outros utilizadores."
+ "Partilhar presença"
+ "Se desativado, não poderás enviar ou receber recibos de leitura ou notificações de escrita"
+ "Ativa a opção para ver a origem da mensagem na cronologia."
+ "Não tens nenhum utilizador bloqueado"
+ "Desbloquear"
+ "Poderás voltar a ver todas as suas mensagens."
+ "Desbloquear utilizador"
+ "A desbloquear…"
+ "Pseudónimo"
+ "O teu pseudónimo"
+ "Foi encontrado um erro desconhecido e a informação não foi alterada."
+ "Não foi possível atualizar o perfil"
+ "Editar perfil"
+ "A atualizar o perfil…"
+ "Configurações adicionais"
+ "Chamadas de áudio e vídeo"
+ "Incompatibilidade de configuração"
+ "Simplificámos as configurações de notificação para tornar as opções mais fáceis de encontrar. Algumas configurações personalizadas que escolheste no passado não são mostradas aqui, mas continuam ativas.
+
+Se prosseguires, algumas delas podem ser alteradas."
+ "Diretas"
+ "Configuração personalizada por conversa"
+ "Erro ao atualizar a configuração de notificação."
+ "Qualquer mensagem"
+ "Menções ou palavras-chave"
+ "Em conversas diretas, notifica-me se receber"
+ "Em conversas de grupo, notifica-me se receber"
+ "Ativar as notificações neste dispositivo"
+ "A configuração não foi corrigida, tenta novamente."
+ "De grupo"
+ "Convites"
+ "O teu servidor não suporta esta opção em salas cifradas, pelo que poderás não ser notificado em algumas salas."
+ "Menções"
+ "Tudo"
+ "Menções"
+ "Conversas"
+ "Quando aparece uma @room"
+ "Para receberes notificações, altera as tuas %1$s."
+ "configurações do sistema"
+ "Notificações do sistema desativadas"
+ "Notificações"
+ "Resolução de problemas"
+ "Resolver problemas com as notificações"
+
diff --git a/features/preferences/impl/src/main/res/values-ro/translations.xml b/features/preferences/impl/src/main/res/values-ro/translations.xml
index 75c0411aa8..b191002a32 100644
--- a/features/preferences/impl/src/main/res/values-ro/translations.xml
+++ b/features/preferences/impl/src/main/res/values-ro/translations.xml
@@ -1,5 +1,6 @@
+ "Alegeți modul de primire a notificărilor"
"Modul dezvoltator"
"Activați pentru a avea acces la funcționalități pentru dezvoltatori."
"Adresa URL de bază Element Call"
@@ -11,9 +12,11 @@
"Împărtășiți prezența"
"Dacă dezactivată, nu veți putea trimite sau primi chitanțe de citire sau notificări de tastare."
"Activați opțiunea pentru a vizualiza sursa mesajelor."
+ "Nu aveți utilizatori blocați"
"Deblocați"
"La deblocarea utilizatorului, veți putea vedea din nou toate mesajele de la acesta."
"Deblocați utilizatorul"
+ "Se deblochează…"
"Nume"
"Numele dumneavoastra"
"A fost întâlnită o eroare necunoscută și informațiile nu au putut fi modificate."
@@ -49,4 +52,6 @@ Dacă continuați, unele dintre setările dumneavoastră pot fi modificate.""Setări de sistem"
"Notificările de sistem sunt dezactivate"
"Notificări"
+ "Depanare"
+ "Depanați notificările"
diff --git a/features/preferences/impl/src/main/res/values-ru/translations.xml b/features/preferences/impl/src/main/res/values-ru/translations.xml
index 3b24cf8c80..dccf557cbf 100644
--- a/features/preferences/impl/src/main/res/values-ru/translations.xml
+++ b/features/preferences/impl/src/main/res/values-ru/translations.xml
@@ -1,5 +1,6 @@
+ "Выберите способ получения уведомлений"
"Режим разработчика"
"Предоставьте разработчикам доступ к функциям и функциональным возможностям."
"Базовый URL сервера звонков Element"
diff --git a/features/preferences/impl/src/main/res/values-sk/translations.xml b/features/preferences/impl/src/main/res/values-sk/translations.xml
index f382d0ab6f..edabc77ec5 100644
--- a/features/preferences/impl/src/main/res/values-sk/translations.xml
+++ b/features/preferences/impl/src/main/res/values-sk/translations.xml
@@ -1,10 +1,12 @@
+ "Vyberte spôsob prijímania oznámení"
"Vývojársky režim"
"Umožniť prístup k možnostiam a funkciám pre vývojárov."
"Vlastná Element Call základná URL adresa"
"Nastaviť vlastnú základnú URL adresu pre Element Call."
"Neplatná adresa URL, uistite sa, že ste uviedli protokol (http/https) a správnu adresu."
+ "Poskytovateľ oznámení Push"
"Vypnite rozšírený textový editor na ručné písanie Markdown."
"Potvrdenia o prečítaní"
"Ak je táto funkcia vypnutá, vaše potvrdenia o prečítaní sa nebudú nikomu odosielať. Stále budete dostávať potvrdenia o prečítaní od ostatných používateľov."
diff --git a/features/preferences/impl/src/main/res/values-sv/translations.xml b/features/preferences/impl/src/main/res/values-sv/translations.xml
index adcb60f9d5..02ee01532e 100644
--- a/features/preferences/impl/src/main/res/values-sv/translations.xml
+++ b/features/preferences/impl/src/main/res/values-sv/translations.xml
@@ -1,5 +1,6 @@
+ "Välj hur du vill ta emot aviseringar"
"Utvecklarläge"
"Aktivera för att ha tillgång till funktionalitet för utvecklare."
"Anpassad bas-URL för Element Call"
diff --git a/features/preferences/impl/src/main/res/values-uk/translations.xml b/features/preferences/impl/src/main/res/values-uk/translations.xml
index 33478a51fb..0fdf2a67ad 100644
--- a/features/preferences/impl/src/main/res/values-uk/translations.xml
+++ b/features/preferences/impl/src/main/res/values-uk/translations.xml
@@ -1,5 +1,6 @@
+ "Виберіть спосіб отримання сповіщень"
"Режим розробника"
"Увімкніть доступ до функцій і можливостей для розробників."
"Користувацька URL-адреса Element Call"
@@ -15,7 +16,7 @@
"Розблокувати"
"Ви знову зможете бачити всі повідомлення від них."
"Розблокувати користувача"
- "Заблокування…"
+ "Розблокування…"
"Відображуване ім\'я"
"Ваше відображуване ім\'я"
"Була виявлена невідома помилка, і інформацію не вдалося змінити."
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 68ea61f94e..000be710d7 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
@@ -1,5 +1,6 @@
+ "選擇接收通知的機制"
"開發者模式"
"分享動態"
"解除封鎖"
diff --git a/features/preferences/impl/src/main/res/values-zh/translations.xml b/features/preferences/impl/src/main/res/values-zh/translations.xml
new file mode 100644
index 0000000000..5a4485ed14
--- /dev/null
+++ b/features/preferences/impl/src/main/res/values-zh/translations.xml
@@ -0,0 +1,55 @@
+
+
+ "选择如何接收通知"
+ "开发者模式"
+ "允许开发人员访问特性和功能。"
+ "自定义 Element 通话 URL"
+ "为 Element 通话设置根 URL。"
+ "URL 无效,请确保包含协议(http/https)和正确的地址。"
+ "禁用富文本编辑器,手动输入 Markdown。"
+ "已读回执"
+ "如果关闭,您的已读回执将不会发送给别人。您仍能收到别人的已读回执。"
+ "分享在线状态"
+ "如果关闭,您将无法发送或接收已读回执、输入通知"
+ "启用在时间轴中查看消息来源的选项。"
+ "您没有屏蔽用户"
+ "解封"
+ "你可以重新接收他们的消息。"
+ "解封用户"
+ "正在解除屏蔽……"
+ "显示名称"
+ "你的显示名称"
+ "遇到未知错误,无法更改信息。"
+ "无法更新个人资料"
+ "编辑个人资料"
+ "更新个人资料……"
+ "更多设置"
+ "音视频通话"
+ "配置不匹配"
+ "我们简化了通知设置,使选项更易于查找。您过去选择的某些自定义设置未在此处显示,但它们仍然有效。
+
+如果继续,您的某些设置可能会更改。"
+ "直接聊天"
+ "各聊天室的独立设置"
+ "更新通知设置时出错。"
+ "全部消息"
+ "仅限提及和关键词"
+ "在私聊中,请通知我:"
+ "在群聊中,请通知我:"
+ "在此设备上启用通知"
+ "配置尚未更正,请重试。"
+ "群聊"
+ "邀请"
+ "您的服务器在加密房间中不支持此选项,因此在某些房间您可能无法收到通知。"
+ "提及"
+ "全部"
+ "提及"
+ "请通知我:"
+ "在 @room 通知我"
+ "要接收通知,请更改您的 %1$s。"
+ "系统设置"
+ "系统通知已关闭"
+ "通知"
+ "排查问题"
+ "排查通知问题"
+
diff --git a/features/preferences/impl/src/main/res/values/localazy.xml b/features/preferences/impl/src/main/res/values/localazy.xml
index 56a5c0ba03..d9b6b583ed 100644
--- a/features/preferences/impl/src/main/res/values/localazy.xml
+++ b/features/preferences/impl/src/main/res/values/localazy.xml
@@ -1,10 +1,12 @@
+ "Choose how to receive notifications"
"Developer mode"
"Enable to have access to features and functionality for developers."
"Custom Element Call base URL"
"Set a custom base URL for Element Call."
"Invalid URL, please make sure you include the protocol (http/https) and the correct address."
+ "Push notification provider"
"Disable the rich text editor to type Markdown manually."
"Read receipts"
"If turned off, your read receipts won\'t be sent to anyone. You will still receive read receipts from other users."
diff --git a/features/preferences/impl/src/test/kotlin/io/element/android/features/preferences/impl/advanced/AdvancedSettingsPresenterTest.kt b/features/preferences/impl/src/test/kotlin/io/element/android/features/preferences/impl/advanced/AdvancedSettingsPresenterTest.kt
index 8f6c45c51d..7e4175d3bd 100644
--- a/features/preferences/impl/src/test/kotlin/io/element/android/features/preferences/impl/advanced/AdvancedSettingsPresenterTest.kt
+++ b/features/preferences/impl/src/test/kotlin/io/element/android/features/preferences/impl/advanced/AdvancedSettingsPresenterTest.kt
@@ -21,8 +21,16 @@ import app.cash.molecule.moleculeFlow
import app.cash.turbine.test
import com.google.common.truth.Truth.assertThat
import io.element.android.compound.theme.Theme
+import io.element.android.libraries.architecture.AsyncAction
+import io.element.android.libraries.matrix.api.MatrixClient
+import io.element.android.libraries.matrix.test.FakeMatrixClient
import io.element.android.libraries.preferences.test.InMemoryAppPreferencesStore
import io.element.android.libraries.preferences.test.InMemorySessionPreferencesStore
+import io.element.android.libraries.push.api.PushService
+import io.element.android.libraries.push.test.FakePushService
+import io.element.android.libraries.pushproviders.api.Distributor
+import io.element.android.libraries.pushproviders.api.PushProvider
+import io.element.android.libraries.pushproviders.test.FakePushProvider
import io.element.android.tests.testutils.WarmUpRule
import io.element.android.tests.testutils.awaitLastSequentialItem
import kotlinx.coroutines.test.runTest
@@ -41,7 +49,6 @@ class AdvancedSettingsPresenterTest {
}.test {
val initialState = awaitLastSequentialItem()
assertThat(initialState.isDeveloperModeEnabled).isFalse()
- assertThat(initialState.isRichTextEditorEnabled).isFalse()
assertThat(initialState.showChangeThemeDialog).isFalse()
assertThat(initialState.isSharePresenceEnabled).isTrue()
assertThat(initialState.theme).isEqualTo(Theme.System)
@@ -63,21 +70,6 @@ class AdvancedSettingsPresenterTest {
}
}
- @Test
- fun `present - rich text editor on off`() = runTest {
- val presenter = createAdvancedSettingsPresenter()
- moleculeFlow(RecompositionMode.Immediate) {
- presenter.present()
- }.test {
- val initialState = awaitLastSequentialItem()
- assertThat(initialState.isRichTextEditorEnabled).isFalse()
- initialState.eventSink.invoke(AdvancedSettingsEvents.SetRichTextEditorEnabled(true))
- assertThat(awaitItem().isRichTextEditorEnabled).isTrue()
- initialState.eventSink.invoke(AdvancedSettingsEvents.SetRichTextEditorEnabled(false))
- assertThat(awaitItem().isRichTextEditorEnabled).isFalse()
- }
- }
-
@Test
fun `present - share presence off on`() = runTest {
val presenter = createAdvancedSettingsPresenter()
@@ -116,11 +108,93 @@ class AdvancedSettingsPresenterTest {
}
}
+ @Test
+ fun `present - change push provider`() = runTest {
+ val presenter = createAdvancedSettingsPresenter(
+ pushService = createFakePushService(),
+ )
+ moleculeFlow(RecompositionMode.Immediate) {
+ presenter.present()
+ }.test {
+ val initialState = awaitLastSequentialItem()
+ assertThat(initialState.currentPushDistributor).isEqualTo(AsyncAction.Success("aDistributorName0"))
+ assertThat(initialState.availablePushDistributors).containsExactly("aDistributorName0", "aDistributorName1")
+ initialState.eventSink.invoke(AdvancedSettingsEvents.ChangePushProvider)
+ val withDialog = awaitItem()
+ assertThat(withDialog.showChangePushProviderDialog).isTrue()
+ // Cancel
+ withDialog.eventSink(AdvancedSettingsEvents.CancelChangePushProvider)
+ val withoutDialog = awaitItem()
+ assertThat(withoutDialog.showChangePushProviderDialog).isFalse()
+ withDialog.eventSink.invoke(AdvancedSettingsEvents.ChangePushProvider)
+ assertThat(awaitItem().showChangePushProviderDialog).isTrue()
+ withDialog.eventSink(AdvancedSettingsEvents.SetPushProvider(1))
+ val withNewProvider = awaitItem()
+ assertThat(withNewProvider.showChangePushProviderDialog).isFalse()
+ assertThat(withNewProvider.currentPushDistributor).isEqualTo(AsyncAction.Loading)
+ val lastItem = awaitItem()
+ assertThat(lastItem.currentPushDistributor).isEqualTo(AsyncAction.Success("aDistributorName1"))
+ cancelAndIgnoreRemainingEvents()
+ }
+ }
+
+ @Test
+ fun `present - change push provider error`() = runTest {
+ val presenter = createAdvancedSettingsPresenter(
+ pushService = createFakePushService(
+ registerWithLambda = { _, _, _ ->
+ Result.failure(Exception("An error"))
+ },
+ ),
+ )
+ moleculeFlow(RecompositionMode.Immediate) {
+ presenter.present()
+ }.test {
+ val initialState = awaitLastSequentialItem()
+ initialState.eventSink.invoke(AdvancedSettingsEvents.ChangePushProvider)
+ val withDialog = awaitItem()
+ assertThat(withDialog.showChangePushProviderDialog).isTrue()
+ withDialog.eventSink(AdvancedSettingsEvents.SetPushProvider(1))
+ val withNewProvider = awaitItem()
+ assertThat(withNewProvider.showChangePushProviderDialog).isFalse()
+ assertThat(withNewProvider.currentPushDistributor).isEqualTo(AsyncAction.Loading)
+ val lastItem = awaitItem()
+ assertThat(lastItem.currentPushDistributor).isInstanceOf(AsyncAction.Failure::class.java)
+ }
+ }
+
+ private fun createFakePushService(
+ registerWithLambda: suspend (MatrixClient, PushProvider, Distributor) -> Result = { _, _, _ ->
+ Result.success(Unit)
+ }
+ ): PushService {
+ val pushProvider1 = FakePushProvider(
+ index = 0,
+ name = "aFakePushProvider0",
+ isAvailable = true,
+ distributors = listOf(Distributor("aDistributorValue0", "aDistributorName0")),
+ )
+ val pushProvider2 = FakePushProvider(
+ index = 1,
+ name = "aFakePushProvider1",
+ isAvailable = true,
+ distributors = listOf(Distributor("aDistributorValue1", "aDistributorName1")),
+ )
+ return FakePushService(
+ availablePushProviders = listOf(pushProvider1, pushProvider2),
+ registerWithLambda = registerWithLambda,
+ )
+ }
+
private fun createAdvancedSettingsPresenter(
appPreferencesStore: InMemoryAppPreferencesStore = InMemoryAppPreferencesStore(),
sessionPreferencesStore: InMemorySessionPreferencesStore = InMemorySessionPreferencesStore(),
+ matrixClient: MatrixClient = FakeMatrixClient(),
+ pushService: PushService = FakePushService(),
) = AdvancedSettingsPresenter(
appPreferencesStore = appPreferencesStore,
sessionPreferencesStore = sessionPreferencesStore,
+ matrixClient = matrixClient,
+ pushService = pushService,
)
}
diff --git a/features/preferences/impl/src/test/kotlin/io/element/android/features/preferences/impl/advanced/AdvancedSettingsViewTest.kt b/features/preferences/impl/src/test/kotlin/io/element/android/features/preferences/impl/advanced/AdvancedSettingsViewTest.kt
new file mode 100644
index 0000000000..ee8c900579
--- /dev/null
+++ b/features/preferences/impl/src/test/kotlin/io/element/android/features/preferences/impl/advanced/AdvancedSettingsViewTest.kt
@@ -0,0 +1,145 @@
+/*
+ * Copyright (c) 2024 New Vector Ltd
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package io.element.android.features.preferences.impl.advanced
+
+import androidx.activity.ComponentActivity
+import androidx.compose.ui.test.junit4.AndroidComposeTestRule
+import androidx.compose.ui.test.junit4.createAndroidComposeRule
+import androidx.compose.ui.test.onNodeWithText
+import androidx.compose.ui.test.performClick
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import io.element.android.compound.theme.Theme
+import io.element.android.features.preferences.impl.R
+import io.element.android.libraries.ui.strings.CommonStrings
+import io.element.android.tests.testutils.EnsureNeverCalled
+import io.element.android.tests.testutils.EventsRecorder
+import io.element.android.tests.testutils.clickOn
+import io.element.android.tests.testutils.ensureCalledOnce
+import io.element.android.tests.testutils.pressBack
+import org.junit.Rule
+import org.junit.Test
+import org.junit.rules.TestRule
+import org.junit.runner.RunWith
+import org.robolectric.annotation.Config
+
+@RunWith(AndroidJUnit4::class)
+class AdvancedSettingsViewTest {
+ @get:Rule
+ val rule = createAndroidComposeRule()
+
+ @Test
+ fun `clicking on back invokes the expected callback`() {
+ val eventsRecorder = EventsRecorder(expectEvents = false)
+ ensureCalledOnce {
+ rule.setAdvancedSettingsView(
+ state = aAdvancedSettingsState(
+ eventSink = eventsRecorder
+ ),
+ onBackPressed = it
+ )
+ rule.pressBack()
+ }
+ }
+
+ @Test
+ fun `clicking on Appearance emits the expected event`() {
+ val eventsRecorder = EventsRecorder()
+ rule.setAdvancedSettingsView(
+ state = aAdvancedSettingsState(
+ eventSink = eventsRecorder
+ ),
+ )
+ rule.clickOn(CommonStrings.common_appearance)
+ eventsRecorder.assertSingle(AdvancedSettingsEvents.ChangeTheme)
+ }
+
+ @Test
+ fun `clicking on other theme emits the expected event`() {
+ val eventsRecorder = EventsRecorder()
+ rule.setAdvancedSettingsView(
+ state = aAdvancedSettingsState(
+ eventSink = eventsRecorder,
+ showChangeThemeDialog = true
+ ),
+ )
+ rule.clickOn(CommonStrings.common_dark)
+ eventsRecorder.assertSingle(AdvancedSettingsEvents.SetTheme(Theme.Dark))
+ }
+
+ @Test
+ fun `clicking on View source emits the expected event`() {
+ val eventsRecorder = EventsRecorder()
+ rule.setAdvancedSettingsView(
+ state = aAdvancedSettingsState(
+ eventSink = eventsRecorder,
+ ),
+ )
+ rule.clickOn(CommonStrings.action_view_source)
+ eventsRecorder.assertSingle(AdvancedSettingsEvents.SetDeveloperModeEnabled(true))
+ }
+
+ @Test
+ fun `clicking on Share presence emits the expected event`() {
+ val eventsRecorder = EventsRecorder()
+ rule.setAdvancedSettingsView(
+ state = aAdvancedSettingsState(
+ eventSink = eventsRecorder,
+ ),
+ )
+ rule.clickOn(R.string.screen_advanced_settings_share_presence)
+ eventsRecorder.assertSingle(AdvancedSettingsEvents.SetSharePresenceEnabled(true))
+ }
+
+ @Config(qualifiers = "h1024dp")
+ @Test
+ fun `clicking on Push notification provider emits the expected event`() {
+ val eventsRecorder = EventsRecorder()
+ rule.setAdvancedSettingsView(
+ state = aAdvancedSettingsState(
+ eventSink = eventsRecorder
+ ),
+ )
+ rule.clickOn(R.string.screen_advanced_settings_push_provider_android)
+ eventsRecorder.assertSingle(AdvancedSettingsEvents.ChangePushProvider)
+ }
+
+ @Test
+ fun `clicking on a push provider emits the expected event`() {
+ val eventsRecorder = EventsRecorder()
+ rule.setAdvancedSettingsView(
+ state = aAdvancedSettingsState(
+ eventSink = eventsRecorder,
+ showChangePushProviderDialog = true,
+ availablePushDistributors = listOf("P1", "P2")
+ ),
+ )
+ rule.onNodeWithText("P2").performClick()
+ eventsRecorder.assertSingle(AdvancedSettingsEvents.SetPushProvider(1))
+ }
+}
+
+private fun AndroidComposeTestRule.setAdvancedSettingsView(
+ state: AdvancedSettingsState,
+ onBackPressed: () -> Unit = EnsureNeverCalled(),
+) {
+ setContent {
+ AdvancedSettingsView(
+ state = state,
+ onBackPressed = onBackPressed,
+ )
+ }
+}
diff --git a/features/rageshake/api/src/main/res/values-ka/translations.xml b/features/rageshake/api/src/main/res/values-ka/translations.xml
new file mode 100644
index 0000000000..64c22d0763
--- /dev/null
+++ b/features/rageshake/api/src/main/res/values-ka/translations.xml
@@ -0,0 +1,7 @@
+
+
+ "%1$s ავარიულად გაითიშა ბოლოს გამოიყენებისას. გსურთ, გამოგვიგზავნოთ ავარიული გათიშვის ჟურნალი?"
+ "როგორც ჩანს, იმედგაცრუებით ტელეფონს აჯანჯღალებთ. გსურთ, გახსნათ შეცდომის დარეპორტების ეკრანი?"
+ "Rageshake"
+ "გამოვლენის ზღვარი"
+
diff --git a/features/rageshake/api/src/main/res/values-pt/translations.xml b/features/rageshake/api/src/main/res/values-pt/translations.xml
new file mode 100644
index 0000000000..8fc38566c4
--- /dev/null
+++ b/features/rageshake/api/src/main/res/values-pt/translations.xml
@@ -0,0 +1,7 @@
+
+
+ "A %1$s teve uma falha da última vez que foi utilizada. Gostarias de partilhar um relatório de acidente connosco?"
+ "Parece que estás a abanar o telefone em sinal de frustração. Gostarias de abrir o painel de relatório de erros?"
+ "Rageshake"
+ "Limiar de deteção"
+
diff --git a/features/rageshake/api/src/main/res/values-zh/translations.xml b/features/rageshake/api/src/main/res/values-zh/translations.xml
new file mode 100644
index 0000000000..38942e2f1a
--- /dev/null
+++ b/features/rageshake/api/src/main/res/values-zh/translations.xml
@@ -0,0 +1,7 @@
+
+
+ "%1$s 上次使用时崩溃了。你想和我们分享崩溃报告吗?"
+ "你似乎愤怒地摇晃了手机。想要打开 Bug 报告页面吗?"
+ "摇一摇"
+ "检测阈值"
+
diff --git a/features/rageshake/impl/src/main/res/values-es/translations.xml b/features/rageshake/impl/src/main/res/values-es/translations.xml
index 3c0d78b659..7398dbc6de 100644
--- a/features/rageshake/impl/src/main/res/values-es/translations.xml
+++ b/features/rageshake/impl/src/main/res/values-es/translations.xml
@@ -7,9 +7,11 @@
"Describe el problema. ¿Qué has hecho? ¿Qué esperabas que ocurriera? ¿Qué ocurrió realmente? Por favor, detállalo todo lo que puedas."
"Describe el problema…"
"Si es posible, escriba la descripción en inglés."
+ "La descripción es demasiado corta. Proporcione más detalles sobre lo sucedido. ¡Gracias!"
"Enviar registros de fallos"
"Permitir registros"
"Enviar captura de pantalla"
"Los registros se incluirán con su mensaje para asegurarse de que todo funciona correctamente. Para enviar tu mensaje sin registros, desactiva esta configuración."
"%1$s se cerró inesperadamente la última vez que se lo usaste. ¿Quieres compartir un informe de error con nosotros?"
+ "Ver los registros"
diff --git a/features/rageshake/impl/src/main/res/values-ka/translations.xml b/features/rageshake/impl/src/main/res/values-ka/translations.xml
new file mode 100644
index 0000000000..6f0afb86b1
--- /dev/null
+++ b/features/rageshake/impl/src/main/res/values-ka/translations.xml
@@ -0,0 +1,15 @@
+
+
+ "ეკრანის ანაბეჭდის დართვა"
+ "შეგიძლიათ, დამიკავშირდეთ თუ გაქვთ შემდგომი კითხვები."
+ "დამიკავშირდით"
+ "ეკრანის ანაბეჭდის რედაქტირება"
+ "გთხოვთ, აღწეროთ პრობლემა. რა გააკეთე? რა შედეგს ელოდებოდით? რა მოხდა სინამდვილეში? გთხოვთ, ყველაფერი დაწვრილებით თქვათ."
+ "აღწერეთ პრობლემა…"
+ "თუ შესაძლებელია, გთხოვთ, დაწეროთ აღწერა ინგლისურ ენაზე."
+ "გაუმართაობის ჟურნალის გაგზავნა"
+ "ჟურნალების დაშვება"
+ "ეკრანის ანაბეჭდის გაგზავნა"
+ "ჟურნალები თქვენს შეტყობინებაში შევა იმაში დასარწმუნებლად, რომ ყველაფერი სწორად მუშაობს. ჟურნალების გარეშე გასაგზავნად გათიშეთ ეს პარამეტრი."
+ "%1$s ავარიულად გაითიშა ბოლოს გამოიყენებისას. გსურთ, გამოგვიგზავნოთ ავარიული გათიშვის ჟურნალი?"
+
diff --git a/features/rageshake/impl/src/main/res/values-pt/translations.xml b/features/rageshake/impl/src/main/res/values-pt/translations.xml
new file mode 100644
index 0000000000..59a066a16e
--- /dev/null
+++ b/features/rageshake/impl/src/main/res/values-pt/translations.xml
@@ -0,0 +1,17 @@
+
+
+ "Anexar captura de ecrã"
+ "Podem contactar-me se tiverem mais questões."
+ "Contactar-me"
+ "Editar captura de ecrã"
+ "Descreve o problema. O que é que fizeste? O que esperavas que acontecesse? O que realmente aconteceu? Por favor, dá o máximo de detalhes que puderes."
+ "Descreve o problema…"
+ "Se possível, escreve a descrição em inglês."
+ "A descrição é demasiado curta. Por favor dá mais detalhes sobre o que aconteceu. Obrigado!"
+ "Enviar registos de falha"
+ "Permitir registos"
+ "Enviar captura de ecrã"
+ "Os registos serão incluídos na tua mensagem para garantir que tudo está a funcionar corretamente. Para enviares a tua mensagem sem registos, desativa esta definição."
+ "A %1$s teve uma falha da última vez que foi utilizada. Gostarias de partilhar um relatório de acidente connosco?"
+ "Ver registos"
+
diff --git a/features/rageshake/impl/src/main/res/values-sv/translations.xml b/features/rageshake/impl/src/main/res/values-sv/translations.xml
index 0058b6519a..f04ccdf738 100644
--- a/features/rageshake/impl/src/main/res/values-sv/translations.xml
+++ b/features/rageshake/impl/src/main/res/values-sv/translations.xml
@@ -7,6 +7,7 @@
"Vänligen beskriv problemet. Vad gjorde du? Vad förväntade du dig skulle hända? Vad hände istället? Vänligen gå in i så mycket detaljer som möjligt."
"Beskriv problemet …"
"Om möjligt, skriv beskrivningen på engelska."
+ "Beskrivningen är för kort, vänligen ge mer information om vad som hände. Tack!"
"Skicka kraschloggar"
"Tillåt loggar"
"Skicka skärmdump"
diff --git a/features/rageshake/impl/src/main/res/values-zh/translations.xml b/features/rageshake/impl/src/main/res/values-zh/translations.xml
new file mode 100644
index 0000000000..7fbf6bd644
--- /dev/null
+++ b/features/rageshake/impl/src/main/res/values-zh/translations.xml
@@ -0,0 +1,17 @@
+
+
+ "附上截图"
+ "如果您有任何后续问题,可以与我联系。"
+ "联系我"
+ "编辑截图"
+ "请尽可能详细地描述问题。您做了什么?您预期会发生什么?实际发生了什么?"
+ "描述问题…"
+ "请尽可能用英文描述。"
+ "描述太短,请提供详细情况。谢谢!"
+ "发送崩溃日志"
+ "允许日志"
+ "发送屏幕截图"
+ "为确认一切正常运行,您的消息中将包含日志。如要发送不带日志的消息,请关闭此设置。"
+ "%1$s 上次使用时崩溃了。你想和我们分享崩溃报告吗?"
+ "查看日志"
+
diff --git a/features/roomaliasresolver/api/src/main/kotlin/io/element/android/features/roomaliasesolver/api/RoomAliasResolverEntryPoint.kt b/features/roomaliasresolver/api/src/main/kotlin/io/element/android/features/roomaliasesolver/api/RoomAliasResolverEntryPoint.kt
index 8c0cc10f64..b22a968035 100644
--- a/features/roomaliasresolver/api/src/main/kotlin/io/element/android/features/roomaliasesolver/api/RoomAliasResolverEntryPoint.kt
+++ b/features/roomaliasresolver/api/src/main/kotlin/io/element/android/features/roomaliasesolver/api/RoomAliasResolverEntryPoint.kt
@@ -22,7 +22,7 @@ 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.RoomAlias
-import io.element.android.libraries.matrix.api.core.RoomId
+import io.element.android.libraries.matrix.api.room.alias.ResolvedRoomAlias
interface RoomAliasResolverEntryPoint : FeatureEntryPoint {
fun nodeBuilder(parentNode: Node, buildContext: BuildContext): NodeBuilder
@@ -34,7 +34,7 @@ interface RoomAliasResolverEntryPoint : FeatureEntryPoint {
}
interface Callback : Plugin {
- fun onAliasResolved(roomId: RoomId)
+ fun onAliasResolved(data: ResolvedRoomAlias)
}
data class Params(
diff --git a/features/roomaliasresolver/impl/src/main/kotlin/io/element/android/features/roomaliasresolver/impl/RoomAliasResolverNode.kt b/features/roomaliasresolver/impl/src/main/kotlin/io/element/android/features/roomaliasresolver/impl/RoomAliasResolverNode.kt
index a4dbcc40b5..d6d497e62a 100644
--- a/features/roomaliasresolver/impl/src/main/kotlin/io/element/android/features/roomaliasresolver/impl/RoomAliasResolverNode.kt
+++ b/features/roomaliasresolver/impl/src/main/kotlin/io/element/android/features/roomaliasresolver/impl/RoomAliasResolverNode.kt
@@ -28,7 +28,7 @@ import io.element.android.anvilannotations.ContributesNode
import io.element.android.features.roomaliasesolver.api.RoomAliasResolverEntryPoint
import io.element.android.libraries.architecture.inputs
import io.element.android.libraries.di.SessionScope
-import io.element.android.libraries.matrix.api.core.RoomId
+import io.element.android.libraries.matrix.api.room.alias.ResolvedRoomAlias
@ContributesNode(SessionScope::class)
class RoomAliasResolverNode @AssistedInject constructor(
@@ -42,8 +42,8 @@ class RoomAliasResolverNode @AssistedInject constructor(
inputs.roomAlias
)
- private fun onAliasResolved(roomId: RoomId) {
- plugins().forEach { it.onAliasResolved(roomId) }
+ private fun onAliasResolved(data: ResolvedRoomAlias) {
+ plugins().forEach { it.onAliasResolved(data) }
}
@Composable
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 775be7d6ff..5e3671f564 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
@@ -29,7 +29,7 @@ import io.element.android.libraries.architecture.Presenter
import io.element.android.libraries.architecture.runCatchingUpdatingState
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.room.alias.ResolvedRoomAlias
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.launch
@@ -46,7 +46,7 @@ class RoomAliasResolverPresenter @AssistedInject constructor(
@Composable
override fun present(): RoomAliasResolverState {
val coroutineScope = rememberCoroutineScope()
- val resolveState: MutableState> = remember { mutableStateOf(AsyncData.Uninitialized) }
+ val resolveState: MutableState> = remember { mutableStateOf(AsyncData.Uninitialized) }
LaunchedEffect(Unit) {
resolveAlias(resolveState)
}
@@ -64,7 +64,7 @@ class RoomAliasResolverPresenter @AssistedInject constructor(
)
}
- private fun CoroutineScope.resolveAlias(resolveState: MutableState>) = launch {
+ private fun CoroutineScope.resolveAlias(resolveState: MutableState>) = launch {
suspend {
matrixClient.resolveRoomAlias(roomAlias).getOrThrow()
}.runCatchingUpdatingState(resolveState)
diff --git a/features/roomaliasresolver/impl/src/main/kotlin/io/element/android/features/roomaliasresolver/impl/RoomAliasResolverState.kt b/features/roomaliasresolver/impl/src/main/kotlin/io/element/android/features/roomaliasresolver/impl/RoomAliasResolverState.kt
index 638214da3f..12cbb64c00 100644
--- a/features/roomaliasresolver/impl/src/main/kotlin/io/element/android/features/roomaliasresolver/impl/RoomAliasResolverState.kt
+++ b/features/roomaliasresolver/impl/src/main/kotlin/io/element/android/features/roomaliasresolver/impl/RoomAliasResolverState.kt
@@ -19,11 +19,11 @@ package io.element.android.features.roomaliasresolver.impl
import androidx.compose.runtime.Immutable
import io.element.android.libraries.architecture.AsyncData
import io.element.android.libraries.matrix.api.core.RoomAlias
-import io.element.android.libraries.matrix.api.core.RoomId
+import io.element.android.libraries.matrix.api.room.alias.ResolvedRoomAlias
@Immutable
data class RoomAliasResolverState(
val roomAlias: RoomAlias,
- val resolveState: AsyncData,
+ val resolveState: AsyncData,
val eventSink: (RoomAliasResolverEvents) -> Unit
)
diff --git a/features/roomaliasresolver/impl/src/main/kotlin/io/element/android/features/roomaliasresolver/impl/RoomAliasResolverStateProvider.kt b/features/roomaliasresolver/impl/src/main/kotlin/io/element/android/features/roomaliasresolver/impl/RoomAliasResolverStateProvider.kt
index 3c5599628c..e7e5cfc686 100644
--- a/features/roomaliasresolver/impl/src/main/kotlin/io/element/android/features/roomaliasresolver/impl/RoomAliasResolverStateProvider.kt
+++ b/features/roomaliasresolver/impl/src/main/kotlin/io/element/android/features/roomaliasresolver/impl/RoomAliasResolverStateProvider.kt
@@ -19,7 +19,7 @@ package io.element.android.features.roomaliasresolver.impl
import androidx.compose.ui.tooling.preview.PreviewParameterProvider
import io.element.android.libraries.architecture.AsyncData
import io.element.android.libraries.matrix.api.core.RoomAlias
-import io.element.android.libraries.matrix.api.core.RoomId
+import io.element.android.libraries.matrix.api.room.alias.ResolvedRoomAlias
open class RoomAliasResolverStateProvider : PreviewParameterProvider {
override val values: Sequence
@@ -36,7 +36,7 @@ open class RoomAliasResolverStateProvider : PreviewParameterProvider = AsyncData.Uninitialized,
+ resolveState: AsyncData = AsyncData.Uninitialized,
eventSink: (RoomAliasResolverEvents) -> Unit = {}
) = RoomAliasResolverState(
roomAlias = roomAlias,
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 cd5bd042c8..722eb86650 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
@@ -49,14 +49,14 @@ 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.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.alias.ResolvedRoomAlias
import io.element.android.libraries.ui.strings.CommonStrings
@Composable
fun RoomAliasResolverView(
state: RoomAliasResolverState,
onBackPressed: () -> Unit,
- onAliasResolved: (RoomId) -> Unit,
+ onAliasResolved: (ResolvedRoomAlias) -> Unit,
modifier: Modifier = Modifier,
) {
val latestOnAliasResolved by rememberUpdatedState(onAliasResolved)
diff --git a/features/roomaliasresolver/impl/src/main/res/values-it/translations.xml b/features/roomaliasresolver/impl/src/main/res/values-it/translations.xml
new file mode 100644
index 0000000000..e52051ae93
--- /dev/null
+++ b/features/roomaliasresolver/impl/src/main/res/values-it/translations.xml
@@ -0,0 +1,4 @@
+
+
+ "Impossibile risolvere l\'alias della stanza."
+
diff --git a/features/roomaliasresolver/impl/src/main/res/values-pt/translations.xml b/features/roomaliasresolver/impl/src/main/res/values-pt/translations.xml
new file mode 100644
index 0000000000..aa469c7158
--- /dev/null
+++ b/features/roomaliasresolver/impl/src/main/res/values-pt/translations.xml
@@ -0,0 +1,4 @@
+
+
+ "Não foi possível encontrar esse endereço de sala"
+
diff --git a/features/roomaliasresolver/impl/src/main/res/values-ro/translations.xml b/features/roomaliasresolver/impl/src/main/res/values-ro/translations.xml
new file mode 100644
index 0000000000..fbec806c6a
--- /dev/null
+++ b/features/roomaliasresolver/impl/src/main/res/values-ro/translations.xml
@@ -0,0 +1,4 @@
+
+
+ "Nu s-a putut rezolva alias-ul camerei."
+
diff --git a/features/roomaliasresolver/impl/src/main/res/values-zh/translations.xml b/features/roomaliasresolver/impl/src/main/res/values-zh/translations.xml
new file mode 100644
index 0000000000..420d74e4a4
--- /dev/null
+++ b/features/roomaliasresolver/impl/src/main/res/values-zh/translations.xml
@@ -0,0 +1,4 @@
+
+
+ "无法解析房间别名。"
+
diff --git a/features/roomaliasresolver/impl/src/test/kotlin/io/element/android/features/roomaliasresolver/impl/RoomAliasResolverPresenterTest.kt b/features/roomaliasresolver/impl/src/test/kotlin/io/element/android/features/roomaliasresolver/impl/RoomAliasResolverPresenterTest.kt
index 2c64690600..c3cd566432 100644
--- a/features/roomaliasresolver/impl/src/test/kotlin/io/element/android/features/roomaliasresolver/impl/RoomAliasResolverPresenterTest.kt
+++ b/features/roomaliasresolver/impl/src/test/kotlin/io/element/android/features/roomaliasresolver/impl/RoomAliasResolverPresenterTest.kt
@@ -22,9 +22,12 @@ import app.cash.turbine.test
import com.google.common.truth.Truth.assertThat
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.room.alias.ResolvedRoomAlias
import io.element.android.libraries.matrix.test.AN_EXCEPTION
import io.element.android.libraries.matrix.test.A_ROOM_ALIAS
import io.element.android.libraries.matrix.test.A_ROOM_ID
+import io.element.android.libraries.matrix.test.A_SERVER_LIST
import io.element.android.libraries.matrix.test.FakeMatrixClient
import io.element.android.tests.testutils.WarmUpRule
import kotlinx.coroutines.test.runTest
@@ -48,8 +51,9 @@ class RoomAliasResolverPresenterTest {
@Test
fun `present - resolve alias to roomId`() = runTest {
+ val result = aResolvedRoomAlias()
val client = FakeMatrixClient(
- resolveRoomAliasResult = { Result.success(A_ROOM_ID) }
+ resolveRoomAliasResult = { Result.success(result) }
)
val presenter = createPresenter(matrixClient = client)
moleculeFlow(RecompositionMode.Immediate) {
@@ -59,7 +63,7 @@ class RoomAliasResolverPresenterTest {
assertThat(awaitItem().resolveState.isLoading()).isTrue()
val resultState = awaitItem()
assertThat(resultState.roomAlias).isEqualTo(A_ROOM_ALIAS)
- assertThat(resultState.resolveState.dataOrNull()).isEqualTo(A_ROOM_ID)
+ assertThat(resultState.resolveState.dataOrNull()).isEqualTo(result)
}
}
@@ -92,3 +96,11 @@ class RoomAliasResolverPresenterTest {
matrixClient = matrixClient,
)
}
+
+internal fun aResolvedRoomAlias(
+ roomId: RoomId = A_ROOM_ID,
+ servers: List = A_SERVER_LIST,
+) = ResolvedRoomAlias(
+ roomId = roomId,
+ servers = servers,
+)
diff --git a/features/roomaliasresolver/impl/src/test/kotlin/io/element/android/features/roomaliasresolver/impl/RoomAliasResolverViewTest.kt b/features/roomaliasresolver/impl/src/test/kotlin/io/element/android/features/roomaliasresolver/impl/RoomAliasResolverViewTest.kt
index 6df8a7849e..990bbfe46a 100644
--- a/features/roomaliasresolver/impl/src/test/kotlin/io/element/android/features/roomaliasresolver/impl/RoomAliasResolverViewTest.kt
+++ b/features/roomaliasresolver/impl/src/test/kotlin/io/element/android/features/roomaliasresolver/impl/RoomAliasResolverViewTest.kt
@@ -21,8 +21,7 @@ import androidx.compose.ui.test.junit4.AndroidComposeTestRule
import androidx.compose.ui.test.junit4.createAndroidComposeRule
import androidx.test.ext.junit.runners.AndroidJUnit4
import io.element.android.libraries.architecture.AsyncData
-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.api.room.alias.ResolvedRoomAlias
import io.element.android.libraries.ui.strings.CommonStrings
import io.element.android.tests.testutils.EnsureNeverCalled
import io.element.android.tests.testutils.EnsureNeverCalledWithParam
@@ -69,11 +68,12 @@ class RoomAliasResolverViewTest {
@Test
fun `success state invokes the expected Callback`() {
+ val result = aResolvedRoomAlias()
val eventsRecorder = EventsRecorder(expectEvents = false)
- ensureCalledOnceWithParam(A_ROOM_ID) {
+ ensureCalledOnceWithParam(result) {
rule.setRoomAliasResolverView(
aRoomAliasResolverState(
- resolveState = AsyncData.Success(A_ROOM_ID),
+ resolveState = AsyncData.Success(result),
eventSink = eventsRecorder,
),
onAliasResolved = it,
@@ -85,7 +85,7 @@ class RoomAliasResolverViewTest {
private fun AndroidComposeTestRule.setRoomAliasResolverView(
state: RoomAliasResolverState,
onBackPressed: () -> Unit = EnsureNeverCalled(),
- onAliasResolved: (RoomId) -> Unit = EnsureNeverCalledWithParam(),
+ onAliasResolved: (ResolvedRoomAlias) -> Unit = EnsureNeverCalledWithParam(),
) {
setContent {
RoomAliasResolverView(
diff --git a/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/edit/RoomDetailsEditPresenter.kt b/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/edit/RoomDetailsEditPresenter.kt
index 6213f2cf1a..67d333c41d 100644
--- a/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/edit/RoomDetailsEditPresenter.kt
+++ b/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/edit/RoomDetailsEditPresenter.kt
@@ -37,6 +37,9 @@ import io.element.android.libraries.matrix.api.room.MatrixRoom
import io.element.android.libraries.matrix.api.room.StateEventType
import io.element.android.libraries.matrix.api.room.powerlevels.canSendState
import io.element.android.libraries.matrix.ui.media.AvatarAction
+import io.element.android.libraries.matrix.ui.room.avatarUrl
+import io.element.android.libraries.matrix.ui.room.rawName
+import io.element.android.libraries.matrix.ui.room.topic
import io.element.android.libraries.mediapickers.api.PickerProvider
import io.element.android.libraries.mediaupload.api.MediaPreProcessor
import io.element.android.libraries.permissions.api.PermissionsEvents
@@ -61,23 +64,35 @@ class RoomDetailsEditPresenter @Inject constructor(
val cameraPermissionState = cameraPermissionPresenter.present()
val roomSyncUpdateFlow = room.syncUpdateFlow.collectAsState()
- // Since there is no way to obtain the new avatar uri after uploading a new avatar,
- // just erase the local value when the room field has changed
- var roomAvatarUri by rememberSaveable(room.avatarUrl) { mutableStateOf(room.avatarUrl?.toUri()) }
+ val roomAvatarUri = room.avatarUrl()?.toUri()
+ var roomAvatarUriEdited by rememberSaveable { mutableStateOf(null) }
+ LaunchedEffect(roomAvatarUri) {
+ // Every time the roomAvatar change (from sync), we can set the new avatar.
+ roomAvatarUriEdited = roomAvatarUri
+ }
- var roomName by rememberSaveable { mutableStateOf(room.displayName.trim()) }
- var roomTopic by rememberSaveable { mutableStateOf(room.topic?.trim()) }
+ val roomRawNameTrimmed = room.rawName().orEmpty().trim()
+ var roomRawNameEdited by rememberSaveable { mutableStateOf("") }
+ LaunchedEffect(roomRawNameTrimmed) {
+ // Every time the rawName change (from sync), we can set the new name.
+ roomRawNameEdited = roomRawNameTrimmed
+ }
+ val roomTopicTrimmed = room.topic().orEmpty().trim()
+ var roomTopicEdited by rememberSaveable { mutableStateOf("") }
+ LaunchedEffect(roomTopicTrimmed) {
+ // Every time the topic change (from sync), we can set the new topic.
+ roomTopicEdited = roomTopicTrimmed
+ }
val saveButtonEnabled by remember(
- roomSyncUpdateFlow.value,
- roomName,
- roomTopic,
+ roomRawNameTrimmed,
+ roomTopicTrimmed,
roomAvatarUri,
) {
derivedStateOf {
- roomAvatarUri?.toString()?.trim() != room.avatarUrl?.toUri()?.toString()?.trim() ||
- roomName.trim() != room.displayName.trim() ||
- roomTopic.orEmpty().trim() != room.topic.orEmpty().trim()
+ roomRawNameTrimmed != roomRawNameEdited.trim() ||
+ roomTopicTrimmed != roomTopicEdited.trim() ||
+ roomAvatarUri != roomAvatarUriEdited
}
}
@@ -85,17 +100,17 @@ class RoomDetailsEditPresenter @Inject constructor(
var canChangeTopic by remember { mutableStateOf(false) }
var canChangeAvatar by remember { mutableStateOf(false) }
- LaunchedEffect(Unit) {
+ LaunchedEffect(roomSyncUpdateFlow.value) {
canChangeName = room.canSendState(StateEventType.ROOM_NAME).getOrElse { false }
canChangeTopic = room.canSendState(StateEventType.ROOM_TOPIC).getOrElse { false }
canChangeAvatar = room.canSendState(StateEventType.ROOM_AVATAR).getOrElse { false }
}
val cameraPhotoPicker = mediaPickerProvider.registerCameraPhotoPicker(
- onResult = { uri -> if (uri != null) roomAvatarUri = uri }
+ onResult = { uri -> if (uri != null) roomAvatarUriEdited = uri }
)
val galleryImagePicker = mediaPickerProvider.registerGalleryImagePicker(
- onResult = { uri -> if (uri != null) roomAvatarUri = uri }
+ onResult = { uri -> if (uri != null) roomAvatarUriEdited = uri }
)
LaunchedEffect(cameraPermissionState.permissionGranted) {
@@ -105,12 +120,12 @@ class RoomDetailsEditPresenter @Inject constructor(
}
}
- val avatarActions by remember(roomAvatarUri) {
+ val avatarActions by remember(roomAvatarUriEdited) {
derivedStateOf {
listOfNotNull(
AvatarAction.TakePhoto,
AvatarAction.ChoosePhoto,
- AvatarAction.Remove.takeIf { roomAvatarUri != null },
+ AvatarAction.Remove.takeIf { roomAvatarUriEdited != null },
).toImmutableList()
}
}
@@ -119,7 +134,15 @@ class RoomDetailsEditPresenter @Inject constructor(
val localCoroutineScope = rememberCoroutineScope()
fun handleEvents(event: RoomDetailsEditEvents) {
when (event) {
- is RoomDetailsEditEvents.Save -> localCoroutineScope.saveChanges(roomName, roomTopic, roomAvatarUri, saveAction)
+ is RoomDetailsEditEvents.Save -> localCoroutineScope.saveChanges(
+ currentNameTrimmed = roomRawNameTrimmed,
+ newNameTrimmed = roomRawNameEdited.trim(),
+ currentTopicTrimmed = roomTopicTrimmed,
+ newTopicTrimmed = roomTopicEdited.trim(),
+ currentAvatar = roomAvatarUri,
+ newAvatarUri = roomAvatarUriEdited,
+ action = saveAction,
+ )
is RoomDetailsEditEvents.HandleAvatarAction -> {
when (event.action) {
AvatarAction.ChoosePhoto -> galleryImagePicker.launch()
@@ -129,23 +152,23 @@ class RoomDetailsEditPresenter @Inject constructor(
pendingPermissionRequest = true
cameraPermissionState.eventSink(PermissionsEvents.RequestPermissions)
}
- AvatarAction.Remove -> roomAvatarUri = null
+ AvatarAction.Remove -> roomAvatarUriEdited = null
}
}
- is RoomDetailsEditEvents.UpdateRoomName -> roomName = event.name
- is RoomDetailsEditEvents.UpdateRoomTopic -> roomTopic = event.topic.takeUnless { it.isEmpty() }
+ is RoomDetailsEditEvents.UpdateRoomName -> roomRawNameEdited = event.name
+ is RoomDetailsEditEvents.UpdateRoomTopic -> roomTopicEdited = event.topic
RoomDetailsEditEvents.CancelSaveChanges -> saveAction.value = AsyncAction.Uninitialized
}
}
return RoomDetailsEditState(
- roomId = room.roomId.value,
- roomName = roomName,
+ roomId = room.roomId,
+ roomRawName = roomRawNameEdited,
canChangeName = canChangeName,
- roomTopic = roomTopic.orEmpty(),
+ roomTopic = roomTopicEdited,
canChangeTopic = canChangeTopic,
- roomAvatarUrl = roomAvatarUri,
+ roomAvatarUrl = roomAvatarUriEdited,
canChangeAvatar = canChangeAvatar,
avatarActions = avatarActions,
saveButtonEnabled = saveButtonEnabled,
@@ -156,25 +179,28 @@ class RoomDetailsEditPresenter @Inject constructor(
}
private fun CoroutineScope.saveChanges(
- name: String,
- topic: String?,
- avatarUri: Uri?,
+ currentNameTrimmed: String,
+ newNameTrimmed: String,
+ currentTopicTrimmed: String,
+ newTopicTrimmed: String,
+ currentAvatar: Uri?,
+ newAvatarUri: Uri?,
action: MutableState>,
) = launch {
val results = mutableListOf>()
suspend {
- if (topic.orEmpty().trim() != room.topic.orEmpty().trim()) {
- results.add(room.setTopic(topic.orEmpty()).onFailure {
+ if (newTopicTrimmed != currentTopicTrimmed) {
+ results.add(room.setTopic(newTopicTrimmed).onFailure {
Timber.e(it, "Failed to set room topic")
})
}
- if (name.isNotEmpty() && name.trim() != room.displayName.trim()) {
- results.add(room.setName(name).onFailure {
+ if (newNameTrimmed.isNotEmpty() && newNameTrimmed != currentNameTrimmed) {
+ results.add(room.setName(newNameTrimmed).onFailure {
Timber.e(it, "Failed to set room name")
})
}
- if (avatarUri?.toString()?.trim() != room.avatarUrl?.trim()) {
- results.add(updateAvatar(avatarUri).onFailure {
+ if (newAvatarUri != currentAvatar) {
+ results.add(updateAvatar(newAvatarUri).onFailure {
Timber.e(it, "Failed to update avatar")
})
}
diff --git a/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/edit/RoomDetailsEditState.kt b/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/edit/RoomDetailsEditState.kt
index d85450b59f..ec74905e38 100644
--- a/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/edit/RoomDetailsEditState.kt
+++ b/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/edit/RoomDetailsEditState.kt
@@ -18,13 +18,15 @@ package io.element.android.features.roomdetails.impl.edit
import android.net.Uri
import io.element.android.libraries.architecture.AsyncAction
+import io.element.android.libraries.matrix.api.core.RoomId
import io.element.android.libraries.matrix.ui.media.AvatarAction
import io.element.android.libraries.permissions.api.PermissionsState
import kotlinx.collections.immutable.ImmutableList
data class RoomDetailsEditState(
- val roomId: String,
- val roomName: String,
+ val roomId: RoomId,
+ /** The raw room name (i.e. the room name from the state event `m.room.name`), not the display name. */
+ val roomRawName: String,
val canChangeName: Boolean,
val roomTopic: String,
val canChangeTopic: Boolean,
diff --git a/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/edit/RoomDetailsEditStateProvider.kt b/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/edit/RoomDetailsEditStateProvider.kt
index d70c83b9a0..abf4f64b69 100644
--- a/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/edit/RoomDetailsEditStateProvider.kt
+++ b/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/edit/RoomDetailsEditStateProvider.kt
@@ -19,33 +19,50 @@ package io.element.android.features.roomdetails.impl.edit
import android.net.Uri
import androidx.compose.ui.tooling.preview.PreviewParameterProvider
import io.element.android.libraries.architecture.AsyncAction
+import io.element.android.libraries.matrix.api.core.RoomId
+import io.element.android.libraries.matrix.ui.media.AvatarAction
+import io.element.android.libraries.permissions.api.PermissionsState
import io.element.android.libraries.permissions.api.aPermissionsState
-import kotlinx.collections.immutable.persistentListOf
+import kotlinx.collections.immutable.toImmutableList
open class RoomDetailsEditStateProvider : PreviewParameterProvider {
override val values: Sequence
get() = sequenceOf(
aRoomDetailsEditState(),
- aRoomDetailsEditState().copy(roomTopic = ""),
- aRoomDetailsEditState().copy(roomAvatarUrl = Uri.parse("example://uri")),
- aRoomDetailsEditState().copy(canChangeName = true, canChangeTopic = false, canChangeAvatar = true, saveButtonEnabled = false),
- aRoomDetailsEditState().copy(canChangeName = false, canChangeTopic = true, canChangeAvatar = false, saveButtonEnabled = false),
- aRoomDetailsEditState().copy(saveAction = AsyncAction.Loading),
- aRoomDetailsEditState().copy(saveAction = AsyncAction.Failure(Throwable("Whelp")))
+ aRoomDetailsEditState(roomTopic = ""),
+ aRoomDetailsEditState(roomRawName = ""),
+ aRoomDetailsEditState(roomAvatarUrl = Uri.parse("example://uri")),
+ aRoomDetailsEditState(canChangeName = true, canChangeTopic = false, canChangeAvatar = true, saveButtonEnabled = false),
+ aRoomDetailsEditState(canChangeName = false, canChangeTopic = true, canChangeAvatar = false, saveButtonEnabled = false),
+ aRoomDetailsEditState(saveAction = AsyncAction.Loading),
+ aRoomDetailsEditState(saveAction = AsyncAction.Failure(Throwable("Whelp"))),
)
}
-fun aRoomDetailsEditState() = RoomDetailsEditState(
- roomId = "a room id",
- roomName = "Marketing",
- canChangeName = true,
- roomTopic = "a room topic that is quite long so should wrap onto multiple lines",
- canChangeTopic = true,
- roomAvatarUrl = null,
- canChangeAvatar = true,
- avatarActions = persistentListOf(),
- saveButtonEnabled = true,
- saveAction = AsyncAction.Uninitialized,
- cameraPermissionState = aPermissionsState(showDialog = false),
- eventSink = {}
+fun aRoomDetailsEditState(
+ roomId: RoomId = RoomId("!aRoomId:aDomain"),
+ roomRawName: String = "Marketing",
+ canChangeName: Boolean = true,
+ roomTopic: String = "a room topic that is quite long so should wrap onto multiple lines",
+ canChangeTopic: Boolean = true,
+ roomAvatarUrl: Uri? = null,
+ canChangeAvatar: Boolean = true,
+ avatarActions: List = emptyList(),
+ saveButtonEnabled: Boolean = true,
+ saveAction: AsyncAction = AsyncAction.Uninitialized,
+ cameraPermissionState: PermissionsState = aPermissionsState(showDialog = false),
+ eventSink: (RoomDetailsEditEvents) -> Unit = {},
+) = RoomDetailsEditState(
+ roomId = roomId,
+ roomRawName = roomRawName,
+ canChangeName = canChangeName,
+ roomTopic = roomTopic,
+ canChangeTopic = canChangeTopic,
+ roomAvatarUrl = roomAvatarUrl,
+ canChangeAvatar = canChangeAvatar,
+ avatarActions = avatarActions.toImmutableList(),
+ saveButtonEnabled = saveButtonEnabled,
+ saveAction = saveAction,
+ cameraPermissionState = cameraPermissionState,
+ eventSink = eventSink,
)
diff --git a/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/edit/RoomDetailsEditView.kt b/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/edit/RoomDetailsEditView.kt
index b93bbd1f47..e0da0d2f19 100644
--- a/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/edit/RoomDetailsEditView.kt
+++ b/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/edit/RoomDetailsEditView.kt
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-@file:OptIn(ExperimentalMaterial3Api::class, ExperimentalMaterialApi::class)
+@file:OptIn(ExperimentalMaterial3Api::class)
package io.element.android.features.roomdetails.impl.edit
@@ -29,13 +29,11 @@ import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.text.KeyboardOptions
import androidx.compose.foundation.verticalScroll
-import androidx.compose.material.ExperimentalMaterialApi
-import androidx.compose.material.ModalBottomSheetValue
-import androidx.compose.material.rememberModalBottomSheetState
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.MaterialTheme
import androidx.compose.runtime.Composable
-import androidx.compose.runtime.rememberCoroutineScope
+import androidx.compose.runtime.mutableStateOf
+import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalFocusManager
import androidx.compose.ui.res.stringResource
@@ -61,9 +59,7 @@ import io.element.android.libraries.matrix.ui.components.AvatarActionBottomSheet
import io.element.android.libraries.matrix.ui.components.EditableAvatarView
import io.element.android.libraries.permissions.api.PermissionsView
import io.element.android.libraries.ui.strings.CommonStrings
-import kotlinx.coroutines.launch
-@OptIn(ExperimentalMaterialApi::class, ExperimentalMaterial3Api::class)
@Composable
fun RoomDetailsEditView(
state: RoomDetailsEditState,
@@ -71,17 +67,12 @@ fun RoomDetailsEditView(
onRoomEdited: () -> Unit,
modifier: Modifier = Modifier,
) {
- val coroutineScope = rememberCoroutineScope()
val focusManager = LocalFocusManager.current
- val itemActionsBottomSheetState = rememberModalBottomSheetState(
- initialValue = ModalBottomSheetValue.Hidden,
- )
+ val isAvatarActionsSheetVisible = remember { mutableStateOf(false) }
fun onAvatarClicked() {
focusManager.clearFocus()
- coroutineScope.launch {
- itemActionsBottomSheetState.show()
- }
+ isAvatarActionsSheetVisible.value = true
}
Scaffold(
@@ -118,8 +109,9 @@ fun RoomDetailsEditView(
) {
Spacer(modifier = Modifier.height(24.dp))
EditableAvatarView(
- userId = state.roomId,
- displayName = state.roomName,
+ matrixId = state.roomId.value,
+ // As per Element Web, we use the raw name for the avatar as well
+ displayName = state.roomRawName,
avatarUrl = state.roomAvatarUrl,
avatarSize = AvatarSize.EditRoomDetails,
onAvatarClicked = ::onAvatarClicked,
@@ -130,7 +122,7 @@ fun RoomDetailsEditView(
if (state.canChangeName) {
LabelledTextField(
label = stringResource(id = R.string.screen_room_details_room_name_label),
- value = state.roomName,
+ value = state.roomRawName,
placeholder = stringResource(CommonStrings.common_room_name_placeholder),
singleLine = true,
onValueChange = { state.eventSink(RoomDetailsEditEvents.UpdateRoomName(it)) },
@@ -138,7 +130,7 @@ fun RoomDetailsEditView(
} else {
LabelledReadOnlyField(
title = stringResource(R.string.screen_room_details_room_name_label),
- value = state.roomName
+ value = state.roomRawName
)
}
@@ -166,7 +158,8 @@ fun RoomDetailsEditView(
AvatarActionBottomSheet(
actions = state.avatarActions,
- modalBottomSheetState = itemActionsBottomSheetState,
+ isVisible = isAvatarActionsSheetVisible.value,
+ onDismiss = { isAvatarActionsSheetVisible.value = false },
onActionSelected = { state.eventSink(RoomDetailsEditEvents.HandleAvatarAction(it)) }
)
diff --git a/features/roomdetails/impl/src/main/res/values-be/translations.xml b/features/roomdetails/impl/src/main/res/values-be/translations.xml
index cb2dc4ce7c..46f987b994 100644
--- a/features/roomdetails/impl/src/main/res/values-be/translations.xml
+++ b/features/roomdetails/impl/src/main/res/values-be/translations.xml
@@ -35,6 +35,9 @@
"Дадаць тэму"
"Ужо ўдзельнік"
"Ужо запрасілі"
+ "Зашыфравана"
+ "Не зашыфравана"
+ "Публічны пакой"
"Рэдагаваць пакой"
"Адбылася невядомая памылка, і інфармацыю нельга было змяніць."
"Немагчыма абнавіць пакой"
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 a8bbc85973..09003dc610 100644
--- a/features/roomdetails/impl/src/main/res/values-cs/translations.xml
+++ b/features/roomdetails/impl/src/main/res/values-cs/translations.xml
@@ -35,6 +35,9 @@
"Přidat téma"
"Již členem"
"Již pozván(a)"
+ "Šifrováno"
+ "Není šifrováno"
+ "Veřejná místnost"
"Upravit místnost"
"Došlo k neznámé chybě a informace nebylo možné změnit."
"Nelze aktualizovat místnost"
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 ae0366a6b1..f3bb984173 100644
--- a/features/roomdetails/impl/src/main/res/values-de/translations.xml
+++ b/features/roomdetails/impl/src/main/res/values-de/translations.xml
@@ -35,6 +35,9 @@
"Thema hinzufügen"
"Bereits Mitglied"
"Bereits eingeladen"
+ "Verschlüsselt"
+ "Nicht verschlüsselt"
+ "Öffentlicher Raum"
"Raum bearbeiten"
"Es ist ein unbekannter Fehler aufgetreten und die Informationen konnten nicht geändert werden."
"Raum kann nicht aktualisiert werden"
diff --git a/features/roomdetails/impl/src/main/res/values-es/translations.xml b/features/roomdetails/impl/src/main/res/values-es/translations.xml
index 16e6a55cfd..17a0249f09 100644
--- a/features/roomdetails/impl/src/main/res/values-es/translations.xml
+++ b/features/roomdetails/impl/src/main/res/values-es/translations.xml
@@ -3,7 +3,32 @@
"Se ha producido un error al actualizar la configuración de notificaciones."
"Tu servidor principal no admite esta opción en salas cifradas, puede que no recibas notificaciones en algunas salas."
"Encuestas"
+ "Solo administradores"
+ "Prohibir personas"
+ "Eliminar mensajes"
"Todos"
+ "Invitar a personas"
+ "Moderación de miembros"
+ "Mensajes y contenido"
+ "Administradores y moderadores"
+ "Eliminar personas"
+ "Cambiar el avatar de la sala"
+ "Detalles de la sala"
+ "Cambiar el nombre de la sala"
+ "Cambiar el tema de la sala"
+ "Enviar mensajes"
+ "Editar administradores"
+ "No podrás deshacer esta acción. Estás promocionando al usuario para que tenga el mismo nivel de poder que tú."
+ "¿Agregar Admin?"
+ "Degradar"
+ "No podrás deshacer este cambio ya que te estás degradando. Si eres el último usuario privilegiado en la sala será imposible recuperar los privilegios."
+ "¿Degradarte?"
+ "Editar moderadores"
+ "Administradores"
+ "Moderadores"
+ "Miembros"
+ "Tienes cambios sin guardar."
+ "¿Guardar cambios?"
"Añadir tema"
"Ya eres miembro"
"Ya estás invitado"
@@ -16,21 +41,43 @@
"No se ha podido silenciar esta sala, inténtalo de nuevo."
"Error al dejar de silenciar esta sala, por favor inténtalo de nuevo."
"Invitar personas"
+ "Salir de la conversación"
"Salir de la sala"
"Personalizado"
"Por defecto"
"Notificaciones"
+ "Roles y permisos"
"Nombre de la sala"
"Seguridad"
"Compartir sala"
"Tema"
"Actualizando la sala…"
+ "Prohibir"
+ "No podrán volver a unirse a esta sala si son invitados."
+ "¿Estás seguro de que quieres prohibir a este miembro?"
+ "No hay usuarios prohibidos en esta sala."
+ "Prohibiendo %1$s"
- "Una persona"
- "%1$d personas"
+ "Eliminar y prohibir a un miembro"
+ "Remover de la sala"
+ "Eliminar y prohibir miembro"
+ "Solo eliminar miembro"
+ "¿Eliminar al miembro y prohibirle unirse en el futuro?"
+ "Anular la prohibición"
+ "Podrán volver a unirse a esta sala si son invitados de nuevo."
+ "Desprohibir al usuario"
+ "Ver perfil"
+ "Prohibidos"
+ "Miembros"
"Pendiente"
+ "Eliminando %1$s…"
+ "Admin"
+ "Moderador"
"Miembros de la sala"
+ "Dejando de prohibir %1$s"
"Permitir configuración personalizada"
"Si activas esta opción, anularás tu configuración por defecto"
"Notificarme en este chat para"
@@ -45,4 +92,18 @@
"Todos los mensajes"
"Únicamente Menciones y Palabras clave"
"En esta sala, notificarme por"
+ "Administradores"
+ "Cambiar mi rol"
+ "Degradar a miembro"
+ "Degradar a moderador"
+ "Moderación de miembros"
+ "Mensajes y contenido"
+ "Moderadores"
+ "Permisos"
+ "Restablecer permisos"
+ "Una vez que restablezca los permisos, perderá la configuración actual."
+ "¿Restablecer los permisos?"
+ "Roles"
+ "Detalles de la sala"
+ "Roles y permisos"
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 71bc11c618..144b82fd87 100644
--- a/features/roomdetails/impl/src/main/res/values-fr/translations.xml
+++ b/features/roomdetails/impl/src/main/res/values-fr/translations.xml
@@ -85,7 +85,7 @@
"Autoriser les paramètres personnalisés"
"L’activation de cette option annulera votre paramètre par défaut"
"Prévenez-moi dans ce salon pour"
- "Vous pouvez le modifier dans votre %1$s."
+ "Vous pouvez le modifier dans vos %1$s."
"paramètres globaux"
"Paramètre par défaut"
"Supprimer le paramètre personnalisé"
diff --git a/features/roomdetails/impl/src/main/res/values-hu/translations.xml b/features/roomdetails/impl/src/main/res/values-hu/translations.xml
index 883a67e014..db9013b6cc 100644
--- a/features/roomdetails/impl/src/main/res/values-hu/translations.xml
+++ b/features/roomdetails/impl/src/main/res/values-hu/translations.xml
@@ -35,6 +35,9 @@
"Téma hozzáadása"
"Már tag"
"Már meghívták"
+ "Titkosítva"
+ "Nincs titkosítva"
+ "Nyilvános szoba"
"Szoba szerkesztése"
"Ismeretlen hiba történt, és az információkat nem lehetett megváltoztatni."
"Nem sikerült frissíteni a szobát"
diff --git a/features/roomdetails/impl/src/main/res/values-it/translations.xml b/features/roomdetails/impl/src/main/res/values-it/translations.xml
index ab3ec27fcc..d1ae1c380c 100644
--- a/features/roomdetails/impl/src/main/res/values-it/translations.xml
+++ b/features/roomdetails/impl/src/main/res/values-it/translations.xml
@@ -24,6 +24,8 @@
"Non potrai annullare questa modifica perché ti stai declassando, se sei l\'ultimo utente privilegiato nella stanza, sarà impossibile riottenere i privilegi."
"Declassare te stesso?"
"%1$s (In attesa)"
+ "(In attesa)"
+ "Gli amministratori hanno automaticamente i privilegi di moderatore"
"Modifica moderatori"
"Amministratori"
"Moderatori"
@@ -51,6 +53,7 @@
"Nome stanza"
"Sicurezza"
"Condividi stanza"
+ "Informazioni sulla stanza"
"Argomento"
"Aggiornamento della stanza…"
"Escludi"
diff --git a/features/roomdetails/impl/src/main/res/values-ka/translations.xml b/features/roomdetails/impl/src/main/res/values-ka/translations.xml
new file mode 100644
index 0000000000..75f7121b45
--- /dev/null
+++ b/features/roomdetails/impl/src/main/res/values-ka/translations.xml
@@ -0,0 +1,45 @@
+
+
+ "შეტყობინებების პარამეტრის განახლებისას მოხდა შეცდომა."
+ "ყველა"
+ "თემის დამატება"
+ "უკვე წევრია"
+ "უკვე მოწვეულია"
+ "ოთახის რედაქტირება"
+ "უცნობი შეცდომა მოხდა. ინფორმაციის შეცვლა ვერ მოხერხდა."
+ "ოთახის განახლება შეუძლებელია"
+ "შეტყობინებები დაცულია საკეტებით. მხოლოდ თქვენ და მიმღებებს გაქვთ მათი განშიფვრის უნიკალური გასაღებები."
+ "შეტყობინების დაშიფვრა ჩართულია"
+ "შეტყობინებების პარამეტრების ჩატვირთვისას მოხდა შეცდომა."
+ "ამ ოთახის დადუმება ვერ მოხერხდა. გთხოვთ, სცადოთ ხელახლა."
+ "ამ ოთახის დადუმების მოხსნა ვერ მოხერხდა. გთხოვთ, სცადოთ ხელახლა."
+ "ხალხის მოწვევა"
+ "ოთახის დატოვება"
+ "მორგებული"
+ "ნაგულისხმევი"
+ "შეტყობინებები"
+ "ოთახის სახელი"
+ "უსაფრთხოება"
+ "ოთახის გაზიარება"
+ "თემა"
+ "ოთახის განახლება…"
+
+ - "%1$d ადამიანი"
+ - "%1$d ადამიანი"
+
+ "მომლოდინე"
+ "ოთახის წევრები"
+ "მორგებული პარამეტრის დაშვება"
+ "ამის ჩართვა უგულებელყოფს თქვენს ნაგულისხმევ პარამეტრს"
+ "ამ ჩატში ჩემი შეტყობინება:"
+ "თქვენ შეგიძლიათ შეცვალოთ იგი თქვენს %1$s ."
+ "გლობალური პარამეტრები"
+ "Სტანდარტული პარამეტრები"
+ "მორგებული პარამეტრის წაშლა"
+ "შეტყობინებების პარამეტრების ჩატვირთვისას მოხდა შეცდომა."
+ "ნაგულისხმევი რეჟიმის აღდგენა ვერ მოხერხდა, გთხოვთ, სცადოთ ხელახლა."
+ "რეჟიმის დაყენება ვერ მოხერხდა, გთხოვთ, სცადოთ ხელახლა."
+ "ყველა შეტყობინება"
+ "მხოლოდ ხსენებები და საკვანძო სიტყვები"
+ "ამ ოთახში, შემატყობინეთ:"
+
diff --git a/features/roomdetails/impl/src/main/res/values-pt/translations.xml b/features/roomdetails/impl/src/main/res/values-pt/translations.xml
new file mode 100644
index 0000000000..dedc033298
--- /dev/null
+++ b/features/roomdetails/impl/src/main/res/values-pt/translations.xml
@@ -0,0 +1,116 @@
+
+
+ "Erro ao atualizar a configuração de notificação."
+ "O teu servidor não suporta esta opção em salas cifradas, pelo que poderás não ser notificado em algumas salas."
+ "Sondagens"
+ "Apenas administradores"
+ "Banir pessoas"
+ "Remover mensagens"
+ "Toda a gente"
+ "Convida pessoas"
+ "Moderação de participantes"
+ "Mensagens e conteúdo"
+ "Administradores e moderadores"
+ "Remover pessoas"
+ "Alterar o ícone da sala"
+ "Detalhes da sala"
+ "Altera o nome da sala"
+ "Alterar a descrição da sala"
+ "Enviar mensagens"
+ "Editar administradores"
+ "Não poderás desfazer esta ação. Estás a promover o utilizador para ter o mesmo nível de poder que tu."
+ "Adicionar administrador?"
+ "Despromover"
+ "Não poderás desfazer esta alteração, uma vez que te estás a despromover. Se fores o último utilizador privilegiado na sala, será impossível recuperar os privilégios."
+ "Despromover-te?"
+ "%1$s (pendente)"
+ "(pendente)"
+ "Os administradores têm automaticamente privilégios de moderador"
+ "Editar moderadores"
+ "Administradores"
+ "Moderadores"
+ "Participantes"
+ "Tens alterações por guardar."
+ "Guardar alterações?"
+ "Adicionar descrição"
+ "Já é participante"
+ "Já foi convidado"
+ "Cifrada"
+ "Não cifrada"
+ "Sala pública"
+ "Editar sala"
+ "Ocorreu um erro desconhecido e não foi possível alterar a informação."
+ "Não foi possível atualizar a sala"
+ "As mensagens são protegidas por cadeados. Apenas tu e os destinatários têm as chaves únicas para os desbloquear."
+ "Cifragem de mensagens ativada"
+ "Erro ao carregar as configurações de notificação."
+ "Não foi possível silenciar esta sala, por favor tenta novamente."
+ "Não foi possível dessilenciar esta sala, por favor tenta novamente."
+ "Convidar pessoas"
+ "Sair da conversa"
+ "Sair da sala"
+ "Personalizado"
+ "Predefinição"
+ "Notificações"
+ "Cargos e permissões"
+ "Nome da sala"
+ "Segurança"
+ "Partilhar sala"
+ "Informação da sala"
+ "Descrição"
+ "A atualizar sala…"
+ "Banir"
+ "Não poderão voltar a entrar nesta sala, mesmo se forem convidados."
+ "Tens a certeza que queres banir este participante?"
+ "Não há nenhum utilizador banido desta sala."
+ "A banir %1$s"
+
+ - "%1$d pessoa"
+ - "%1$d pessoas"
+
+ "Remover e banir participante"
+ "Remover da sala"
+ "Remover e banir"
+ "Remover apenas"
+ "Remover participante e proibir de se juntar no futuro?"
+ "Anular banimento"
+ "Poderão juntar-se novamente a esta sala se forem convidados."
+ "Anular banimento do utilizador"
+ "Ver perfil"
+ "Banidos"
+ "Participantes"
+ "Pendente"
+ "A remover %1$s…"
+ "Administrador"
+ "Moderador"
+ "Participantes"
+ "A anular banimento de %1$s"
+ "Permitir configuração personalizada"
+ "Ativar esta opção substitui a tua configuração predefinida"
+ "Nesta conversa, notifica-me se"
+ "Podes alterá-lo nas tuas %1$s."
+ "configurações globais"
+ "Predefinição"
+ "Remover configuração personalizada"
+ "Erro ao carregar as configurações de notificação."
+ "Falha ao restaurar o modo predefinido, tenta novamente."
+ "Falha ao definir o modo, tenta novamente."
+ "O teu servidor não suporta esta opção em salas cifradas, pelo que não serás notificado nesta sala."
+ "Todas as mensagens"
+ "Menções ou palavras-chave"
+ "Nesta sala, notifica-me se"
+ "Administradores"
+ "Alterar o meu cargo"
+ "Despromover para participante"
+ "Despromover para moderador"
+ "Moderação de participantes"
+ "Mensagens e conteúdo"
+ "Moderadores"
+ "Permissões"
+ "Repor permissões"
+ "Ao repores as permissões, perderás as configurações atuais."
+ "Repor as permissões?"
+ "Cargos"
+ "Detalhes da sala"
+ "Cargos e permissões"
+
diff --git a/features/roomdetails/impl/src/main/res/values-ro/translations.xml b/features/roomdetails/impl/src/main/res/values-ro/translations.xml
index ef8edf43be..05cd542f3b 100644
--- a/features/roomdetails/impl/src/main/res/values-ro/translations.xml
+++ b/features/roomdetails/impl/src/main/res/values-ro/translations.xml
@@ -3,11 +3,41 @@
"A apărut o eroare în timpul actualizării setărilor pentru notificari."
"Serverul dumneavoastră nu acceptă această opțiune în camerele criptate, este posibil să nu primiți notificări în unele camere."
"Sondaje"
+ "Doar administratori"
+ "Interziceți persoane"
+ "Eliminați mesaje"
"Toți"
+ "Invitați persoane"
+ "Moderarea membrilor"
+ "Mesaje și conținut"
+ "Administratori și moderatori"
+ "Îndepărtați persoane"
+ "Schimbați avatarul camerei"
+ "Detaliile camerei"
+ "Schimbă numele camerei"
+ "Schimbați subiectul camerei"
+ "Trimiteți mesaje"
+ "Editați administratorii"
+ "Promovați utilizatorul să aibă același nivel de putere ca dumneavoastră. Nu veți putea anula această acțiune."
+ "Adăugați administrator?"
+ "Retrogradare"
+ "Nu veți putea anula această modificare, deoarece vă retrogradați. Dacă sunteți ultimul utilizator privilegiat din cameră, va fi imposibil să recâștigați privilegiile."
+ "Vreți să vă retrogradați?"
+ "%1$s (În așteptare)"
+ "(În așteptare)"
+ "Administratorii au automat privilegii de moderator"
+ "Editați moderatorii"
+ "Administratori"
+ "Moderatori"
"Membri"
+ "Aveți modificări nesalvate."
+ "Salvați modificările?"
"Adăugare subiect"
"Deja membru"
"Deja invitat"
+ "Criptat"
+ "Necriptat"
+ "Cameră publică"
"Editați camera"
"A apărut o eroare la actualizarea detaliilor camerei"
"Nu s-a putut actualiza camera"
@@ -22,27 +52,39 @@
"Personalizat"
"Implicit"
"Notificări"
+ "Roluri și permisiuni"
"Numele camerei"
"Securitate"
"Partajați camera"
+ "Informatii camera"
"Subiect"
"Se actualizează camera…"
+ "Interzicere"
+ "Nu se vor putea alătura din nou acestei camere dacă sunt invitați."
+ "Sunteți sigur că doriți să interziceți acest membru?"
+ "Nu există utilizatori interziși în această cameră."
+ "Se interzice %1$s"
- "o persoană"
- "%1$d persoane"
+ "Eliminați și interziceți membrul"
"Înlăturați membrul"
"Înlăturați și interziceți membrul"
"Doar înlăturare"
"Înlăturați membrul și interziceți-i să se alăture în viitor?"
"Anulare excludere"
- "Vedeți informații despre utilizator"
+ "Se vor putea alătura din nou acestei săli dacă sunt invitați."
+ "Anulați interzicerea utilizatorului"
+ "Vizualizare profil"
"Excluși"
"Membri"
"În așteptare"
+ "Se elimină %1$s"
"Administrator"
"Moderator"
"Membrii camerei"
+ "Se anulează interzicerea lui %1$s"
"Permiteți setări personalizate"
"Activarea acestei opțiuni va anula setările implicite."
"Anunțați-mă în acestă cameră pentru"
@@ -57,4 +99,18 @@
"Toate mesajele"
"Numai mențiuni și cuvinte cheie"
"În această cameră, anunțați-mă pentru"
+ "Administratori"
+ "Schimbare rol"
+ "Degradare la membru"
+ "Degradare la moderator"
+ "Moderarea membrilor"
+ "Mesaje și conținut"
+ "Moderatori"
+ "Permisiuni"
+ "Resetați permisiunile"
+ "După ce resetați permisiunile, veți pierde setările curente."
+ "Resetați permisiunile?"
+ "Roluri"
+ "Detaliile camerei"
+ "Roluri și permisiuni"
diff --git a/features/roomdetails/impl/src/main/res/values-sk/translations.xml b/features/roomdetails/impl/src/main/res/values-sk/translations.xml
index 467ba5578a..c905333c2c 100644
--- a/features/roomdetails/impl/src/main/res/values-sk/translations.xml
+++ b/features/roomdetails/impl/src/main/res/values-sk/translations.xml
@@ -35,6 +35,9 @@
"Pridať tému"
"Už ste členom"
"Už ste pozvaní"
+ "Zašifrované"
+ "Nešifrované"
+ "Verejná miestnosť"
"Upraviť miestnosť"
"Vyskytla sa neznáma chyba a informácie nebolo možné zmeniť."
"Nepodarilo sa aktualizovať miestnosť"
diff --git a/features/roomdetails/impl/src/main/res/values-sv/translations.xml b/features/roomdetails/impl/src/main/res/values-sv/translations.xml
index b8161c4108..73f4f945a8 100644
--- a/features/roomdetails/impl/src/main/res/values-sv/translations.xml
+++ b/features/roomdetails/impl/src/main/res/values-sv/translations.xml
@@ -31,6 +31,8 @@
- "%1$d personer"
"Väntar"
+ "Admin"
+ "Moderator"
"Rumsmedlemmar"
"Tillåt anpassad inställning"
"Om du aktiverar detta åsidosätts din standardinställning"
diff --git a/features/roomdetails/impl/src/main/res/values-uk/translations.xml b/features/roomdetails/impl/src/main/res/values-uk/translations.xml
index e61a7052a3..b06ad30097 100644
--- a/features/roomdetails/impl/src/main/res/values-uk/translations.xml
+++ b/features/roomdetails/impl/src/main/res/values-uk/translations.xml
@@ -12,10 +12,10 @@
"Повідомлення та зміст"
"Адміністратори та модератори"
"Вилучати людей"
- "Змінити аватар кімнати"
+ "Змінювати аватар кімнати"
"Деталі кімнати"
- "Змінити назву кімнати"
- "Змінити тему кімнати"
+ "Змінювати назву кімнати"
+ "Змінювати тему кімнати"
"Надсилати повідомлення"
"Керувати адмінами"
"Ви не зможете скасувати цю дію. Ви просуваєте користувача, щоб він мав такий же рівень прав, як і ви."
@@ -74,7 +74,7 @@
"Заблоковані"
"Учасники"
"На розгляді"
- "Видаляємо %1$s…"
+ "Вилучаємо %1$s…"
"Адміністратор"
"Модератор"
"Учасники кімнати"
diff --git a/features/roomdetails/impl/src/main/res/values-zh/translations.xml b/features/roomdetails/impl/src/main/res/values-zh/translations.xml
new file mode 100644
index 0000000000..b4314fa71a
--- /dev/null
+++ b/features/roomdetails/impl/src/main/res/values-zh/translations.xml
@@ -0,0 +1,112 @@
+
+
+ "更新通知设置时出错。"
+ "您的服务器在加密房间中不支持此选项,因此在某些房间您可能无法收到通知。"
+ "投票"
+ "仅限管理员"
+ "封禁成员"
+ "移除消息"
+ "所有人"
+ "邀请成员"
+ "成员权限"
+ "消息和内容"
+ "管理员和协管员"
+ "移除成员"
+ "更改聊天室头像"
+ "聊天室详情"
+ "更改聊天室名称"
+ "更改聊天室话题"
+ "发送消息"
+ "编辑管理员"
+ "您将无法撤消此操作。您正在提升用户的权限,使其拥有与您平权。"
+ "添加管理员?"
+ "降级"
+ "由于您正在降级,您将无法撤消此更改。如果您是房间中的最后一个特权用户,则无法重新获得权限。"
+ "降级自己?"
+ "%1$s(待处理)"
+ "(已邀请)"
+ "管理员自动拥有协管员权限"
+ "编辑协管员"
+ "管理员"
+ "协管员"
+ "成员"
+ "您有未保存的更改。"
+ "保存更改?"
+ "添加主题"
+ "已经是成员"
+ "已邀请"
+ "编辑聊天室"
+ "出现未知错误,无法更改信息。"
+ "无法更新聊天室"
+ "你的消息受加密保护,并且只有你和消息接收者拥有唯一解密密钥。"
+ "消息加密已启用"
+ "加载通知设置时出错。"
+ "无法将此房间静音,请重试。"
+ "无法取消此房间的静音,请重试。"
+ "邀请朋友"
+ "离开聊天"
+ "离开房间"
+ "自定义"
+ "默认"
+ "通知"
+ "角色与权限"
+ "房间名称"
+ "安全"
+ "分享房间"
+ "聊天室信息"
+ "话题"
+ "正在更新房间……"
+ "封禁"
+ "即使受到邀请,他们也无法再次加入房间。"
+ "您确定要封禁该成员吗?"
+ "这个房间里没有被封禁的用户。"
+ "封禁 %1$s"
+
+ - "%1$d 人"
+
+ "移除并封禁成员"
+ "从房间移除"
+ "移除并封禁成员"
+ "仅移除成员"
+ "删除成员并禁止重新加入?"
+ "取消封禁"
+ "如果受到邀请,他们可以重新加入房间。"
+ "解封用户"
+ "查看个人资料"
+ "已封禁用户"
+ "成员"
+ "待处理"
+ "正在移除 %1$s……"
+ "管理员"
+ "协管员"
+ "聊天室成员"
+ "解除封禁 %1$s"
+ "允许自定义设置"
+ "开启此功能将覆盖您的默认设置"
+ "在此聊天中通知我以下内容"
+ "你可以在你的 %1$s 中更改这一项。"
+ "全局设置"
+ "默认设置"
+ "撤销独立设置"
+ "加载通知设置时出错。"
+ "恢复默认模式失败,请重试。"
+ "设置模式失败,请重试。"
+ "您的服务器在加密房间中不支持此选项,您无法在此房间收到通知。"
+ "所有消息"
+ "仅限提及和关键词"
+ "在这个聊天室,通知我:"
+ "管理员"
+ "更改我的角色"
+ "降级为成员"
+ "降级为协管员"
+ "成员权限"
+ "消息和内容"
+ "协管员"
+ "权限"
+ "重置权限"
+ "重置权限后,您将丢失当前设置。"
+ "重置权限?"
+ "角色"
+ "聊天室详情"
+ "角色与权限"
+
diff --git a/features/roomdetails/impl/src/test/kotlin/io/element/android/features/roomdetails/MatrixRoomFixture.kt b/features/roomdetails/impl/src/test/kotlin/io/element/android/features/roomdetails/MatrixRoomFixture.kt
new file mode 100644
index 0000000000..cffd2ae1f1
--- /dev/null
+++ b/features/roomdetails/impl/src/test/kotlin/io/element/android/features/roomdetails/MatrixRoomFixture.kt
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 2024 New Vector Ltd
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package io.element.android.features.roomdetails
+
+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.libraries.matrix.test.notificationsettings.FakeNotificationSettingsService
+import io.element.android.libraries.matrix.test.room.FakeMatrixRoom
+import io.element.android.libraries.matrix.test.room.aRoomInfo
+
+fun aMatrixRoom(
+ roomId: RoomId = A_ROOM_ID,
+ displayName: String = A_ROOM_NAME,
+ rawName: String? = displayName,
+ topic: String? = "A topic",
+ avatarUrl: String? = "https://matrix.org/avatar.jpg",
+ isEncrypted: Boolean = true,
+ isPublic: Boolean = true,
+ isDirect: Boolean = false,
+ notificationSettingsService: FakeNotificationSettingsService = FakeNotificationSettingsService(),
+ emitRoomInfo: Boolean = false,
+) = FakeMatrixRoom(
+ roomId = roomId,
+ displayName = displayName,
+ topic = topic,
+ avatarUrl = avatarUrl,
+ isEncrypted = isEncrypted,
+ isPublic = isPublic,
+ isDirect = isDirect,
+ notificationSettingsService = notificationSettingsService
+).apply {
+ if (emitRoomInfo) {
+ givenRoomInfo(
+ aRoomInfo(
+ name = displayName,
+ rawName = rawName,
+ topic = topic,
+ avatarUrl = avatarUrl,
+ isDirect = isDirect,
+ isPublic = isPublic,
+ )
+ )
+ }
+}
diff --git a/features/roomdetails/impl/src/test/kotlin/io/element/android/features/roomdetails/RoomDetailsPresenterTests.kt b/features/roomdetails/impl/src/test/kotlin/io/element/android/features/roomdetails/RoomDetailsPresenterTests.kt
index 998193690e..857422ca51 100644
--- a/features/roomdetails/impl/src/test/kotlin/io/element/android/features/roomdetails/RoomDetailsPresenterTests.kt
+++ b/features/roomdetails/impl/src/test/kotlin/io/element/android/features/roomdetails/RoomDetailsPresenterTests.kt
@@ -37,14 +37,11 @@ import io.element.android.features.roomdetails.impl.members.details.RoomMemberDe
import io.element.android.libraries.core.coroutine.CoroutineDispatchers
import io.element.android.libraries.featureflag.api.FeatureFlags
import io.element.android.libraries.featureflag.test.FakeFeatureFlagService
-import io.element.android.libraries.matrix.api.core.RoomId
import io.element.android.libraries.matrix.api.core.UserId
import io.element.android.libraries.matrix.api.room.MatrixRoom
import io.element.android.libraries.matrix.api.room.MatrixRoomMembersState
import io.element.android.libraries.matrix.api.room.RoomNotificationMode
import io.element.android.libraries.matrix.api.room.StateEventType
-import io.element.android.libraries.matrix.test.A_ROOM_ID
-import io.element.android.libraries.matrix.test.A_ROOM_NAME
import io.element.android.libraries.matrix.test.A_SESSION_ID
import io.element.android.libraries.matrix.test.A_USER_ID_2
import io.element.android.libraries.matrix.test.FakeMatrixClient
@@ -473,23 +470,3 @@ class RoomDetailsPresenterTests {
}
}
}
-
-fun aMatrixRoom(
- roomId: RoomId = A_ROOM_ID,
- displayName: String = A_ROOM_NAME,
- topic: String? = "A topic",
- avatarUrl: String? = "https://matrix.org/avatar.jpg",
- isEncrypted: Boolean = true,
- isPublic: Boolean = true,
- isDirect: Boolean = false,
- notificationSettingsService: FakeNotificationSettingsService = FakeNotificationSettingsService()
-) = FakeMatrixRoom(
- roomId = roomId,
- displayName = displayName,
- topic = topic,
- avatarUrl = avatarUrl,
- isEncrypted = isEncrypted,
- isPublic = isPublic,
- isDirect = isDirect,
- notificationSettingsService = notificationSettingsService
-)
diff --git a/features/roomdetails/impl/src/test/kotlin/io/element/android/features/roomdetails/edit/RoomDetailsEditPresenterTest.kt b/features/roomdetails/impl/src/test/kotlin/io/element/android/features/roomdetails/edit/RoomDetailsEditPresenterTest.kt
index 8b0dcd5b0a..f287fe4ab4 100644
--- a/features/roomdetails/impl/src/test/kotlin/io/element/android/features/roomdetails/edit/RoomDetailsEditPresenterTest.kt
+++ b/features/roomdetails/impl/src/test/kotlin/io/element/android/features/roomdetails/edit/RoomDetailsEditPresenterTest.kt
@@ -19,6 +19,7 @@ package io.element.android.features.roomdetails.edit
import android.net.Uri
import app.cash.molecule.RecompositionMode
import app.cash.molecule.moleculeFlow
+import app.cash.turbine.ReceiveTurbine
import app.cash.turbine.test
import com.google.common.truth.Truth.assertThat
import io.element.android.features.roomdetails.aMatrixRoom
@@ -28,6 +29,8 @@ import io.element.android.libraries.architecture.AsyncAction
import io.element.android.libraries.matrix.api.room.MatrixRoom
import io.element.android.libraries.matrix.api.room.StateEventType
import io.element.android.libraries.matrix.test.AN_AVATAR_URL
+import io.element.android.libraries.matrix.test.A_ROOM_NAME
+import io.element.android.libraries.matrix.test.A_ROOM_RAW_NAME
import io.element.android.libraries.matrix.ui.media.AvatarAction
import io.element.android.libraries.mediapickers.test.FakePickerProvider
import io.element.android.libraries.mediaupload.api.MediaUploadInfo
@@ -90,15 +93,19 @@ class RoomDetailsEditPresenterTest {
@Test
fun `present - initial state is created from room info`() = runTest {
- val room = aMatrixRoom(avatarUrl = AN_AVATAR_URL)
+ val room = aMatrixRoom(
+ avatarUrl = AN_AVATAR_URL,
+ displayName = A_ROOM_NAME,
+ rawName = A_ROOM_RAW_NAME,
+ emitRoomInfo = true,
+ )
val presenter = createRoomDetailsEditPresenter(room)
-
moleculeFlow(RecompositionMode.Immediate) {
presenter.present()
}.test {
- val initialState = awaitItem()
- assertThat(initialState.roomId).isEqualTo(room.roomId.value)
- assertThat(initialState.roomName).isEqualTo(room.displayName)
+ val initialState = awaitFirstItem()
+ assertThat(initialState.roomId).isEqualTo(room.roomId)
+ assertThat(initialState.roomRawName).isEqualTo(A_ROOM_RAW_NAME)
assertThat(initialState.roomAvatarUrl).isEqualTo(roomAvatarUri)
assertThat(initialState.roomTopic).isEqualTo(room.topic.orEmpty())
assertThat(initialState.avatarActions).containsExactly(
@@ -119,7 +126,6 @@ class RoomDetailsEditPresenterTest {
givenCanSendStateResult(StateEventType.ROOM_TOPIC, Result.failure(Throwable("Oops")))
}
val presenter = createRoomDetailsEditPresenter(room)
-
moleculeFlow(RecompositionMode.Immediate) {
presenter.present()
}.test {
@@ -128,7 +134,6 @@ class RoomDetailsEditPresenterTest {
assertThat(initialState.canChangeName).isFalse()
assertThat(initialState.canChangeAvatar).isFalse()
assertThat(initialState.canChangeTopic).isFalse()
-
// When the asynchronous check completes, the single field we can edit is true
val settledState = awaitItem()
assertThat(settledState.canChangeName).isTrue()
@@ -145,7 +150,6 @@ class RoomDetailsEditPresenterTest {
givenCanSendStateResult(StateEventType.ROOM_TOPIC, Result.failure(Throwable("Oops")))
}
val presenter = createRoomDetailsEditPresenter(room)
-
moleculeFlow(RecompositionMode.Immediate) {
presenter.present()
}.test {
@@ -154,7 +158,6 @@ class RoomDetailsEditPresenterTest {
assertThat(initialState.canChangeName).isFalse()
assertThat(initialState.canChangeAvatar).isFalse()
assertThat(initialState.canChangeTopic).isFalse()
-
// When the asynchronous check completes, the single field we can edit is true
val settledState = awaitItem()
assertThat(settledState.canChangeName).isFalse()
@@ -171,7 +174,6 @@ class RoomDetailsEditPresenterTest {
givenCanSendStateResult(StateEventType.ROOM_TOPIC, Result.success(true))
}
val presenter = createRoomDetailsEditPresenter(room)
-
moleculeFlow(RecompositionMode.Immediate) {
presenter.present()
}.test {
@@ -180,7 +182,6 @@ class RoomDetailsEditPresenterTest {
assertThat(initialState.canChangeName).isFalse()
assertThat(initialState.canChangeAvatar).isFalse()
assertThat(initialState.canChangeTopic).isFalse()
-
// When the asynchronous check completes, the single field we can edit is true
val settledState = awaitItem()
assertThat(settledState.canChangeName).isFalse()
@@ -191,42 +192,42 @@ class RoomDetailsEditPresenterTest {
@Test
fun `present - updates state in response to changes`() = runTest {
- val room = aMatrixRoom(topic = "My topic", displayName = "Name", avatarUrl = AN_AVATAR_URL)
+ val room = aMatrixRoom(
+ topic = "My topic",
+ displayName = "Name",
+ avatarUrl = AN_AVATAR_URL,
+ emitRoomInfo = true,
+ )
val presenter = createRoomDetailsEditPresenter(room)
-
moleculeFlow(RecompositionMode.Immediate) {
presenter.present()
}.test {
- val initialState = awaitItem()
+ val initialState = awaitFirstItem()
assertThat(initialState.roomTopic).isEqualTo("My topic")
- assertThat(initialState.roomName).isEqualTo("Name")
+ assertThat(initialState.roomRawName).isEqualTo("Name")
assertThat(initialState.roomAvatarUrl).isEqualTo(roomAvatarUri)
-
initialState.eventSink(RoomDetailsEditEvents.UpdateRoomName("Name II"))
awaitItem().apply {
assertThat(roomTopic).isEqualTo("My topic")
- assertThat(roomName).isEqualTo("Name II")
+ assertThat(roomRawName).isEqualTo("Name II")
assertThat(roomAvatarUrl).isEqualTo(roomAvatarUri)
}
-
initialState.eventSink(RoomDetailsEditEvents.UpdateRoomName("Name III"))
awaitItem().apply {
assertThat(roomTopic).isEqualTo("My topic")
- assertThat(roomName).isEqualTo("Name III")
+ assertThat(roomRawName).isEqualTo("Name III")
assertThat(roomAvatarUrl).isEqualTo(roomAvatarUri)
}
-
initialState.eventSink(RoomDetailsEditEvents.UpdateRoomTopic("Another topic"))
awaitItem().apply {
assertThat(roomTopic).isEqualTo("Another topic")
- assertThat(roomName).isEqualTo("Name III")
+ assertThat(roomRawName).isEqualTo("Name III")
assertThat(roomAvatarUrl).isEqualTo(roomAvatarUri)
}
-
initialState.eventSink(RoomDetailsEditEvents.HandleAvatarAction(AvatarAction.Remove))
awaitItem().apply {
assertThat(roomTopic).isEqualTo("Another topic")
- assertThat(roomName).isEqualTo("Name III")
+ assertThat(roomRawName).isEqualTo("Name III")
assertThat(roomAvatarUrl).isNull()
}
}
@@ -234,18 +235,19 @@ class RoomDetailsEditPresenterTest {
@Test
fun `present - obtains avatar uris from gallery`() = runTest {
- val room = aMatrixRoom(topic = "My topic", displayName = "Name", avatarUrl = AN_AVATAR_URL)
-
+ val room = aMatrixRoom(
+ topic = "My topic",
+ displayName = "Name",
+ avatarUrl = AN_AVATAR_URL,
+ emitRoomInfo = true,
+ )
fakePickerProvider.givenResult(anotherAvatarUri)
-
val presenter = createRoomDetailsEditPresenter(room)
-
moleculeFlow(RecompositionMode.Immediate) {
presenter.present()
}.test {
- val initialState = awaitItem()
+ val initialState = awaitFirstItem()
assertThat(initialState.roomAvatarUrl).isEqualTo(roomAvatarUri)
-
initialState.eventSink(RoomDetailsEditEvents.HandleAvatarAction(AvatarAction.ChoosePhoto))
awaitItem().apply {
assertThat(roomAvatarUrl).isEqualTo(anotherAvatarUri)
@@ -255,19 +257,22 @@ class RoomDetailsEditPresenterTest {
@Test
fun `present - obtains avatar uris from camera`() = runTest {
- val room = aMatrixRoom(topic = "My topic", displayName = "Name", avatarUrl = AN_AVATAR_URL)
-
+ val room = aMatrixRoom(
+ topic = "My topic",
+ displayName = "Name",
+ avatarUrl = AN_AVATAR_URL,
+ emitRoomInfo = true,
+ )
fakePickerProvider.givenResult(anotherAvatarUri)
val fakePermissionsPresenter = FakePermissionsPresenter()
val presenter = createRoomDetailsEditPresenter(
room = room,
permissionsPresenter = fakePermissionsPresenter,
)
-
moleculeFlow(RecompositionMode.Immediate) {
presenter.present()
}.test {
- val initialState = awaitItem()
+ val initialState = awaitFirstItem()
assertThat(initialState.roomAvatarUrl).isEqualTo(roomAvatarUri)
assertThat(initialState.cameraPermissionState.permissionGranted).isFalse()
initialState.eventSink(RoomDetailsEditEvents.HandleAvatarAction(AvatarAction.TakePhoto))
@@ -288,48 +293,44 @@ class RoomDetailsEditPresenterTest {
@Test
fun `present - updates save button state`() = runTest {
- val room = aMatrixRoom(topic = "My topic", displayName = "Name", avatarUrl = AN_AVATAR_URL)
-
+ val room = aMatrixRoom(
+ topic = "My topic",
+ displayName = "Name",
+ avatarUrl = AN_AVATAR_URL,
+ emitRoomInfo = true,
+ )
fakePickerProvider.givenResult(roomAvatarUri)
-
val presenter = createRoomDetailsEditPresenter(room)
-
moleculeFlow(RecompositionMode.Immediate) {
presenter.present()
}.test {
- val initialState = awaitItem()
+ val initialState = awaitFirstItem()
assertThat(initialState.saveButtonEnabled).isFalse()
-
// Once a change is made, the save button is enabled
initialState.eventSink(RoomDetailsEditEvents.UpdateRoomName("Name II"))
awaitItem().apply {
assertThat(saveButtonEnabled).isTrue()
}
-
// If it's reverted then the save disables again
initialState.eventSink(RoomDetailsEditEvents.UpdateRoomName("Name"))
awaitItem().apply {
assertThat(saveButtonEnabled).isFalse()
}
-
// Make a change...
initialState.eventSink(RoomDetailsEditEvents.UpdateRoomTopic("Another topic"))
awaitItem().apply {
assertThat(saveButtonEnabled).isTrue()
}
-
// Revert it...
initialState.eventSink(RoomDetailsEditEvents.UpdateRoomTopic("My topic"))
awaitItem().apply {
assertThat(saveButtonEnabled).isFalse()
}
-
// Make a change...
initialState.eventSink(RoomDetailsEditEvents.HandleAvatarAction(AvatarAction.Remove))
awaitItem().apply {
assertThat(saveButtonEnabled).isTrue()
}
-
// Revert it...
initialState.eventSink(RoomDetailsEditEvents.HandleAvatarAction(AvatarAction.ChoosePhoto))
awaitItem().apply {
@@ -340,48 +341,44 @@ class RoomDetailsEditPresenterTest {
@Test
fun `present - updates save button state when initial values are null`() = runTest {
- val room = aMatrixRoom(topic = null, displayName = "fallback", avatarUrl = null)
-
+ val room = aMatrixRoom(
+ topic = null,
+ displayName = "fallback",
+ avatarUrl = null,
+ emitRoomInfo = true,
+ )
fakePickerProvider.givenResult(roomAvatarUri)
-
val presenter = createRoomDetailsEditPresenter(room)
-
moleculeFlow(RecompositionMode.Immediate) {
presenter.present()
}.test {
- val initialState = awaitItem()
+ val initialState = awaitFirstItem()
assertThat(initialState.saveButtonEnabled).isFalse()
-
// Once a change is made, the save button is enabled
initialState.eventSink(RoomDetailsEditEvents.UpdateRoomName("Name II"))
awaitItem().apply {
assertThat(saveButtonEnabled).isTrue()
}
-
// If it's reverted then the save disables again
initialState.eventSink(RoomDetailsEditEvents.UpdateRoomName("fallback"))
awaitItem().apply {
assertThat(saveButtonEnabled).isFalse()
}
-
// Make a change...
initialState.eventSink(RoomDetailsEditEvents.UpdateRoomTopic("Another topic"))
awaitItem().apply {
assertThat(saveButtonEnabled).isTrue()
}
-
// Revert it...
initialState.eventSink(RoomDetailsEditEvents.UpdateRoomTopic(""))
awaitItem().apply {
assertThat(saveButtonEnabled).isFalse()
}
-
// Make a change...
initialState.eventSink(RoomDetailsEditEvents.HandleAvatarAction(AvatarAction.ChoosePhoto))
awaitItem().apply {
assertThat(saveButtonEnabled).isTrue()
}
-
// Revert it...
initialState.eventSink(RoomDetailsEditEvents.HandleAvatarAction(AvatarAction.Remove))
awaitItem().apply {
@@ -392,15 +389,17 @@ class RoomDetailsEditPresenterTest {
@Test
fun `present - save changes room details if different`() = runTest {
- val room = aMatrixRoom(topic = "My topic", displayName = "Name", avatarUrl = AN_AVATAR_URL)
-
+ val room = aMatrixRoom(
+ topic = "My topic",
+ displayName = "Name",
+ avatarUrl = AN_AVATAR_URL,
+ emitRoomInfo = true,
+ )
val presenter = createRoomDetailsEditPresenter(room)
-
moleculeFlow(RecompositionMode.Immediate) {
presenter.present()
}.test {
- val initialState = awaitItem()
-
+ val initialState = awaitFirstItem()
initialState.eventSink(RoomDetailsEditEvents.UpdateRoomName("New name"))
initialState.eventSink(RoomDetailsEditEvents.UpdateRoomTopic("New topic"))
initialState.eventSink(RoomDetailsEditEvents.HandleAvatarAction(AvatarAction.Remove))
@@ -410,31 +409,24 @@ class RoomDetailsEditPresenterTest {
assertThat(room.newTopic).isEqualTo("New topic")
assertThat(room.newAvatarData).isNull()
assertThat(room.removedAvatar).isTrue()
-
- cancelAndIgnoreRemainingEvents()
}
}
@Test
fun `present - save doesn't change room details if they're the same trimmed`() = runTest {
val room = aMatrixRoom(topic = "My topic", displayName = "Name", avatarUrl = AN_AVATAR_URL)
-
val presenter = createRoomDetailsEditPresenter(room)
-
moleculeFlow(RecompositionMode.Immediate) {
presenter.present()
}.test {
val initialState = awaitItem()
-
initialState.eventSink(RoomDetailsEditEvents.UpdateRoomName(" Name "))
initialState.eventSink(RoomDetailsEditEvents.UpdateRoomTopic(" My topic "))
initialState.eventSink(RoomDetailsEditEvents.Save)
-
assertThat(room.newName).isNull()
assertThat(room.newTopic).isNull()
assertThat(room.newAvatarData).isNull()
assertThat(room.removedAvatar).isFalse()
-
cancelAndIgnoreRemainingEvents()
}
}
@@ -442,22 +434,17 @@ class RoomDetailsEditPresenterTest {
@Test
fun `present - save doesn't change topic if it was unset and is now blank`() = runTest {
val room = aMatrixRoom(topic = null, displayName = "Name", avatarUrl = AN_AVATAR_URL)
-
val presenter = createRoomDetailsEditPresenter(room)
-
moleculeFlow(RecompositionMode.Immediate) {
presenter.present()
}.test {
val initialState = awaitItem()
-
initialState.eventSink(RoomDetailsEditEvents.UpdateRoomTopic(""))
initialState.eventSink(RoomDetailsEditEvents.Save)
-
assertThat(room.newName).isNull()
assertThat(room.newTopic).isNull()
assertThat(room.newAvatarData).isNull()
assertThat(room.removedAvatar).isFalse()
-
cancelAndIgnoreRemainingEvents()
}
}
@@ -465,22 +452,17 @@ class RoomDetailsEditPresenterTest {
@Test
fun `present - save doesn't change name if it's now empty`() = runTest {
val room = aMatrixRoom(topic = "My topic", displayName = "Name", avatarUrl = AN_AVATAR_URL)
-
val presenter = createRoomDetailsEditPresenter(room)
-
moleculeFlow(RecompositionMode.Immediate) {
presenter.present()
}.test {
val initialState = awaitItem()
-
initialState.eventSink(RoomDetailsEditEvents.UpdateRoomName(""))
initialState.eventSink(RoomDetailsEditEvents.Save)
-
assertThat(room.newName).isNull()
assertThat(room.newTopic).isNull()
assertThat(room.newAvatarData).isNull()
assertThat(room.removedAvatar).isFalse()
-
cancelAndIgnoreRemainingEvents()
}
}
@@ -488,20 +470,15 @@ class RoomDetailsEditPresenterTest {
@Test
fun `present - save processes and sets avatar when processor returns successfully`() = runTest {
val room = aMatrixRoom(topic = "My topic", displayName = "Name", avatarUrl = AN_AVATAR_URL)
-
givenPickerReturnsFile()
-
val presenter = createRoomDetailsEditPresenter(room)
-
moleculeFlow(RecompositionMode.Immediate) {
presenter.present()
}.test {
val initialState = awaitItem()
-
initialState.eventSink(RoomDetailsEditEvents.HandleAvatarAction(AvatarAction.ChoosePhoto))
initialState.eventSink(RoomDetailsEditEvents.Save)
skipItems(3)
-
assertThat(room.newName).isNull()
assertThat(room.newTopic).isNull()
assertThat(room.newAvatarData).isSameInstanceAs(fakeFileContents)
@@ -512,89 +489,92 @@ class RoomDetailsEditPresenterTest {
@Test
fun `present - save does not set avatar data if processor fails`() = runTest {
val room = aMatrixRoom(topic = "My topic", displayName = "Name", avatarUrl = AN_AVATAR_URL)
-
fakePickerProvider.givenResult(anotherAvatarUri)
fakeMediaPreProcessor.givenResult(Result.failure(Throwable("Oh no")))
-
val presenter = createRoomDetailsEditPresenter(room)
-
moleculeFlow(RecompositionMode.Immediate) {
presenter.present()
}.test {
val initialState = awaitItem()
-
initialState.eventSink(RoomDetailsEditEvents.HandleAvatarAction(AvatarAction.ChoosePhoto))
initialState.eventSink(RoomDetailsEditEvents.Save)
skipItems(2)
-
assertThat(room.newName).isNull()
assertThat(room.newTopic).isNull()
assertThat(room.newAvatarData).isNull()
assertThat(room.removedAvatar).isFalse()
-
assertThat(awaitItem().saveAction).isInstanceOf(AsyncAction.Failure::class.java)
}
}
@Test
fun `present - sets save action to failure if name update fails`() = runTest {
- val room = aMatrixRoom(topic = "My topic", displayName = "Name", avatarUrl = AN_AVATAR_URL).apply {
+ val room = aMatrixRoom(
+ topic = "My topic",
+ displayName = "Name",
+ avatarUrl = AN_AVATAR_URL,
+ emitRoomInfo = true,
+ ).apply {
givenSetNameResult(Result.failure(Throwable("!")))
}
-
saveAndAssertFailure(room, RoomDetailsEditEvents.UpdateRoomName("New name"))
}
@Test
fun `present - sets save action to failure if topic update fails`() = runTest {
- val room = aMatrixRoom(topic = "My topic", displayName = "Name", avatarUrl = AN_AVATAR_URL).apply {
+ val room = aMatrixRoom(
+ topic = "My topic",
+ displayName = "Name",
+ avatarUrl = AN_AVATAR_URL,
+ emitRoomInfo = true,
+ ).apply {
givenSetTopicResult(Result.failure(Throwable("!")))
}
-
saveAndAssertFailure(room, RoomDetailsEditEvents.UpdateRoomTopic("New topic"))
}
@Test
fun `present - sets save action to failure if removing avatar fails`() = runTest {
- val room = aMatrixRoom(topic = "My topic", displayName = "Name", avatarUrl = AN_AVATAR_URL).apply {
+ val room = aMatrixRoom(
+ topic = "My topic",
+ displayName = "Name",
+ avatarUrl = AN_AVATAR_URL,
+ emitRoomInfo = true,
+ ).apply {
givenRemoveAvatarResult(Result.failure(Throwable("!")))
}
-
saveAndAssertFailure(room, RoomDetailsEditEvents.HandleAvatarAction(AvatarAction.Remove))
}
@Test
fun `present - sets save action to failure if setting avatar fails`() = runTest {
givenPickerReturnsFile()
-
- val room = aMatrixRoom(topic = "My topic", displayName = "Name", avatarUrl = AN_AVATAR_URL).apply {
+ val room = aMatrixRoom(
+ topic = "My topic",
+ displayName = "Name",
+ avatarUrl = AN_AVATAR_URL,
+ emitRoomInfo = true,
+ ).apply {
givenUpdateAvatarResult(Result.failure(Throwable("!")))
}
-
saveAndAssertFailure(room, RoomDetailsEditEvents.HandleAvatarAction(AvatarAction.ChoosePhoto))
}
@Test
fun `present - CancelSaveChanges resets save action state`() = runTest {
givenPickerReturnsFile()
-
val room = aMatrixRoom(topic = "My topic", displayName = "Name", avatarUrl = AN_AVATAR_URL).apply {
givenSetTopicResult(Result.failure(Throwable("!")))
}
-
val presenter = createRoomDetailsEditPresenter(room)
-
moleculeFlow(RecompositionMode.Immediate) {
presenter.present()
}.test {
val initialState = awaitItem()
-
initialState.eventSink(RoomDetailsEditEvents.UpdateRoomTopic("foo"))
initialState.eventSink(RoomDetailsEditEvents.Save)
skipItems(2)
-
assertThat(awaitItem().saveAction).isInstanceOf(AsyncAction.Failure::class.java)
-
initialState.eventSink(RoomDetailsEditEvents.CancelSaveChanges)
assertThat(awaitItem().saveAction).isInstanceOf(AsyncAction.Uninitialized::class.java)
}
@@ -602,16 +582,13 @@ class RoomDetailsEditPresenterTest {
private suspend fun saveAndAssertFailure(room: MatrixRoom, event: RoomDetailsEditEvents) {
val presenter = createRoomDetailsEditPresenter(room)
-
moleculeFlow(RecompositionMode.Immediate) {
presenter.present()
}.test {
- val initialState = awaitItem()
-
+ val initialState = awaitFirstItem()
initialState.eventSink(event)
initialState.eventSink(RoomDetailsEditEvents.Save)
skipItems(1)
-
assertThat(awaitItem().saveAction).isInstanceOf(AsyncAction.Loading::class.java)
assertThat(awaitItem().saveAction).isInstanceOf(AsyncAction.Failure::class.java)
}
@@ -622,7 +599,6 @@ class RoomDetailsEditPresenterTest {
val processedFile: File = mockk {
every { readBytes() } returns fakeFileContents
}
-
fakePickerProvider.givenResult(anotherAvatarUri)
fakeMediaPreProcessor.givenResult(
Result.success(
@@ -638,3 +614,8 @@ class RoomDetailsEditPresenterTest {
private const val ANOTHER_AVATAR_URL = "example://camera/foo.jpg"
}
}
+
+private suspend fun ReceiveTurbine.awaitFirstItem(): T {
+ skipItems(2)
+ return awaitItem()
+}
diff --git a/features/roomdetails/impl/src/test/kotlin/io/element/android/features/roomdetails/edit/RoomDetailsEditViewTest.kt b/features/roomdetails/impl/src/test/kotlin/io/element/android/features/roomdetails/edit/RoomDetailsEditViewTest.kt
new file mode 100644
index 0000000000..4db2d9bb02
--- /dev/null
+++ b/features/roomdetails/impl/src/test/kotlin/io/element/android/features/roomdetails/edit/RoomDetailsEditViewTest.kt
@@ -0,0 +1,243 @@
+/*
+ * Copyright (c) 2024 New Vector Ltd
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package io.element.android.features.roomdetails.edit
+
+import androidx.activity.ComponentActivity
+import androidx.annotation.StringRes
+import androidx.compose.ui.test.assertHasClickAction
+import androidx.compose.ui.test.assertHasNoClickAction
+import androidx.compose.ui.test.hasTestTag
+import androidx.compose.ui.test.junit4.AndroidComposeTestRule
+import androidx.compose.ui.test.junit4.createAndroidComposeRule
+import androidx.compose.ui.test.onNodeWithText
+import androidx.compose.ui.test.performClick
+import androidx.compose.ui.test.performTextInput
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import io.element.android.features.roomdetails.impl.edit.RoomDetailsEditEvents
+import io.element.android.features.roomdetails.impl.edit.RoomDetailsEditState
+import io.element.android.features.roomdetails.impl.edit.RoomDetailsEditView
+import io.element.android.features.roomdetails.impl.edit.aRoomDetailsEditState
+import io.element.android.libraries.architecture.AsyncAction
+import io.element.android.libraries.matrix.ui.media.AvatarAction
+import io.element.android.libraries.testtags.TestTags
+import io.element.android.libraries.ui.strings.CommonStrings
+import io.element.android.tests.testutils.EnsureNeverCalled
+import io.element.android.tests.testutils.EventsRecorder
+import io.element.android.tests.testutils.clickOn
+import io.element.android.tests.testutils.ensureCalledOnce
+import io.element.android.tests.testutils.pressBack
+import org.junit.Ignore
+import org.junit.Rule
+import org.junit.Test
+import org.junit.rules.TestRule
+import org.junit.runner.RunWith
+
+@RunWith(AndroidJUnit4::class)
+class RoomDetailsEditViewTest {
+ @get:Rule val rule = createAndroidComposeRule()
+
+ @Test
+ fun `clicking on back invoke back callback`() {
+ val eventsRecorder = EventsRecorder(expectEvents = false)
+ ensureCalledOnce { callback ->
+ rule.setRoomDetailsEditView(
+ aRoomDetailsEditState(
+ eventSink = eventsRecorder
+ ),
+ onBackPressed = callback,
+ )
+ rule.pressBack()
+ }
+ }
+
+ @Test
+ fun `when edition is successful, the expected callback is invoked`() {
+ val eventsRecorder = EventsRecorder(expectEvents = false)
+ ensureCalledOnce { callback ->
+ rule.setRoomDetailsEditView(
+ aRoomDetailsEditState(
+ eventSink = eventsRecorder,
+ saveAction = AsyncAction.Success(Unit)
+ ),
+ onRoomEdited = callback,
+ )
+ }
+ }
+
+ @Test
+ fun `when name is changed, the expected Event is emitted`() {
+ val eventsRecorder = EventsRecorder()
+ rule.setRoomDetailsEditView(
+ aRoomDetailsEditState(
+ eventSink = eventsRecorder,
+ roomRawName = "Marketing",
+ ),
+ )
+ rule.onNodeWithText("Marketing").assertHasClickAction()
+ rule.onNodeWithText("Marketing").performTextInput("A")
+ eventsRecorder.assertSingle(RoomDetailsEditEvents.UpdateRoomName("AMarketing"))
+ }
+
+ @Test
+ fun `when user cannot change name, nothing happen`() {
+ val eventsRecorder = EventsRecorder(expectEvents = false)
+ rule.setRoomDetailsEditView(
+ aRoomDetailsEditState(
+ eventSink = eventsRecorder,
+ roomRawName = "Marketing",
+ canChangeName = false,
+ ),
+ )
+ rule.onNodeWithText("Marketing").assertHasNoClickAction()
+ }
+
+ @Test
+ fun `when topic is changed, the expected Event is emitted`() {
+ val eventsRecorder = EventsRecorder()
+ rule.setRoomDetailsEditView(
+ aRoomDetailsEditState(
+ eventSink = eventsRecorder,
+ roomTopic = "My Topic",
+ ),
+ )
+ rule.onNodeWithText("My Topic").assertHasClickAction()
+ rule.onNodeWithText("My Topic").performTextInput("A")
+ eventsRecorder.assertSingle(RoomDetailsEditEvents.UpdateRoomTopic("AMy Topic"))
+ }
+
+ @Test
+ fun `when user cannot change topic, nothing happen`() {
+ val eventsRecorder = EventsRecorder(expectEvents = false)
+ rule.setRoomDetailsEditView(
+ aRoomDetailsEditState(
+ eventSink = eventsRecorder,
+ roomTopic = "My Topic",
+ canChangeTopic = false,
+ ),
+ )
+ rule.onNodeWithText("My Topic").assertHasNoClickAction()
+ }
+
+ @Ignore("This test is failing because the bottom sheet does not open")
+ @Test
+ fun `when avatar is changed with action to take photo, the expected Event is emitted`() {
+ testAvatarChange(
+ stringActionRes = CommonStrings.action_take_photo,
+ expectedEvent = RoomDetailsEditEvents.HandleAvatarAction(AvatarAction.TakePhoto),
+ )
+ }
+
+ @Ignore("This test is failing because the bottom sheet does not open")
+ @Test
+ fun `when avatar is changed with action to choose photo, the expected Event is emitted`() {
+ testAvatarChange(
+ stringActionRes = CommonStrings.action_choose_photo,
+ expectedEvent = RoomDetailsEditEvents.HandleAvatarAction(AvatarAction.ChoosePhoto),
+ )
+ }
+
+ @Ignore("This test is failing because the bottom sheet does not open")
+ @Test
+ fun `when avatar is changed with action to remove photo, the expected Event is emitted`() {
+ testAvatarChange(
+ stringActionRes = CommonStrings.action_remove,
+ expectedEvent = RoomDetailsEditEvents.HandleAvatarAction(AvatarAction.Remove),
+ )
+ }
+
+ private fun testAvatarChange(
+ @StringRes stringActionRes: Int,
+ expectedEvent: RoomDetailsEditEvents.HandleAvatarAction,
+ ) {
+ val eventsRecorder = EventsRecorder()
+ rule.setRoomDetailsEditView(
+ aRoomDetailsEditState(
+ eventSink = eventsRecorder,
+ ),
+ )
+ // Open the bottom sheet
+ rule.onNode(hasTestTag(TestTags.editAvatar.value)).performClick()
+ rule.onNodeWithText(rule.activity.getString(stringActionRes)).assertExists()
+ rule.clickOn(stringActionRes)
+ eventsRecorder.assertSingle(expectedEvent)
+ }
+
+ @Test
+ fun `when user cannot change avatar, nothing happen`() {
+ val eventsRecorder = EventsRecorder(expectEvents = false)
+ rule.setRoomDetailsEditView(
+ aRoomDetailsEditState(
+ eventSink = eventsRecorder,
+ canChangeAvatar = false,
+ ),
+ )
+ rule.onNode(hasTestTag(TestTags.editAvatar.value)).performClick()
+ rule.onNodeWithText(rule.activity.getString(CommonStrings.action_take_photo)).assertDoesNotExist()
+ }
+
+ @Test
+ fun `when save is clicked, the expected Event is emitted`() {
+ val eventsRecorder = EventsRecorder()
+ rule.setRoomDetailsEditView(
+ aRoomDetailsEditState(
+ eventSink = eventsRecorder,
+ saveButtonEnabled = true,
+ ),
+ )
+ rule.clickOn(CommonStrings.action_save)
+ eventsRecorder.assertSingle(RoomDetailsEditEvents.Save)
+ }
+
+ @Test
+ fun `when save is clicked, but nothing need to be saved, nothing happens`() {
+ val eventsRecorder = EventsRecorder(expectEvents = false)
+ rule.setRoomDetailsEditView(
+ aRoomDetailsEditState(
+ eventSink = eventsRecorder,
+ saveButtonEnabled = false,
+ ),
+ )
+ rule.clickOn(CommonStrings.action_save)
+ }
+
+ @Test
+ fun `when error is shown, closing the dialog emit the expected Event`() {
+ val eventsRecorder = EventsRecorder()
+ rule.setRoomDetailsEditView(
+ aRoomDetailsEditState(
+ eventSink = eventsRecorder,
+ saveAction = AsyncAction.Failure(Throwable("Whelp")),
+ ),
+ )
+ rule.clickOn(CommonStrings.action_ok)
+ eventsRecorder.assertSingle(RoomDetailsEditEvents.CancelSaveChanges)
+ }
+}
+
+private fun AndroidComposeTestRule.setRoomDetailsEditView(
+ state: RoomDetailsEditState,
+ onBackPressed: () -> Unit = EnsureNeverCalled(),
+ onRoomEdited: () -> Unit = EnsureNeverCalled(),
+) {
+ setContent {
+ RoomDetailsEditView(
+ state = state,
+ onBackPressed = onBackPressed,
+ onRoomEdited = onRoomEdited,
+ )
+ }
+}
diff --git a/features/roomdirectory/api/src/main/kotlin/io/element/android/features/roomdirectory/api/RoomDirectoryEntryPoint.kt b/features/roomdirectory/api/src/main/kotlin/io/element/android/features/roomdirectory/api/RoomDirectoryEntryPoint.kt
index 4c90b82543..d72a7cbe17 100644
--- a/features/roomdirectory/api/src/main/kotlin/io/element/android/features/roomdirectory/api/RoomDirectoryEntryPoint.kt
+++ b/features/roomdirectory/api/src/main/kotlin/io/element/android/features/roomdirectory/api/RoomDirectoryEntryPoint.kt
@@ -20,7 +20,6 @@ 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.matrix.api.core.RoomId
interface RoomDirectoryEntryPoint : FeatureEntryPoint {
fun nodeBuilder(parentNode: Node, buildContext: BuildContext): NodeBuilder
@@ -31,7 +30,6 @@ interface RoomDirectoryEntryPoint : FeatureEntryPoint {
}
interface Callback : Plugin {
- fun onRoomJoined(roomId: RoomId)
fun onResultClicked(roomDescription: RoomDescription)
}
}
diff --git a/features/roomdirectory/impl/build.gradle.kts b/features/roomdirectory/impl/build.gradle.kts
index 49638ece40..71bfa5ff89 100644
--- a/features/roomdirectory/impl/build.gradle.kts
+++ b/features/roomdirectory/impl/build.gradle.kts
@@ -46,9 +46,11 @@ dependencies {
implementation(projects.libraries.designsystem)
implementation(projects.libraries.uiStrings)
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)
diff --git a/features/roomdirectory/impl/src/main/kotlin/io/element/android/features/roomdirectory/impl/root/RoomDirectoryEvents.kt b/features/roomdirectory/impl/src/main/kotlin/io/element/android/features/roomdirectory/impl/root/RoomDirectoryEvents.kt
index 37e0ffb3c6..f105a19c53 100644
--- a/features/roomdirectory/impl/src/main/kotlin/io/element/android/features/roomdirectory/impl/root/RoomDirectoryEvents.kt
+++ b/features/roomdirectory/impl/src/main/kotlin/io/element/android/features/roomdirectory/impl/root/RoomDirectoryEvents.kt
@@ -16,11 +16,7 @@
package io.element.android.features.roomdirectory.impl.root
-import io.element.android.libraries.matrix.api.core.RoomId
-
sealed interface RoomDirectoryEvents {
- data class JoinRoom(val roomId: RoomId) : RoomDirectoryEvents
data class Search(val query: String) : RoomDirectoryEvents
data object LoadMore : RoomDirectoryEvents
- data object JoinRoomDismissError : RoomDirectoryEvents
}
diff --git a/features/roomdirectory/impl/src/main/kotlin/io/element/android/features/roomdirectory/impl/root/RoomDirectoryNode.kt b/features/roomdirectory/impl/src/main/kotlin/io/element/android/features/roomdirectory/impl/root/RoomDirectoryNode.kt
index 32f9571d44..694febe571 100644
--- a/features/roomdirectory/impl/src/main/kotlin/io/element/android/features/roomdirectory/impl/root/RoomDirectoryNode.kt
+++ b/features/roomdirectory/impl/src/main/kotlin/io/element/android/features/roomdirectory/impl/root/RoomDirectoryNode.kt
@@ -28,7 +28,6 @@ import io.element.android.anvilannotations.ContributesNode
import io.element.android.features.roomdirectory.api.RoomDescription
import io.element.android.features.roomdirectory.api.RoomDirectoryEntryPoint
import io.element.android.libraries.di.SessionScope
-import io.element.android.libraries.matrix.api.core.RoomId
@ContributesNode(SessionScope::class)
class RoomDirectoryNode @AssistedInject constructor(
@@ -42,18 +41,11 @@ class RoomDirectoryNode @AssistedInject constructor(
}
}
- private fun onRoomJoined(roomId: RoomId) {
- plugins().forEach {
- it.onRoomJoined(roomId)
- }
- }
-
@Composable
override fun View(modifier: Modifier) {
val state = presenter.present()
RoomDirectoryView(
state = state,
- onRoomJoined = ::onRoomJoined,
onResultClicked = ::onResultClicked,
onBackPressed = ::navigateUp,
modifier = modifier
diff --git a/features/roomdirectory/impl/src/main/kotlin/io/element/android/features/roomdirectory/impl/root/RoomDirectoryPresenter.kt b/features/roomdirectory/impl/src/main/kotlin/io/element/android/features/roomdirectory/impl/root/RoomDirectoryPresenter.kt
index 4f9130613f..dad3616f0c 100644
--- a/features/roomdirectory/impl/src/main/kotlin/io/element/android/features/roomdirectory/impl/root/RoomDirectoryPresenter.kt
+++ b/features/roomdirectory/impl/src/main/kotlin/io/element/android/features/roomdirectory/impl/root/RoomDirectoryPresenter.kt
@@ -18,7 +18,6 @@ package io.element.android.features.roomdirectory.impl.root
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
-import androidx.compose.runtime.MutableState
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
@@ -26,27 +25,20 @@ import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.runtime.setValue
-import io.element.android.features.roomdirectory.impl.root.di.JoinRoom
import io.element.android.features.roomdirectory.impl.root.model.RoomDirectoryListState
import io.element.android.features.roomdirectory.impl.root.model.toFeatureModel
-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.CoroutineDispatchers
-import io.element.android.libraries.matrix.api.core.RoomId
import io.element.android.libraries.matrix.api.roomdirectory.RoomDirectoryList
import io.element.android.libraries.matrix.api.roomdirectory.RoomDirectoryService
import kotlinx.collections.immutable.toImmutableList
-import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.flowOn
import kotlinx.coroutines.flow.map
-import kotlinx.coroutines.launch
import javax.inject.Inject
class RoomDirectoryPresenter @Inject constructor(
private val dispatchers: CoroutineDispatchers,
- private val joinRoom: JoinRoom,
private val roomDirectoryService: RoomDirectoryService,
) : Presenter {
@Composable
@@ -62,9 +54,6 @@ class RoomDirectoryPresenter @Inject constructor(
roomDirectoryService.createRoomDirectoryList(coroutineScope)
}
val listState by roomDirectoryList.collectState()
- val joinRoomAction: MutableState> = remember {
- mutableStateOf(AsyncAction.Uninitialized)
- }
LaunchedEffect(searchQuery) {
if (searchQuery == null) return@LaunchedEffect
// cancel load more right away
@@ -87,12 +76,6 @@ class RoomDirectoryPresenter @Inject constructor(
is RoomDirectoryEvents.Search -> {
searchQuery = event.query
}
- is RoomDirectoryEvents.JoinRoom -> {
- coroutineScope.joinRoom(joinRoomAction, event.roomId)
- }
- RoomDirectoryEvents.JoinRoomDismissError -> {
- joinRoomAction.value = AsyncAction.Uninitialized
- }
}
}
@@ -100,18 +83,10 @@ class RoomDirectoryPresenter @Inject constructor(
query = searchQuery.orEmpty(),
roomDescriptions = listState.items,
displayLoadMoreIndicator = listState.hasMoreToLoad,
- joinRoomAction = joinRoomAction.value,
eventSink = ::handleEvents
)
}
- private fun CoroutineScope.joinRoom(state: MutableState>, roomId: RoomId) = launch {
- state.runUpdatingState {
- joinRoom(roomId)
- .map { roomId }
- }
- }
-
@Composable
private fun RoomDirectoryList.collectState() = remember {
state.map {
diff --git a/features/roomdirectory/impl/src/main/kotlin/io/element/android/features/roomdirectory/impl/root/RoomDirectoryState.kt b/features/roomdirectory/impl/src/main/kotlin/io/element/android/features/roomdirectory/impl/root/RoomDirectoryState.kt
index 526139338d..0488757f0b 100644
--- a/features/roomdirectory/impl/src/main/kotlin/io/element/android/features/roomdirectory/impl/root/RoomDirectoryState.kt
+++ b/features/roomdirectory/impl/src/main/kotlin/io/element/android/features/roomdirectory/impl/root/RoomDirectoryState.kt
@@ -17,15 +17,12 @@
package io.element.android.features.roomdirectory.impl.root
import io.element.android.features.roomdirectory.api.RoomDescription
-import io.element.android.libraries.architecture.AsyncAction
-import io.element.android.libraries.matrix.api.core.RoomId
import kotlinx.collections.immutable.ImmutableList
data class RoomDirectoryState(
val query: String,
val roomDescriptions: ImmutableList,
val displayLoadMoreIndicator: Boolean,
- val joinRoomAction: AsyncAction,
val eventSink: (RoomDirectoryEvents) -> Unit
) {
val displayEmptyState = roomDescriptions.isEmpty() && !displayLoadMoreIndicator
diff --git a/features/roomdirectory/impl/src/main/kotlin/io/element/android/features/roomdirectory/impl/root/RoomDirectoryStateProvider.kt b/features/roomdirectory/impl/src/main/kotlin/io/element/android/features/roomdirectory/impl/root/RoomDirectoryStateProvider.kt
index bf682fc15b..42acefa534 100644
--- a/features/roomdirectory/impl/src/main/kotlin/io/element/android/features/roomdirectory/impl/root/RoomDirectoryStateProvider.kt
+++ b/features/roomdirectory/impl/src/main/kotlin/io/element/android/features/roomdirectory/impl/root/RoomDirectoryStateProvider.kt
@@ -18,7 +18,6 @@ package io.element.android.features.roomdirectory.impl.root
import androidx.compose.ui.tooling.preview.PreviewParameterProvider
import io.element.android.features.roomdirectory.api.RoomDescription
-import io.element.android.libraries.architecture.AsyncAction
import io.element.android.libraries.matrix.api.core.RoomAlias
import io.element.android.libraries.matrix.api.core.RoomId
import kotlinx.collections.immutable.ImmutableList
@@ -37,16 +36,6 @@ open class RoomDirectoryStateProvider : PreviewParameterProvider = persistentListOf(),
- joinRoomAction: AsyncAction = AsyncAction.Uninitialized,
eventSink: (RoomDirectoryEvents) -> Unit = {},
) = RoomDirectoryState(
query = query,
roomDescriptions = roomDescriptions,
displayLoadMoreIndicator = displayLoadMoreIndicator,
- joinRoomAction = joinRoomAction,
eventSink = eventSink,
)
diff --git a/features/roomdirectory/impl/src/main/kotlin/io/element/android/features/roomdirectory/impl/root/RoomDirectoryView.kt b/features/roomdirectory/impl/src/main/kotlin/io/element/android/features/roomdirectory/impl/root/RoomDirectoryView.kt
index a79f0d6e70..6cecb61368 100644
--- a/features/roomdirectory/impl/src/main/kotlin/io/element/android/features/roomdirectory/impl/root/RoomDirectoryView.kt
+++ b/features/roomdirectory/impl/src/main/kotlin/io/element/android/features/roomdirectory/impl/root/RoomDirectoryView.kt
@@ -47,7 +47,6 @@ import io.element.android.compound.theme.ElementTheme
import io.element.android.compound.tokens.generated.CompoundIcons
import io.element.android.features.roomdirectory.api.RoomDescription
import io.element.android.features.roomdirectory.impl.R
-import io.element.android.libraries.designsystem.components.async.AsyncActionView
import io.element.android.libraries.designsystem.components.avatar.Avatar
import io.element.android.libraries.designsystem.components.avatar.AvatarSize
import io.element.android.libraries.designsystem.components.button.BackButton
@@ -61,7 +60,6 @@ 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.TextField
import io.element.android.libraries.designsystem.theme.components.TopAppBar
-import io.element.android.libraries.matrix.api.core.RoomId
import io.element.android.libraries.testtags.TestTags
import io.element.android.libraries.ui.strings.CommonStrings
import kotlinx.collections.immutable.ImmutableList
@@ -70,7 +68,6 @@ import kotlinx.collections.immutable.ImmutableList
fun RoomDirectoryView(
state: RoomDirectoryState,
onResultClicked: (RoomDescription) -> Unit,
- onRoomJoined: (RoomId) -> Unit,
onBackPressed: () -> Unit,
modifier: Modifier = Modifier,
) {
@@ -84,21 +81,11 @@ fun RoomDirectoryView(
state = state,
onResultClicked = onResultClicked,
modifier = Modifier
- .padding(padding)
- .consumeWindowInsets(padding)
+ .padding(padding)
+ .consumeWindowInsets(padding)
)
}
)
- AsyncActionView(
- async = state.joinRoomAction,
- onSuccess = onRoomJoined,
- onErrorDismiss = {
- state.eventSink(RoomDirectoryEvents.JoinRoomDismissError)
- },
- errorMessage = {
- stringResource(id = CommonStrings.error_unknown)
- }
- )
}
@OptIn(ExperimentalMaterial3Api::class)
@@ -186,10 +173,10 @@ private fun RoomDirectoryRoomList(
@Composable
private fun LoadMoreIndicator(modifier: Modifier = Modifier) {
Box(
- modifier
- .fillMaxWidth()
- .wrapContentHeight()
- .padding(24.dp),
+ modifier = modifier
+ .fillMaxWidth()
+ .wrapContentHeight()
+ .padding(24.dp),
contentAlignment = Alignment.Center,
) {
CircularProgressIndicator(
@@ -259,14 +246,14 @@ private fun RoomDirectoryRoomRow(
) {
Row(
modifier = modifier
- .fillMaxWidth()
- .clickable(onClick = onClick)
- .padding(
- top = 12.dp,
- bottom = 12.dp,
- start = 16.dp,
- )
- .height(IntrinsicSize.Min),
+ .fillMaxWidth()
+ .clickable(onClick = onClick)
+ .padding(
+ top = 12.dp,
+ bottom = 12.dp,
+ start = 16.dp,
+ )
+ .height(IntrinsicSize.Min),
) {
Avatar(
avatarData = roomDescription.avatarData(AvatarSize.RoomDirectoryItem),
@@ -274,8 +261,8 @@ private fun RoomDirectoryRoomRow(
)
Column(
modifier = Modifier
- .weight(1f)
- .padding(horizontal = 16.dp)
+ .weight(1f)
+ .padding(horizontal = 16.dp)
) {
Text(
text = roomDescription.computedName,
@@ -301,7 +288,6 @@ internal fun RoomDirectoryViewPreview(@PreviewParameter(RoomDirectoryStateProvid
RoomDirectoryView(
state = state,
onResultClicked = {},
- onRoomJoined = {},
onBackPressed = {},
)
}
diff --git a/features/roomdirectory/impl/src/main/res/values-pt/translations.xml b/features/roomdirectory/impl/src/main/res/values-pt/translations.xml
new file mode 100644
index 0000000000..a6a24f3dbd
--- /dev/null
+++ b/features/roomdirectory/impl/src/main/res/values-pt/translations.xml
@@ -0,0 +1,5 @@
+
+
+ "Falha ao carregar"
+ "Diretório de salas"
+
diff --git a/features/roomdirectory/impl/src/main/res/values-ro/translations.xml b/features/roomdirectory/impl/src/main/res/values-ro/translations.xml
new file mode 100644
index 0000000000..c996f87f8a
--- /dev/null
+++ b/features/roomdirectory/impl/src/main/res/values-ro/translations.xml
@@ -0,0 +1,5 @@
+
+
+ "Încărcare eșuată"
+ "Director de camere"
+
diff --git a/features/roomdirectory/impl/src/main/res/values-zh/translations.xml b/features/roomdirectory/impl/src/main/res/values-zh/translations.xml
new file mode 100644
index 0000000000..705b8e353f
--- /dev/null
+++ b/features/roomdirectory/impl/src/main/res/values-zh/translations.xml
@@ -0,0 +1,5 @@
+
+
+ "加载失败"
+ "房间目录"
+
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 3af102146b..87cb8b8c5d 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
@@ -17,12 +17,8 @@
package io.element.android.features.roomdirectory.impl.root
import com.google.common.truth.Truth.assertThat
-import io.element.android.features.roomdirectory.impl.root.di.JoinRoom
-import io.element.android.libraries.architecture.AsyncAction
-import io.element.android.libraries.matrix.api.core.RoomId
import io.element.android.libraries.matrix.api.roomdirectory.RoomDirectoryList
import io.element.android.libraries.matrix.api.roomdirectory.RoomDirectoryService
-import io.element.android.libraries.matrix.test.A_ROOM_ID
import io.element.android.libraries.matrix.test.roomdirectory.FakeRoomDirectoryList
import io.element.android.libraries.matrix.test.roomdirectory.FakeRoomDirectoryService
import io.element.android.libraries.matrix.test.roomdirectory.aRoomDescription
@@ -47,7 +43,6 @@ import org.junit.Test
val initialState = awaitItem()
assertThat(initialState.query).isEmpty()
assertThat(initialState.displayEmptyState).isFalse()
- assertThat(initialState.joinRoomAction).isEqualTo(AsyncAction.Uninitialized)
assertThat(initialState.roomDescriptions).isEmpty()
assertThat(initialState.displayLoadMoreIndicator).isTrue()
}
@@ -136,46 +131,13 @@ import org.junit.Test
.withNoParameter()
}
- @Test
- fun `present - emit join room event`() = runTest {
- val joinRoomSuccess = lambdaRecorder { _: RoomId ->
- Result.success(Unit)
- }
- val joinRoomFailure = lambdaRecorder { roomId: RoomId ->
- Result.failure(RuntimeException("Failed to join room $roomId"))
- }
- val fakeJoinRoom = FakeJoinRoom(joinRoomSuccess)
- val presenter = createRoomDirectoryPresenter(joinRoom = fakeJoinRoom)
- presenter.test {
- awaitItem().also { state ->
- state.eventSink(RoomDirectoryEvents.JoinRoom(A_ROOM_ID))
- }
- awaitItem().also { state ->
- assertThat(state.joinRoomAction).isEqualTo(AsyncAction.Success(A_ROOM_ID))
- fakeJoinRoom.lambda = joinRoomFailure
- state.eventSink(RoomDirectoryEvents.JoinRoom(A_ROOM_ID))
- }
- awaitItem().also { state ->
- assertThat(state.joinRoomAction).isInstanceOf(AsyncAction.Failure::class.java)
- }
- }
- assert(joinRoomSuccess)
- .isCalledOnce()
- .with(value(A_ROOM_ID))
- assert(joinRoomFailure)
- .isCalledOnce()
- .with(value(A_ROOM_ID))
- }
-
private fun TestScope.createRoomDirectoryPresenter(
roomDirectoryService: RoomDirectoryService = FakeRoomDirectoryService(
createRoomDirectoryListFactory = { FakeRoomDirectoryList() }
),
- joinRoom: JoinRoom = FakeJoinRoom { Result.success(Unit) },
): RoomDirectoryPresenter {
return RoomDirectoryPresenter(
dispatchers = testCoroutineDispatchers(),
- joinRoom = joinRoom,
roomDirectoryService = roomDirectoryService,
)
}
diff --git a/features/roomdirectory/impl/src/test/kotlin/io/element/android/features/roomdirectory/impl/root/RoomDirectoryViewTest.kt b/features/roomdirectory/impl/src/test/kotlin/io/element/android/features/roomdirectory/impl/root/RoomDirectoryViewTest.kt
index 2535f6f421..7fc9e7bb55 100644
--- a/features/roomdirectory/impl/src/test/kotlin/io/element/android/features/roomdirectory/impl/root/RoomDirectoryViewTest.kt
+++ b/features/roomdirectory/impl/src/test/kotlin/io/element/android/features/roomdirectory/impl/root/RoomDirectoryViewTest.kt
@@ -25,8 +25,6 @@ import androidx.compose.ui.test.performClick
import androidx.compose.ui.test.performTextInput
import androidx.test.ext.junit.runners.AndroidJUnit4
import io.element.android.features.roomdirectory.api.RoomDescription
-import io.element.android.libraries.architecture.AsyncAction
-import io.element.android.libraries.matrix.api.core.RoomId
import io.element.android.libraries.testtags.TestTags
import io.element.android.tests.testutils.EnsureNeverCalled
import io.element.android.tests.testutils.EnsureNeverCalledWithParam
@@ -82,37 +80,17 @@ class RoomDirectoryViewTest {
rule.setRoomDirectoryView(state = state)
eventsRecorder.assertSingle(RoomDirectoryEvents.LoadMore)
}
-
- @Test
- fun `when joining room with success then onRoomJoined lambda is called once`() {
- val eventsRecorder = EventsRecorder(expectEvents = false)
- val roomDescriptions = aRoomDescriptionList()
- val joinedRoomId = roomDescriptions.first().roomId
- val state = aRoomDirectoryState(
- joinRoomAction = AsyncAction.Success(joinedRoomId),
- roomDescriptions = roomDescriptions,
- eventSink = eventsRecorder,
- )
- ensureCalledOnceWithParam(joinedRoomId) { callback ->
- rule.setRoomDirectoryView(
- state = state,
- onRoomJoined = callback,
- )
- }
- }
}
private fun AndroidComposeTestRule.setRoomDirectoryView(
state: RoomDirectoryState,
onBackPressed: () -> Unit = EnsureNeverCalled(),
onResultClicked: (RoomDescription) -> Unit = EnsureNeverCalledWithParam(),
- onRoomJoined: (RoomId) -> Unit = EnsureNeverCalledWithParam(),
) {
setContent {
RoomDirectoryView(
state = state,
onResultClicked = onResultClicked,
- onRoomJoined = onRoomJoined,
onBackPressed = onBackPressed,
)
}
diff --git a/features/roomlist/impl/src/main/res/values-es/translations.xml b/features/roomlist/impl/src/main/res/values-es/translations.xml
index 3873c335c5..0c3e47822d 100644
--- a/features/roomlist/impl/src/main/res/values-es/translations.xml
+++ b/features/roomlist/impl/src/main/res/values-es/translations.xml
@@ -13,8 +13,23 @@
"Crear una nueva conversación o sala"
"Empieza enviando un mensaje a alguien."
"Aún no hay chats."
+ "Favoritos"
+ "Puedes añadir un chat a tus favoritos en la configuración del chat.
+Por ahora, puedes deseleccionar los filtros para ver tus otros chats"
+ "Aún no tienes chats favoritos"
+ "Prioridad baja"
+ "Puedes deseleccionar filtros para ver tus otros chats."
+ "No tienes chats para esta selección"
"Personas"
+ "Todavía no tienes ningún mensaje directo"
+ "Salas"
+ "Todavía no estás en ninguna sala"
+ "No leídos"
+ "¡Felicidades!
+¡No tienes ningún mensaje sin leer!"
"Todos los chats"
+ "Marcar como leído"
+ "Marcar como no leído"
"Parece que estás usando un nuevo dispositivo. Verifica que eres tú para acceder a tus mensajes cifrados."
"Verifica que eres tú"
diff --git a/features/roomlist/impl/src/main/res/values-it/translations.xml b/features/roomlist/impl/src/main/res/values-it/translations.xml
index 349057e7c4..c44dbd07db 100644
--- a/features/roomlist/impl/src/main/res/values-it/translations.xml
+++ b/features/roomlist/impl/src/main/res/values-it/translations.xml
@@ -17,6 +17,8 @@
"Puoi aggiungere una conversazione ai tuoi preferiti nelle impostazioni della stessa.
Per il momento, puoi deselezionare i filtri per vedere le altre conversazioni."
"Non hai ancora conversazioni preferite"
+ "Inviti"
+ "Non hai nessun invito in sospeso."
"Bassa priorità"
"Puoi deselezionare i filtri per vedere le altre conversazioni."
"Non hai conversazioni per questa selezione"
diff --git a/features/roomlist/impl/src/main/res/values-ka/translations.xml b/features/roomlist/impl/src/main/res/values-ka/translations.xml
new file mode 100644
index 0000000000..de6358f443
--- /dev/null
+++ b/features/roomlist/impl/src/main/res/values-ka/translations.xml
@@ -0,0 +1,18 @@
+
+
+ "დარწმუნებული ხართ, რომ გსურთ, უარი თქვათ მოწვევაზე %1$s-ში?"
+ "მოწვევაზე უარის თქმა"
+ "დარწმუნებული ხართ, რომ გსურთ, უარი თქვათ ჩატზე %1$s-თან?"
+ "ჩატზე უარის თქვა"
+ "მოწვევები არ არის"
+ "%1$s (%2$s) მოგიწვიათ"
+ "ეს არის ერთჯერადი პროცესი, მადლობა ლოდინისთვის."
+ "თქვენი ანგარიშის კონფიგურაცია"
+ "ახალი საუბრისა ან ოთახის შექმნა"
+ "დაიწყეთ ვინმესთვის შეტყობინების გაგზავნით."
+ "არც ერთი ჩატი ჯერ არაა."
+ "ხალხი"
+ "ჩატები"
+ "როგორც ჩანს, ახალ მოწყობილობას იყენებთ. დაადასტურეთ სხვა მოწყობილობით თქვენს დაშიფრულ შეტყობინებებზე წვდომისთვის."
+ "დაადასტურეთ, რომ ეს თქვენ ხართ"
+
diff --git a/features/roomlist/impl/src/main/res/values-pt/translations.xml b/features/roomlist/impl/src/main/res/values-pt/translations.xml
new file mode 100644
index 0000000000..2bb094c693
--- /dev/null
+++ b/features/roomlist/impl/src/main/res/values-pt/translations.xml
@@ -0,0 +1,38 @@
+
+
+ "A tua cópia de segurança das conversas está atualmente dessincronizada. Tens de inserir a tua chave de recuperação para manteres o acesso à cópia."
+ "Insere a tua chave de recuperação"
+ "Tens a certeza que queres rejeitar o convite para %1$s?"
+ "Rejeitar conite"
+ "Tens a certeza que queres rejeitar esta conversa privada com %1$s?"
+ "Rejeitar conversa"
+ "Sem convites"
+ "%1$s (%2$s) convidou-te"
+ "Este processo só acontece uma única vez, obrigado por esperares."
+ "A configurar a tua conta…"
+ "Criar uma nova conversa ou sala"
+ "Começa por enviar uma mensagem a alguém."
+ "Ainda não tens conversas."
+ "Favoritas"
+ "Podes adicionar uma conversa às tuas favoritas nas suas configurações.
+Por enquanto, podes anular a seleção dos filtros para veres as tuas outras conversas"
+ "Ainda não tens nenhuma conversa favorita"
+ "Convites"
+ "Não tens nenhum convite pendente."
+ "Prioridade baixa"
+ "Podes anular a seleção dos filtros para veres as tuas outras conversas"
+ "Não tens nenhuma conversa selecionada"
+ "Pessoas"
+ "Ainda não tens nenhuma MD (mensagem direta)"
+ "Salas"
+ "Ainda não estás em nenhuma sala"
+ "Por ler"
+ "Parabéns!
+Não tens nenhuma mensagem por ler!"
+ "Conversas"
+ "Marcar como lida"
+ "Marcar como não lida"
+ "Consultar lista completa de salas"
+ "Parece que estás a utilizar um novo dispositivo. Verifica-o com um outro para poderes aceder às tuas mensagens cifradas."
+ "Verifica que és tu"
+
diff --git a/features/roomlist/impl/src/main/res/values-ro/translations.xml b/features/roomlist/impl/src/main/res/values-ro/translations.xml
index b766caf8f0..a4e250070e 100644
--- a/features/roomlist/impl/src/main/res/values-ro/translations.xml
+++ b/features/roomlist/impl/src/main/res/values-ro/translations.xml
@@ -14,13 +14,25 @@
"Începeți prin a trimite mesaje cuiva."
"Nu există încă discuții."
"Favorite"
+ "Puteți adăuga un chat la preferințele dvs. în setările de chat.
+Deocamdată, puteți deselecta filtrele pentru a vedea celelalte chat-uri"
+ "Încă nu aveți conversații preferate"
+ "Invitații"
+ "Nu aveți invitații în așteptare."
"Prioritate scăzută"
+ "Puteți deselecta filtrele pentru a vedea celelalte chat-uri"
+ "Nu aveți chat-uri pentru această selecție"
"Persoane"
+ "Încă nu aveți DM-uri"
"Camere"
+ "Nu sunteți încă în nicio cameră"
"Necitite"
+ "Felicitari!
+Nu aveți mesaje necitite!"
"Toate conversatiile"
"Marcați ca citită"
"Marcați ca necitită"
+ "Răsfoiți toate camerele"
"Se pare că folosiți un dispozitiv nou. Verificați-vă identitatea cu un alt dispozitiv pentru a accesa mesajele dumneavoastră criptate."
"Verificați că sunteți dumneavoastră"
diff --git a/features/roomlist/impl/src/main/res/values-zh/translations.xml b/features/roomlist/impl/src/main/res/values-zh/translations.xml
new file mode 100644
index 0000000000..0fa5542b5d
--- /dev/null
+++ b/features/roomlist/impl/src/main/res/values-zh/translations.xml
@@ -0,0 +1,38 @@
+
+
+ "您的聊天备份当前不同步。您需要输入恢复密钥才能访问聊天备份。"
+ "输入您的恢复密钥"
+ "您确定要拒绝加入 %1$s 的邀请吗?"
+ "拒绝邀请"
+ "您确定要拒绝与 %1$s 开始私聊吗?"
+ "拒绝聊天"
+ "没有邀请"
+ "%1$s (%2$s)邀请了你"
+ "这是一个一次性的过程,感谢您的等待。"
+ "设置您的账户。"
+ "创建新的对话或聊天室"
+ "通过向某人发送消息来开始。"
+ "还没有聊天。"
+ "收藏夹"
+ "您可以在聊天设置中将聊天添加到收藏夹中。
+现在,你可以取消选择过滤器以查看你的其他对话。"
+ "您未收藏任何聊天"
+ "邀请"
+ "你没有任何待处理的邀请。"
+ "低优先级"
+ "您可以取消选择过滤器以查看其他对话"
+ "您没有关于此选项的聊天"
+ "人"
+ "目前您还没有私信"
+ "聊天室"
+ "您尚未进入任何聊天室"
+ "未读"
+ "恭喜!
+你没有任何未读消息!"
+ "全部聊天"
+ "标记为已读"
+ "标记为未读"
+ "浏览所有房间"
+ "您似乎正在使用新设备。使用另一台设备进行验证以访问您的加密消息。"
+ "验证是你本人"
+
diff --git a/features/roomlist/impl/src/test/kotlin/io/element/android/features/roomlist/impl/RoomListPresenterTests.kt b/features/roomlist/impl/src/test/kotlin/io/element/android/features/roomlist/impl/RoomListPresenterTests.kt
index 053b4e51a8..e682e6608d 100644
--- a/features/roomlist/impl/src/test/kotlin/io/element/android/features/roomlist/impl/RoomListPresenterTests.kt
+++ b/features/roomlist/impl/src/test/kotlin/io/element/android/features/roomlist/impl/RoomListPresenterTests.kt
@@ -140,7 +140,7 @@ class RoomListPresenterTests {
}.test {
val initialState = awaitItem()
assertThat(initialState.showAvatarIndicator).isTrue()
- sessionVerificationService.givenCanVerifySession(false)
+ sessionVerificationService.givenNeedsSessionVerification(false)
encryptionService.emitBackupState(BackupState.ENABLED)
val finalState = awaitItem()
assertThat(finalState.showAvatarIndicator).isFalse()
@@ -282,7 +282,7 @@ class RoomListPresenterTests {
roomListService = roomListService,
encryptionService = encryptionService,
sessionVerificationService = FakeSessionVerificationService().apply {
- givenCanVerifySession(false)
+ givenNeedsSessionVerification(false)
},
syncService = FakeSyncService(initialState = SyncState.Running)
)
diff --git a/features/securebackup/impl/src/main/res/values-fr/translations.xml b/features/securebackup/impl/src/main/res/values-fr/translations.xml
index 824e786cc4..6296e0d7ac 100644
--- a/features/securebackup/impl/src/main/res/values-fr/translations.xml
+++ b/features/securebackup/impl/src/main/res/values-fr/translations.xml
@@ -48,7 +48,7 @@
"Avez-vous sauvegardé votre clé de récupération?"
"Votre sauvegarde est protégée par votre clé de récupération. Si vous avez besoin d’une nouvelle clé après la configuration, vous pourrez en créer une nouvelle en cliquant sur \"Changer la clé de récupération\"."
"Générer la clé de récupération"
- "Assurez-vous de pouvoir enregistrer votre clé dans un endroit sécurisé"
+ "Assurez-vous de conserver la clé dans un endroit sûr"
"Sauvegarde mise en place avec succès"
"Configurer la sauvegarde"
diff --git a/features/securebackup/impl/src/main/res/values-it/translations.xml b/features/securebackup/impl/src/main/res/values-it/translations.xml
index ba2948e8a5..7b2a40341a 100644
--- a/features/securebackup/impl/src/main/res/values-it/translations.xml
+++ b/features/securebackup/impl/src/main/res/values-it/translations.xml
@@ -9,6 +9,13 @@
"Il backup delle conversazioni non è attualmente sincronizzato."
"Configura il recupero"
"Ottieni l\'accesso ai tuoi messaggi cifrati se perdi tutti i tuoi dispositivi o se sei disconnesso da %1$s ovunque."
+ "Apri %1$s in un dispositivo desktop"
+ "Accedi nuovamente al tuo account"
+ "Quando ti viene chiesto di verificare il tuo dispositivo, seleziona %1$s"
+ "“Reimposta tutto”"
+ "Segui le istruzioni per creare una nuova chiave di recupero"
+ "Salva la tua nuova chiave di recupero in un gestore di password o in una nota cifrata."
+ "Reimposta la crittografia del tuo account utilizzando un altro dispositivo"
"Disattiva"
"Perderai i tuoi messaggi cifrati se sei disconnesso da tutti i dispositivi."
"Vuoi davvero disattivare il backup?"
@@ -21,13 +28,16 @@
"Assicurati di conservare la chiave di recupero in un posto sicuro"
"Chiave di recupero cambiata"
"Cambiare la chiave di recupero?"
+ "Crea una nuova chiave di recupero"
"Assicurati che nessuno possa vedere questa schermata!"
"Riprova per confermare l\'accesso al backup della chat."
"Chiave di recupero errata"
"Se hai una chiave di sicurezza o una password, andrà bene anche questo."
+ "Chiave di recupero o codice di accesso"
"Inserisci…"
+ "Hai perso la chiave di recupero?"
"Chiave di recupero confermata"
- "Inserisci la chiave o password di recupero"
+ "Inserisci la tua chiave di recupero"
"Chiave di recupero copiata"
"Generazione…"
"Salva la chiave di recupero"
diff --git a/features/securebackup/impl/src/main/res/values-ka/translations.xml b/features/securebackup/impl/src/main/res/values-ka/translations.xml
new file mode 100644
index 0000000000..e31153859c
--- /dev/null
+++ b/features/securebackup/impl/src/main/res/values-ka/translations.xml
@@ -0,0 +1,40 @@
+
+
+ "სარეზერვო ასლის გამორთვა"
+ "სარეზერვო ასლის ჩართვა"
+ "სარეზერვო ასლი უზრუნველყოფს იმას, რომ თქვენ შეტყობინებების ისტორიას არ დაკარგავთ. %1$s"
+ "სარეზერვო ასლი"
+ "აღდგენის გასაღების შეცვლა"
+ "შეიყვანეთ აღდგენის გასაღები"
+ "თქვენი ჩატის სარეზერვო ასლი ამჟამად არ არის სინქრონიზებული."
+ "აღდგენის დაყენება"
+ "მიიღეთ წვდომა თქვენს დაშიფრულ შეტყობინებებზე, თუ დაკარგავთ თქვენს ყველა მოწყობილობას ან გამოხვალთ სისტემიდან %1$s-დან ყველგან."
+ "გამორთვა"
+ "თქვენ დაკარგავთ დაშიფრულ შეტყობინებებს, თუ ყველა მოწყობილობიდან გამოხვალთ."
+ "დარწმუნებული ხართ, რომ გსურთ გამორთოთ სარეზერვო ასლი?"
+ "სარეზერვო ასლის გამორთვა წაშლის თქვენი მიმდინარე დაშიფვრის გასაღების სარეზერვო ასლს და გამორთავს უსაფრთხოების სხვა ფუნქციებს. ამ შემთხვევაში, თქვენ:"
+ "არ გექნებათ დაშიფვრული შეტყობინებების ისტორია ახალ მოწყობილობებზე"
+ "დაკარვავთ წვდომას დაშიფრულ შეტყობინებებზე თუ ყველგან გამოხვალთ %1$s-დან"
+ "დარწმუნებული ხართ, რომ გსურთ გამორთოთ სარეზერვო ასლი?"
+ "მიიღეთ ახალი აღდგენის გასაღები, თუ დაკარგეთ არსებული. აღდგენის გასაღების შეცვლის შემდეგ, ძველი აღარ იმუშავებს."
+ "ახალი აღდგენის გასაღების შექმნა"
+ "დარწმუნდით, რომ შეგიძლიათ შეინახოთ თქვენი აღდგენის გასაღები სადმე უსაფრთხო ადგილას"
+ "აღდგენის გასაღები შეიცვალა"
+ "გსურთ აღდგენის გასაღების შეცვლა?"
+ "დარწმუნდით, რომ ვერავინ ხედავს ამ ეკრანს!"
+ "თუ თქვენ გაქვთ უსაფრთხოების გასაღები ან უსაფრთხოების ფრაზა, ეს ასევე იმუშავებს."
+ "შეყვანა"
+ "აღდგენის გასაღები დადასტურებულია"
+ "შეიყვანეთ თქვენი აღდგენის გასაღები"
+ "აღდგენის გასაღების შენახვა"
+ "ჩაწერეთ თქვენი აღდგენის გასაღები სადმე უსაფრთხო ადგილას ან შეინახეთ პაროლის მენეჯერში."
+ "აღდგენის გასაღების დასაკოპირებლად, დააწკაპუნეთ"
+ "შეინახეთ აღდგენის გასაღები"
+ "თქვენ ვერ შეძლებთ წვდომას თქვენი ახალი აღდგენის გასაღებზე ამ ნაბიჯის შემდეგ."
+ "შეინახეთ თქვენი აღდგენის გასაღები?"
+ "თქვენი ჩატის სარეზერვო ასლი დაცულია აღდგენის გასაღებით. თუ დაყენების შემდეგ გჭირდებათ ახალი აღდგენის გასაღები, შეგიძლიათ ხელახლა შექმნათ „აღდგენის გასაღების შეცვლის“ არჩევით."
+ "შექმენით აღდგენის გასაღები"
+ "დარწმუნდით, რომ შეგიძლიათ შეინახოთ თქვენი აღდგენის გასაღები სადმე უსაფრთხო ადგილას"
+ "აღდგენის დაყენება წარმატებით დასრულდა"
+ "აღდგენის დაყენება"
+
diff --git a/features/securebackup/impl/src/main/res/values-pt/translations.xml b/features/securebackup/impl/src/main/res/values-pt/translations.xml
new file mode 100644
index 0000000000..274de6d6af
--- /dev/null
+++ b/features/securebackup/impl/src/main/res/values-pt/translations.xml
@@ -0,0 +1,54 @@
+
+
+ "Desativar a cópia de segurança"
+ "Ativar a cópia de segurança"
+ "A cópia de segurança garante que não perdes o teu histórico de mensagens. %1$s."
+ "Cópia de segurança"
+ "Alterar chave de recuperação"
+ "Inserir chave de recuperação"
+ "A tua cópia de segurança das conversas está atualmente dessincronizada."
+ "Configurar recuperação"
+ "Obtém acesso às tuas mensagens cifradas mesmo se perderes todos os teus dispositivos ou se terminares todas as tuas sessões %1$s."
+ "Abre a %1$s num computador"
+ "Inicia sessão novamente"
+ "Quando te for pedido para verificares o teu dispositivo, seleciona %1$s"
+ "“Repor tudo”"
+ "Segue as instruções para criar uma nova chave de recuperação"
+ "Guarda a tua nova chave de recuperação num gestor de senhas ou numa nota cifrada"
+ "Repor a cifragem da tua conta utilizando outro dispositivo"
+ "Desligar"
+ "Perderás as tuas mensagens cifradas se tiveres terminado a sessão em todos os teus dispositivos."
+ "Tens a certeza que queres desativar a cópia de segurança?"
+ "Desativar a cópia de segurança irá remover a atual cópia da chave de cifragem e desativar outras funcionalidades de segurança. Neste caso, irá:"
+ "O histórico de mensagens cifradas em novos dispositivos"
+ "Acesso às tuas mensagens cifradas se terminares todas as sessões %1$s"
+ "Tens a certeza que queres desativar a cópia de segurança?"
+ "Obtém uma nova chave de recuperação se tiveres perdido a atual. Depois de a alterares, a antiga deixará de funcionar."
+ "Gerar uma nova chave de recuperação"
+ "Certifica-te de que podes guardar a tua chave de recuperação num local seguro"
+ "Chave de recuperação alterada"
+ "Alterar a chave de recuperação?"
+ "Criar nova chave de recuperação"
+ "Certifica-te de que ninguém consegue ver esta página!"
+ "Por favor, tenta novamente para confirmar o acesso à tua cópia de segurança das conversas."
+ "Chave de recuperação incorreta"
+ "Também funciona se tiveres uma chave ou frase de segurança."
+ "Chave ou código de recuperação"
+ "Inserir…"
+ "Perdeste a tua chave de recuperação?"
+ "Chave de recuperação confirmada"
+ "Insere a tua chave de recuperação"
+ "Chave de recuperação copiada"
+ "A gerar…"
+ "Guardar chave de recuperação"
+ "Anota a tua chave de recuperação num local seguro ou guarda-a num gestor de senhas."
+ "Toca para copiar a chave de recuperação"
+ "Guarda a tua chave de recuperação"
+ "Não poderás aceder à tua nova chave de recuperação após este passo."
+ "Guardaste a tua chave de recuperação?"
+ "A tua cópia de segurança das conversas está protegida por uma chave de recuperação. Se precisares de uma nova chave após a configuração, podes recriá-la selecionando \"Alterar chave de recuperação\"."
+ "Gerar a tua chave de recuperação"
+ "Certifica-te de que podes guardar a tua chave de recuperação num local seguro"
+ "Recuperação configurada com sucesso"
+ "Configurar recuperação"
+
diff --git a/features/securebackup/impl/src/main/res/values-ro/translations.xml b/features/securebackup/impl/src/main/res/values-ro/translations.xml
index 5bc6e44d55..6b2f2e31dc 100644
--- a/features/securebackup/impl/src/main/res/values-ro/translations.xml
+++ b/features/securebackup/impl/src/main/res/values-ro/translations.xml
@@ -9,6 +9,13 @@
"Backup-ul pentru chat nu este sincronizat în prezent."
"Configurați recuperarea"
"Obțineți acces la mesajele dumneavoastră criptate dacă vă pierdeți toate dispozitivele sau sunteți deconectat de la %1$s peste tot."
+ "Deschideți %1$s pe un dispozitiv desktop"
+ "Conectați-vă din nou la contul dumneavoastră"
+ "Când vi se cere să vă verificați dispozitivul, selectați%1$s"
+ "„Resetați tot”"
+ "Urmați instrucțiunile pentru a crea o nouă cheie de recuperare"
+ "Salvați noua cheie de recuperare într-un manager de parole sau o notă criptată"
+ "Resetați criptarea contului dumneavoastră folosind un alt dispozitiv"
"Dezactivare"
"Veți pierde mesajele criptate dacă sunteți deconectat de pe toate dispozitivele."
"Sunteți sigur că doriți să dezactivați backup-ul?"
@@ -21,11 +28,14 @@
"Asigurați-vă că puteți stoca cheia de recuperare undeva în siguranță"
"Cheia de recuperare a fost schimbată"
"Schimbați cheia de recuperare?"
- "Introduceți cheia de recuperare pentru a confirma accesul la backup."
+ "Creați o nouă cheie de recuperare"
+ "Asigurați-vă că nimeni nu poate vedea acest ecran!"
"Vă rugăm să încercați din nou să confirmați accesul la backup."
"Cheie de recuperare incorectă"
- "Introduceți codul de 48 de caractere."
+ "Dacă aveți o cheie de securitate sau o frază de securitate, aceasta va funcționa și ea."
+ "Cheie de recuperare sau cod de acces"
"Introduceți…"
+ "Ați pierdut cheia de recuperare?"
"Cheia de recuperare confirmată"
"Confirmați cheia de recuperare"
"Cheia de recuperare copiată"
diff --git a/features/securebackup/impl/src/main/res/values-ru/translations.xml b/features/securebackup/impl/src/main/res/values-ru/translations.xml
index b311575c4b..6a46ab3797 100644
--- a/features/securebackup/impl/src/main/res/values-ru/translations.xml
+++ b/features/securebackup/impl/src/main/res/values-ru/translations.xml
@@ -60,6 +60,7 @@
" или пароль"
"Вход…"
+ "Потеряли ключ восстановления?"
"Ключ восстановления"
" подтвержден"
diff --git a/features/securebackup/impl/src/main/res/values-uk/translations.xml b/features/securebackup/impl/src/main/res/values-uk/translations.xml
index 236e7e258a..2a5b029a6b 100644
--- a/features/securebackup/impl/src/main/res/values-uk/translations.xml
+++ b/features/securebackup/impl/src/main/res/values-uk/translations.xml
@@ -12,9 +12,9 @@
"Вимкнути"
"Ви втратите зашифровані повідомлення, якщо вийдете з усіх пристроїв."
"Ви впевнені, що хочете вимкнути резервне копіювання?"
- "Вимкнення резервного копіювання призведе до видалення поточної резервної копії ключа шифрування та вимкнення інших функцій безпеки. В цьому випадку ви будете:"
- "Не мати зашифрованої історії повідомлень на нових пристроях"
- "Втратите доступ до зашифрованих повідомлень, якщо ви вийдете з усіх %1$s сеансів"
+ "Вимкнення резервного копіювання призведе до видалення поточної резервної копії ключа шифрування та вимкнення інших функцій безпеки. В такому разі ви:"
+ "Не матимете історії зашифрованих повідомлень на нових пристроях"
+ "Втратите доступ до зашифрованих повідомлень, якщо вийдете з усіх сеансів %1$s"
"Ви впевнені, що хочете вимкнути резервне копіювання?"
"Отримайте новий ключ відновлення, якщо ви втратили існуючий ключ. Після зміни ключа відновлення ваш старий більше не буде працювати."
"Згенерувати новий ключ відновлення"
diff --git a/features/securebackup/impl/src/main/res/values-zh/translations.xml b/features/securebackup/impl/src/main/res/values-zh/translations.xml
new file mode 100644
index 0000000000..a984d72208
--- /dev/null
+++ b/features/securebackup/impl/src/main/res/values-zh/translations.xml
@@ -0,0 +1,54 @@
+
+
+ "关闭备份"
+ "开启备份"
+ "备份可确保你不会丢失消息历史记录。%1$s。"
+ "备份"
+ "更改恢复密钥"
+ "输入恢复密钥"
+ "您的聊天备份当前不同步。"
+ "设置恢复密钥"
+ "在丢失或从 %1$s 登出所有设备的情况下访问加密消息。"
+ "在桌面设备中打开 %1$s"
+ "再次登录您的账户"
+ "当要求验证您的设备时,选择 %1$s"
+ "「全部重置」"
+ "按照说明创建新的恢复密钥"
+ "将新的恢复密钥保存在密码管理器或加密备忘录中"
+ "使用其他设备重置账户的加密"
+ "关闭"
+ "如果您登出所有设备,您的加密消息将丢失。"
+ "您确定要关闭备份吗?"
+ "关闭备份将删除您当前的加密密钥备份并关闭其他安全功能。在这种情况下,你将:"
+ "新设备上没有加密消息的历史记录"
+ "如果您在所有设备上登出了 %1$s,那将无法访问加密的消息"
+ "您确定要关闭备份吗?"
+ "如果您丢失了现有的恢复密钥,请获取新的恢复密钥。更改恢复密钥后,您的旧密钥将不再起作用。"
+ "生成新的恢复密钥"
+ "确保您可以将恢复密钥存储在安全的地方"
+ "恢复密钥已更改"
+ "更改恢复密钥?"
+ "创建新的恢复密钥"
+ "确保没有人能看到这个界面!"
+ "请重试以访问您的聊天备份。"
+ "恢复密钥不正确"
+ "如果您有安全密钥或安全短语,也可以用。"
+ "恢复密钥或密码"
+ "输入……"
+ "丢失了恢复密钥?"
+ "恢复密钥已确认"
+ "输入您的恢复密钥"
+ "恢复密钥已复制"
+ "正在生成……"
+ "保存恢复密钥"
+ "在安全的地方写下恢复密钥或将其保存在密码管理器中。"
+ "点击复制恢复密钥"
+ "保存您的恢复密钥"
+ "完成此步骤后,您将无法访问新的恢复密钥。"
+ "您保存了恢复密钥吗?"
+ "您的聊天备份受恢复密钥保护。如果您在安装后需要新的恢复密钥,则可以通过选择「更改恢复密钥」来重新创建。"
+ "生成恢复密钥"
+ "确保将恢复密钥存储在安全的地方"
+ "恢复设置成功"
+ "设置恢复"
+
diff --git a/features/signedout/impl/src/main/res/values-ka/translations.xml b/features/signedout/impl/src/main/res/values-ka/translations.xml
new file mode 100644
index 0000000000..37c86149ed
--- /dev/null
+++ b/features/signedout/impl/src/main/res/values-ka/translations.xml
@@ -0,0 +1,8 @@
+
+
+ "თქვენ პაროლი შეცვალეთ სხვა სესიაში"
+ "თქვენ სესია წაშალეთ სხვა სესიიდან"
+ "თქვენი სერვერის ადმინისტრატორმა გააუქმა თქვენი წვდომა"
+ "ალბათ, თქვენ გამოხვედით ქვემოთ ჩამოთვლილი ერთ-ერთი მიზეზის გამო. გთხოვთ, შეხვიდეთ ანგარიშში, რათა გააგრძელოთ %s-ს გამოყენება."
+ "თქვენ ანგარიშიდან გამოსული ხართ"
+
diff --git a/features/signedout/impl/src/main/res/values-pt/translations.xml b/features/signedout/impl/src/main/res/values-pt/translations.xml
new file mode 100644
index 0000000000..d7e6ad8948
--- /dev/null
+++ b/features/signedout/impl/src/main/res/values-pt/translations.xml
@@ -0,0 +1,8 @@
+
+
+ "Alteraste a tua senha noutra sessão"
+ "Apagaste esta sessão a partir de outra"
+ "O administrador do teu servidor invalidou o teu acesso"
+ "A tua sessão pode ter sido terminada por um dos motivos indicados abaixo. Inicia sessão novamente para continuares a utilizar a %s."
+ "Não tens sessão iniciada"
+
diff --git a/features/signedout/impl/src/main/res/values-zh/translations.xml b/features/signedout/impl/src/main/res/values-zh/translations.xml
new file mode 100644
index 0000000000..87c7620d98
--- /dev/null
+++ b/features/signedout/impl/src/main/res/values-zh/translations.xml
@@ -0,0 +1,8 @@
+
+
+ "你在另一个会话中更改了密码"
+ "你已从其他会话中删除本会话"
+ "您的服务器管理员已禁止您访问"
+ "您可能因下列原因而被登出。请重新登录以继续使用 %s。"
+ "你已登出"
+
diff --git a/features/userprofile/shared/src/main/res/values-ka/translations.xml b/features/userprofile/shared/src/main/res/values-ka/translations.xml
new file mode 100644
index 0000000000..0054f19946
--- /dev/null
+++ b/features/userprofile/shared/src/main/res/values-ka/translations.xml
@@ -0,0 +1,10 @@
+
+
+ "დაბლოკვა"
+ "დაბლოკილი მომხმარებლები ვერ შეძლებენ თქვენთვის შეტყობინების გაგზავნას და ყველა მათი შეტყობინება თქვენთვის დამალული იქნება. თქვენ მათი განბლოკვა ნებისმეირ დროს შეგიძლიათ."
+ "მომხმარებლის დაბლოკვა"
+ "განბლოკვა"
+ "თქვენ კვლავ შეძლებთ მათგან ყველა შეტყობინების ნახვას."
+ "Მომხმარებლის განბლოკვა"
+ "ჩატის დაწყების მცდელობისას შეცდომა მოხდა"
+
diff --git a/features/userprofile/shared/src/main/res/values-pt/translations.xml b/features/userprofile/shared/src/main/res/values-pt/translations.xml
new file mode 100644
index 0000000000..df2ca21681
--- /dev/null
+++ b/features/userprofile/shared/src/main/res/values-pt/translations.xml
@@ -0,0 +1,10 @@
+
+
+ "Bloquear"
+ "Os utilizadores bloqueados não poderão enviar-te mensagens e todas as suas mensagens ficarão ocultas. Podes desbloqueá-los em qualquer altura."
+ "Bloquear utilizador"
+ "Desbloquear"
+ "Poderás voltar a ver todas as suas mensagens."
+ "Desbloquear utilizador"
+ "Ocorreu um erro ao tentar iniciar uma conversa"
+
diff --git a/features/userprofile/shared/src/main/res/values-zh/translations.xml b/features/userprofile/shared/src/main/res/values-zh/translations.xml
new file mode 100644
index 0000000000..d70689b326
--- /dev/null
+++ b/features/userprofile/shared/src/main/res/values-zh/translations.xml
@@ -0,0 +1,10 @@
+
+
+ "封禁"
+ "被封禁的用户无法给你发消息,并且他们的消息会被隐藏。你可以随时解封。"
+ "封禁用户"
+ "解封"
+ "你可以重新接收他们的消息。"
+ "解封用户"
+ "在开始聊天时发生了错误"
+
diff --git a/features/verifysession/impl/src/main/kotlin/io/element/android/features/verifysession/impl/VerifySelfSessionPresenter.kt b/features/verifysession/impl/src/main/kotlin/io/element/android/features/verifysession/impl/VerifySelfSessionPresenter.kt
index b31cbd0162..ed7342eb60 100644
--- a/features/verifysession/impl/src/main/kotlin/io/element/android/features/verifysession/impl/VerifySelfSessionPresenter.kt
+++ b/features/verifysession/impl/src/main/kotlin/io/element/android/features/verifysession/impl/VerifySelfSessionPresenter.kt
@@ -25,7 +25,6 @@ import androidx.compose.runtime.derivedStateOf
import androidx.compose.runtime.getValue
import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberCoroutineScope
-import androidx.compose.runtime.setValue
import com.freeletics.flowredux.compose.rememberStateAndDispatch
import io.element.android.features.preferences.api.store.SessionPreferencesStore
import io.element.android.libraries.architecture.AsyncData
@@ -61,7 +60,7 @@ class VerifySelfSessionPresenter @Inject constructor(
val recoveryState by encryptionService.recoveryStateStateFlow.collectAsState()
val stateAndDispatch = stateMachine.rememberStateAndDispatch()
val skipVerification by sessionPreferencesStore.isSessionVerificationSkipped().collectAsState(initial = false)
- val needsVerification by sessionVerificationService.canVerifySessionFlow.collectAsState(initial = true)
+ val needsVerification by sessionVerificationService.needsSessionVerification.collectAsState(initial = true)
val verificationFlowStep by remember {
derivedStateOf {
when {
diff --git a/features/verifysession/impl/src/main/res/values-es/translations.xml b/features/verifysession/impl/src/main/res/values-es/translations.xml
index 812ba53a32..b165818726 100644
--- a/features/verifysession/impl/src/main/res/values-es/translations.xml
+++ b/features/verifysession/impl/src/main/res/values-es/translations.xml
@@ -1,11 +1,16 @@
+ "Verifica este dispositivo para configurar la mensajería segura."
+ "Confirma que eres tú"
+ "Ahora puedes leer o enviar mensajes de forma segura y cualquier persona con la que chatees también puede confiar en este dispositivo."
+ "Dispositivo verificado"
"Algo no fue bien. Se agotó el tiempo de espera de la solicitud o se rechazó."
"Confirma que los emojis que aparecen a continuación coinciden con los que aparecen en tu otra sesión."
"Comparar emojis"
"Confirma que los números que aparecen a continuación coinciden con los mostrados en tu otra sesión."
"Comparar números"
"Tu nueva sesión ya está verificada. Tienes acceso a tus mensajes cifrados y otros usuarios lo considerarán de confianza."
+ "Introduzca la clave de recuperación"
"Demuestra que eres tú para acceder a tu historial de mensajes cifrados."
"Abrir una sesión existente"
"Reintentar la verificación"
diff --git a/features/verifysession/impl/src/main/res/values-it/translations.xml b/features/verifysession/impl/src/main/res/values-it/translations.xml
index a3b300793d..5e22712283 100644
--- a/features/verifysession/impl/src/main/res/values-it/translations.xml
+++ b/features/verifysession/impl/src/main/res/values-it/translations.xml
@@ -1,5 +1,6 @@
+ "Crea una nuova chiave di recupero"
"Verifica questo dispositivo per segnare i tuoi messaggi come sicuri."
"Conferma la tua identità"
"Ora puoi leggere o inviare messaggi in tutta sicurezza e anche chi chatta con te può fidarsi di questo dispositivo."
diff --git a/features/verifysession/impl/src/main/res/values-ka/translations.xml b/features/verifysession/impl/src/main/res/values-ka/translations.xml
new file mode 100644
index 0000000000..fb1f3c6db4
--- /dev/null
+++ b/features/verifysession/impl/src/main/res/values-ka/translations.xml
@@ -0,0 +1,17 @@
+
+
+ "რაღაცა არასწორადაა. ან მოთხოვნის ვადაა ამოწურული, ან მოთხოვნა უარყოფილი იყო."
+ "დაადასტურეთ, რომ ქვემოთ მოყვანილი ემოჯიები შეესაბამება თქვენს სხვა სესიაზე ნაჩვენებს."
+ "შეადარეთ ემოჯიები"
+ "თქვენი ახალი სესია დადასტურებულია. მას აქვს წვდომა დაშიფრულ შეტყობინებებზე და სხვა მომხმარებლები მას სანდოდ ხედავენ."
+ "დაამტკიცეთ, რომ ეს თქვენ ხართ, რათა მიიღოთ წვდომა თქვენი დაშიფრული შეტყობინებების ისტორიასთან."
+ "არსებული სესიის გახსნა"
+ "დადასტურების ხელახლა ცდა"
+ "მზად ვარ"
+ "ველოდებით დამთხვევას"
+ "შეადარეთ უნიკალური ემოჯი, დარწმუნდით, რომ ისინი ერთი დ იმავე თანმიმდევრობით გამოჩნდნენ."
+ "ისინი არ ემთხვევიან ერთმანეთს"
+ "ისინი ემთხვევიან ერთმანეთს"
+ "მიიღეთ დადასტურების მოთხოვნა თქვენს სხვა სესიაში ამ პროცესის გასაგრძელებლად."
+ "მოთხოვნის მიღებას ველოდებით"
+
diff --git a/features/verifysession/impl/src/main/res/values-pt/translations.xml b/features/verifysession/impl/src/main/res/values-pt/translations.xml
new file mode 100644
index 0000000000..919c8db023
--- /dev/null
+++ b/features/verifysession/impl/src/main/res/values-pt/translations.xml
@@ -0,0 +1,28 @@
+
+
+ "Criar uma nova chave de recuperação"
+ "Verifica este dispositivo para configurar o envio seguro de mensagens."
+ "Confirma que és tu"
+ "Agora podes ler ou enviar mensagens de forma segura, e qualquer pessoa com quem converses também pode confiar neste dispositivo."
+ "Dispositivo verificado"
+ "Utilizar outro dispositivo"
+ "A aguardar por outros dispositivos…"
+ "Algo não bateu certo. O pedido ou demorou demasiado tempo ou foi rejeitado."
+ "Confirma se os emojis abaixo correspondem aos apresentados na tua outra sessão."
+ "Compara os emojis"
+ "Confirma se os números abaixo correspondem aos números apresentados na tua outra sessão."
+ "Comparar números"
+ "A tua nova sessão está agora verificada, pelo que tem acesso às tuas mensagens cifradas e os outros utilizadores vão vê-la como de confiança."
+ "Insere a chave de recuperação"
+ "Prova que és tu para acederes ao teu histórico de mensagens cifradas."
+ "Abrir sessão existente"
+ "Repetir verficiação"
+ "Estou pronto"
+ "A aguardar correspondência"
+ "Compara um conjunto único de emojis."
+ "Compara os emojis únicos, certificando-te de que aparecem pela mesma ordem."
+ "Não correspondem"
+ "Correspondem"
+ "Para continuar, aceita o pedido de verificação na tua outra sessão."
+ "À aguardar a aceitação do pedido"
+
diff --git a/features/verifysession/impl/src/main/res/values-ro/translations.xml b/features/verifysession/impl/src/main/res/values-ro/translations.xml
index ed96210f84..91e837ddec 100644
--- a/features/verifysession/impl/src/main/res/values-ro/translations.xml
+++ b/features/verifysession/impl/src/main/res/values-ro/translations.xml
@@ -1,5 +1,12 @@
+ "Creați o nouă cheie de recuperare"
+ "Verificați acest dispozitiv pentru a configura mesagerie securizată."
+ "Confirmați că sunteți dumneavoastră"
+ "Acum puteți citi sau trimite mesaje în siguranță, iar oricine cu care conversați poate avea încredere în acest dispozitiv."
+ "Dispozitiv verificat"
+ "Utilizați un alt dispozitiv"
+ "Se așteaptă celălalt dispozitiv…"
"Ceva nu este în regulă. Fie cererea a expirat, fie a fost respinsă."
"Confirmați că emoticoanele de mai jos se potrivesc cu cele afișate în cealaltă sesiune."
"Comparați emoticoanele"
diff --git a/features/verifysession/impl/src/main/res/values-zh/translations.xml b/features/verifysession/impl/src/main/res/values-zh/translations.xml
new file mode 100644
index 0000000000..15cf93695f
--- /dev/null
+++ b/features/verifysession/impl/src/main/res/values-zh/translations.xml
@@ -0,0 +1,28 @@
+
+
+ "创建新的恢复密钥"
+ "验证此设备以开始安全地收发消息。"
+ "确认这是你"
+ "现在,您可以安全地阅读或发送消息,与您聊天的人也会信任此设备。"
+ "设备已验证"
+ "使用其他设备"
+ "正在等待其他设备……"
+ "发生了一些错误。网络请求超时,或者被服务器拒绝。"
+ "确认下方的表情符号与另一设备上显示的相同。"
+ "比较表情符号"
+ "确认以下数字与其他会话中显示的一致。"
+ "比较数字"
+ "你的新设备已经成功验证。现在新设备可以访问加密信息,别的用户也会信任这个设备。"
+ "输入恢复密钥"
+ "证明自己的身份以访问加密历史消息。"
+ "打开已有会话"
+ "重试验证"
+ "准备就绪"
+ "等待比对"
+ "比较一组表情符号。"
+ "比较表情符号,确保它们以相同顺序排列。"
+ "不匹配"
+ "匹配"
+ "请在其他会话中接受验证请求。"
+ "等待接受请求"
+
diff --git a/features/verifysession/impl/src/test/kotlin/io/element/android/features/verifysession/impl/VerifySelfSessionPresenterTests.kt b/features/verifysession/impl/src/test/kotlin/io/element/android/features/verifysession/impl/VerifySelfSessionPresenterTests.kt
index 3dd391da16..1a27891bef 100644
--- a/features/verifysession/impl/src/test/kotlin/io/element/android/features/verifysession/impl/VerifySelfSessionPresenterTests.kt
+++ b/features/verifysession/impl/src/test/kotlin/io/element/android/features/verifysession/impl/VerifySelfSessionPresenterTests.kt
@@ -296,8 +296,7 @@ class VerifySelfSessionPresenterTests {
@Test
fun `present - When verification is not needed, the flow is completed`() = runTest {
val service = FakeSessionVerificationService().apply {
- givenCanVerifySession(false)
- givenIsReady(true)
+ givenNeedsSessionVerification(false)
givenVerifiedStatus(SessionVerifiedStatus.Verified)
givenVerificationFlowState(VerificationFlowState.Finished)
}
diff --git a/gradle.properties b/gradle.properties
index f28522f5b0..19237b74cf 100644
--- a/gradle.properties
+++ b/gradle.properties
@@ -49,7 +49,7 @@ signing.element.nightly.keyPassword=Secret
# Customise the Lint version to use a more recent version than the one bundled with AGP
# https://googlesamples.github.io/android-custom-lint-rules/usage/newer-lint.md.html
-android.experimental.lint.version=8.4.0-alpha13
+android.experimental.lint.version=8.5.0-alpha07
# Enable test fixture for all modules by default
android.experimental.enableTestFixtures=true
@@ -59,3 +59,6 @@ android.enableBuildConfigAsBytecode=true
# By default, the plugin applies itself to all subprojects, but we don't want that as it would cause issues with builds using local AARs
dependency.analysis.autoapply=false
+
+# Disable new R8 shrinking for local dependencies as it causes issues with release builds
+android.disableMinifyLocalDependenciesForLibraries=false
diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml
index 27dfaa42f1..37605bf098 100644
--- a/gradle/libs.versions.toml
+++ b/gradle/libs.versions.toml
@@ -3,9 +3,9 @@
[versions]
# Project
-android_gradle_plugin = "8.3.2"
-kotlin = "1.9.23"
-ksp = "1.9.23-1.0.20"
+android_gradle_plugin = "8.4.0"
+kotlin = "1.9.24"
+ksp = "1.9.24-1.0.20"
firebaseAppDistribution = "5.0.0"
# AndroidX
@@ -24,10 +24,10 @@ media3 = "1.3.1"
# Compose
compose_bom = "2024.05.00"
-composecompiler = "1.5.13"
+composecompiler = "1.5.14"
# Coroutines
-coroutines = "1.8.0"
+coroutines = "1.8.1"
# Accompanist
accompanist = "0.34.0"
@@ -37,13 +37,13 @@ test_core = "1.5.0"
#other
coil = "2.6.0"
-datetime = "0.5.0"
+datetime = "0.6.0"
dependencyAnalysis = "1.31.0"
serialization_json = "1.6.3"
showkase = "1.0.2"
appyx = "1.4.0"
sqldelight = "2.0.2"
-wysiwyg = "2.37.2"
+wysiwyg = "2.37.3"
telephoto = "0.11.2"
# DI
@@ -54,10 +54,9 @@ anvil = "2.4.9"
autoservice = "1.1.1"
# quality
-junit = "4.13.2"
androidx-test-ext-junit = "1.1.5"
espresso-core = "3.5.1"
-kover = "0.7.6"
+kover = "0.8.0"
[libraries]
# Project
@@ -75,7 +74,7 @@ autonomousapps_dependencyanalysis_plugin = { module = "com.autonomousapps:depend
# AndroidX
androidx_core = { module = "androidx.core:core", version.ref = "core" }
androidx_corektx = { module = "androidx.core:core-ktx", version.ref = "core" }
-androidx_annotationjvm = "androidx.annotation:annotation-jvm:1.7.1"
+androidx_annotationjvm = "androidx.annotation:annotation-jvm:1.8.0"
androidx_datastore_preferences = { module = "androidx.datastore:datastore-preferences", version.ref = "datastore" }
androidx_datastore_datastore = { module = "androidx.datastore:datastore", version.ref = "datastore" }
androidx_exifinterface = "androidx.exifinterface:exifinterface:1.3.7"
@@ -114,7 +113,6 @@ coroutines_test = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-test", ve
# Accompanist
accompanist_permission = { module = "com.google.accompanist:accompanist-permissions", version.ref = "accompanist" }
-accompanist_systemui = { module = "com.google.accompanist:accompanist-systemuicontroller", version.ref = "accompanist" }
# Libraries
squareup_seismic = "com.squareup:seismic:1.0.3"
@@ -135,13 +133,12 @@ test_corektx = { module = "androidx.test:core-ktx", version.ref = "test_core" }
test_arch_core = "androidx.arch.core:core-testing:2.2.0"
test_junit = "junit:junit:4.13.2"
test_runner = "androidx.test:runner:1.5.2"
-test_junitext = "androidx.test.ext:junit:1.1.5"
-test_mockk = "io.mockk:mockk:1.13.10"
+test_mockk = "io.mockk:mockk:1.13.11"
test_konsist = "com.lemonappdev:konsist:0.13.0"
test_turbine = "app.cash.turbine:turbine:1.1.0"
test_truth = "com.google.truth:truth:1.4.2"
test_parameter_injector = "com.google.testparameterinjector:test-parameter-injector:1.16"
-test_robolectric = "org.robolectric:robolectric:4.12.1"
+test_robolectric = "org.robolectric:robolectric:4.12.2"
test_appyx_junit = { module = "com.bumble.appyx:testing-junit4", version.ref = "appyx" }
# Others
@@ -157,9 +154,9 @@ showkase = { module = "com.airbnb.android:showkase", version.ref = "showkase" }
showkase_processor = { module = "com.airbnb.android:showkase-processor", version.ref = "showkase" }
jsoup = "org.jsoup:jsoup:1.17.2"
appyx_core = { module = "com.bumble.appyx:core", version.ref = "appyx" }
-molecule-runtime = "app.cash.molecule:molecule-runtime:1.4.2"
+molecule-runtime = "app.cash.molecule:molecule-runtime:1.4.3"
timber = "com.jakewharton.timber:timber:5.0.1"
-matrix_sdk = "org.matrix.rustcomponents:sdk-android:0.2.18"
+matrix_sdk = "org.matrix.rustcomponents:sdk-android:0.2.20"
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" }
@@ -167,7 +164,7 @@ sqldelight-driver-jvm = { module = "app.cash.sqldelight:sqlite-driver", version.
sqldelight-coroutines = { module = "app.cash.sqldelight:coroutines-extensions", version.ref = "sqldelight" }
sqlcipher = "net.zetetic:android-database-sqlcipher:4.5.4"
sqlite = "androidx.sqlite:sqlite-ktx:2.4.0"
-unifiedpush = "com.github.UnifiedPush:android-connector:2.1.1"
+unifiedpush = "com.github.UnifiedPush:android-connector:2.4.0"
otaliastudios_transcoder = "com.otaliastudios:transcoder:0.10.5"
vanniktech_blurhash = "com.vanniktech:blurhash:0.3.0"
telephoto_zoomableimage = { module = "me.saket.telephoto:zoomable-image-coil", version.ref = "telephoto" }
@@ -181,7 +178,7 @@ kotlinpoet = "com.squareup:kotlinpoet:1.16.0"
# Analytics
posthog = "com.posthog:posthog-android:3.2.1"
-sentry = "io.sentry:sentry-android:7.8.0"
+sentry = "io.sentry:sentry-android:7.9.0"
# main branch can be tested replacing the version with main-SNAPSHOT
matrix_analytics_events = "com.github.matrix-org:matrix-analytics-events:0.21.0"
@@ -204,7 +201,6 @@ google_autoservice_annotations = { module = "com.google.auto.service:auto-servic
# value of `composecompiler` (which is used to set composeOptions.kotlinCompilerExtensionVersion.
# See https://github.com/renovatebot/renovate/issues/18354
android_composeCompiler = { module = "androidx.compose.compiler:compiler", version.ref = "composecompiler" }
-junit = { group = "junit", name = "junit", version.ref = "junit" }
androidx-test-ext-junit = { group = "androidx.test.ext", name = "junit", version.ref = "androidx-test-ext-junit" }
espresso-core = { group = "androidx.test.espresso", name = "espresso-core", version.ref = "espresso-core" }
appcompat = "androidx.appcompat:appcompat:1.6.1"
@@ -226,7 +222,6 @@ dependencygraph = "com.savvasdalkitsis.module-dependency-graph:0.12"
dependencycheck = "org.owasp.dependencycheck:9.1.0"
dependencyanalysis = { id = "com.autonomousapps.dependency-analysis", version.ref = "dependencyAnalysis" }
paparazzi = "app.cash.paparazzi:1.3.3"
-kover = { id = "org.jetbrains.kotlinx.kover", version.ref = "kover" }
sqldelight = { id = "app.cash.sqldelight", version.ref = "sqldelight" }
firebaseAppDistribution = { id = "com.google.firebase.appdistribution", version.ref = "firebaseAppDistribution" }
knit = { id = "org.jetbrains.kotlinx.knit", version = "0.5.0" }
diff --git a/libraries/androidutils/src/main/res/values-ka/translations.xml b/libraries/androidutils/src/main/res/values-ka/translations.xml
new file mode 100644
index 0000000000..ee284f3a40
--- /dev/null
+++ b/libraries/androidutils/src/main/res/values-ka/translations.xml
@@ -0,0 +1,4 @@
+
+
+ "თავსებადი აპლიკაცია ვერ მოიძებნა ამ მოქმედების შესასრულებლად."
+
diff --git a/libraries/androidutils/src/main/res/values-pt/translations.xml b/libraries/androidutils/src/main/res/values-pt/translations.xml
new file mode 100644
index 0000000000..9795e1b0d5
--- /dev/null
+++ b/libraries/androidutils/src/main/res/values-pt/translations.xml
@@ -0,0 +1,4 @@
+
+
+ "Nenhuma aplicação encontrada capaz de continuar esta ação."
+
diff --git a/libraries/androidutils/src/main/res/values-zh/translations.xml b/libraries/androidutils/src/main/res/values-zh/translations.xml
new file mode 100644
index 0000000000..00f50d4614
--- /dev/null
+++ b/libraries/androidutils/src/main/res/values-zh/translations.xml
@@ -0,0 +1,4 @@
+
+
+ "找不到完成此项操作的合适应用。"
+
diff --git a/libraries/architecture/src/main/kotlin/io/element/android/libraries/architecture/AsyncAction.kt b/libraries/architecture/src/main/kotlin/io/element/android/libraries/architecture/AsyncAction.kt
index e69b1b9eaf..9545f1ab68 100644
--- a/libraries/architecture/src/main/kotlin/io/element/android/libraries/architecture/AsyncAction.kt
+++ b/libraries/architecture/src/main/kotlin/io/element/android/libraries/architecture/AsyncAction.kt
@@ -86,6 +86,8 @@ sealed interface AsyncAction {
fun isFailure(): Boolean = this is Failure
fun isSuccess(): Boolean = this is Success
+
+ fun isReady() = isSuccess() || isFailure()
}
suspend inline fun MutableState>.runCatchingUpdatingState(
diff --git a/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/theme/components/ModalBottomSheetLayout.kt b/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/theme/components/ModalBottomSheetLayout.kt
deleted file mode 100644
index 8dd63d1cc6..0000000000
--- a/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/theme/components/ModalBottomSheetLayout.kt
+++ /dev/null
@@ -1,132 +0,0 @@
-/*
- * Copyright (c) 2023 New Vector Ltd
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-// This is actually expected, as we should remove this component soon and use ModalBottomSheet instead
-@file:Suppress("UsingMaterialAndMaterial3Libraries")
-
-package io.element.android.libraries.designsystem.theme.components
-
-import androidx.compose.foundation.background
-import androidx.compose.foundation.layout.Box
-import androidx.compose.foundation.layout.Column
-import androidx.compose.foundation.layout.ColumnScope
-import androidx.compose.foundation.layout.Spacer
-import androidx.compose.foundation.layout.fillMaxWidth
-import androidx.compose.foundation.layout.height
-import androidx.compose.foundation.layout.navigationBarsPadding
-import androidx.compose.foundation.layout.padding
-import androidx.compose.foundation.layout.size
-import androidx.compose.foundation.shape.CornerSize
-import androidx.compose.foundation.shape.RoundedCornerShape
-import androidx.compose.material.ExperimentalMaterialApi
-import androidx.compose.material.ModalBottomSheetDefaults
-import androidx.compose.material.ModalBottomSheetState
-import androidx.compose.material.ModalBottomSheetValue
-import androidx.compose.material.rememberModalBottomSheetState
-import androidx.compose.material3.MaterialTheme
-import androidx.compose.material3.contentColorFor
-import androidx.compose.runtime.Composable
-import androidx.compose.ui.Alignment
-import androidx.compose.ui.Modifier
-import androidx.compose.ui.graphics.Color
-import androidx.compose.ui.graphics.Shape
-import androidx.compose.ui.platform.LocalDensity
-import androidx.compose.ui.tooling.preview.Preview
-import androidx.compose.ui.unit.Dp
-import androidx.compose.ui.unit.dp
-import io.element.android.libraries.architecture.coverage.ExcludeFromCoverage
-import io.element.android.libraries.designsystem.modifiers.applyIf
-import io.element.android.libraries.designsystem.preview.ElementPreviewDark
-import io.element.android.libraries.designsystem.preview.ElementPreviewLight
-import io.element.android.libraries.designsystem.preview.PreviewGroup
-
-@OptIn(ExperimentalMaterialApi::class)
-@Composable
-fun ModalBottomSheetLayout(
- sheetContent: @Composable ColumnScope.() -> Unit,
- modifier: Modifier = Modifier,
- sheetState: ModalBottomSheetState = rememberModalBottomSheetState(ModalBottomSheetValue.Hidden),
- sheetShape: Shape = MaterialTheme.shapes.large.copy(bottomStart = CornerSize(0.dp), bottomEnd = CornerSize(0.dp)),
- sheetElevation: Dp = ModalBottomSheetDefaults.Elevation,
- sheetBackgroundColor: Color = MaterialTheme.colorScheme.surface,
- sheetContentColor: Color = contentColorFor(sheetBackgroundColor),
- scrimColor: Color = ModalBottomSheetDefaults.scrimColor,
- displayHandle: Boolean = false,
- useSystemPadding: Boolean = true,
- content: @Composable () -> Unit = {}
-) {
- androidx.compose.material.ModalBottomSheetLayout(
- sheetContent = {
- Column(
- Modifier.fillMaxWidth()
- .applyIf(useSystemPadding, ifTrue = {
- navigationBarsPadding()
- })
- ) {
- if (displayHandle) {
- Spacer(modifier = Modifier.height(16.dp))
- Box(
- modifier = Modifier
- .background(MaterialTheme.colorScheme.onSurfaceVariant, RoundedCornerShape(2.dp))
- .size(width = 32.dp, height = 4.dp)
- .align(Alignment.CenterHorizontally),
- )
- Spacer(modifier = Modifier.height(24.dp))
- }
- sheetContent()
- }
- },
- modifier = modifier,
- sheetState = sheetState,
- sheetShape = sheetShape,
- sheetElevation = sheetElevation,
- sheetBackgroundColor = sheetBackgroundColor,
- sheetContentColor = sheetContentColor,
- scrimColor = scrimColor,
- content = content,
- )
-}
-
-@Preview(group = PreviewGroup.BottomSheets)
-@Composable
-internal fun ModalBottomSheetLayoutLightPreview() =
- ElementPreviewLight { ContentToPreview() }
-
-@Preview(group = PreviewGroup.BottomSheets)
-@Composable
-internal fun ModalBottomSheetLayoutDarkPreview() =
- ElementPreviewDark { ContentToPreview() }
-
-@OptIn(ExperimentalMaterialApi::class)
-@ExcludeFromCoverage
-@Composable
-private fun ContentToPreview() {
- ModalBottomSheetLayout(
- modifier = Modifier.height(140.dp),
- displayHandle = true,
- sheetState = ModalBottomSheetState(ModalBottomSheetValue.Expanded, density = LocalDensity.current),
- sheetContent = {
- Text(
- text = "Sheet Content",
- modifier = Modifier
- .padding(start = 16.dp, end = 16.dp, bottom = 20.dp)
- .background(color = Color.Green)
- )
- }
- ) {
- Text(text = "Content", modifier = Modifier.background(color = Color.Red))
- }
-}
diff --git a/libraries/eventformatter/impl/src/main/kotlin/io/element/android/libraries/eventformatter/impl/RoomMembershipContentFormatter.kt b/libraries/eventformatter/impl/src/main/kotlin/io/element/android/libraries/eventformatter/impl/RoomMembershipContentFormatter.kt
index 1c58cffd43..72748a84ff 100644
--- a/libraries/eventformatter/impl/src/main/kotlin/io/element/android/libraries/eventformatter/impl/RoomMembershipContentFormatter.kt
+++ b/libraries/eventformatter/impl/src/main/kotlin/io/element/android/libraries/eventformatter/impl/RoomMembershipContentFormatter.kt
@@ -34,6 +34,7 @@ class RoomMembershipContentFormatter @Inject constructor(
): CharSequence? {
val userId = membershipContent.userId
val memberIsYou = matrixClient.isMe(userId)
+ val userDisplayNameOrId = membershipContent.userDisplayName ?: userId.value
return when (membershipContent.change) {
MembershipChange.JOINED -> if (memberIsYou) {
sp.getString(R.string.state_event_room_join_by_you)
@@ -46,41 +47,41 @@ class RoomMembershipContentFormatter @Inject constructor(
sp.getString(R.string.state_event_room_leave, senderDisambiguatedDisplayName)
}
MembershipChange.BANNED, MembershipChange.KICKED_AND_BANNED -> if (senderIsYou) {
- sp.getString(R.string.state_event_room_ban_by_you, userId.value)
+ sp.getString(R.string.state_event_room_ban_by_you, userDisplayNameOrId)
} else {
- sp.getString(R.string.state_event_room_ban, senderDisambiguatedDisplayName, userId.value)
+ sp.getString(R.string.state_event_room_ban, senderDisambiguatedDisplayName, userDisplayNameOrId)
}
MembershipChange.UNBANNED -> if (senderIsYou) {
- sp.getString(R.string.state_event_room_unban_by_you, userId.value)
+ sp.getString(R.string.state_event_room_unban_by_you, userDisplayNameOrId)
} else {
- sp.getString(R.string.state_event_room_unban, senderDisambiguatedDisplayName, userId.value)
+ sp.getString(R.string.state_event_room_unban, senderDisambiguatedDisplayName, userDisplayNameOrId)
}
MembershipChange.KICKED -> if (senderIsYou) {
- sp.getString(R.string.state_event_room_remove_by_you, userId.value)
+ sp.getString(R.string.state_event_room_remove_by_you, userDisplayNameOrId)
} else {
- sp.getString(R.string.state_event_room_remove, senderDisambiguatedDisplayName, userId.value)
+ sp.getString(R.string.state_event_room_remove, senderDisambiguatedDisplayName, userDisplayNameOrId)
}
MembershipChange.INVITED -> if (senderIsYou) {
- sp.getString(R.string.state_event_room_invite_by_you, userId.value)
+ sp.getString(R.string.state_event_room_invite_by_you, userDisplayNameOrId)
} else if (memberIsYou) {
sp.getString(R.string.state_event_room_invite_you, senderDisambiguatedDisplayName)
} else {
- sp.getString(R.string.state_event_room_invite, senderDisambiguatedDisplayName, userId.value)
+ sp.getString(R.string.state_event_room_invite, senderDisambiguatedDisplayName, userDisplayNameOrId)
}
MembershipChange.INVITATION_ACCEPTED -> if (memberIsYou) {
sp.getString(R.string.state_event_room_invite_accepted_by_you)
} else {
- sp.getString(R.string.state_event_room_invite_accepted, userId.value)
+ sp.getString(R.string.state_event_room_invite_accepted, userDisplayNameOrId)
}
MembershipChange.INVITATION_REJECTED -> if (memberIsYou) {
sp.getString(R.string.state_event_room_reject_by_you)
} else {
- sp.getString(R.string.state_event_room_reject, userId.value)
+ sp.getString(R.string.state_event_room_reject, userDisplayNameOrId)
}
MembershipChange.INVITATION_REVOKED -> if (senderIsYou) {
- sp.getString(R.string.state_event_room_third_party_revoked_invite_by_you, userId.value)
+ sp.getString(R.string.state_event_room_third_party_revoked_invite_by_you, userDisplayNameOrId)
} else {
- sp.getString(R.string.state_event_room_third_party_revoked_invite, senderDisambiguatedDisplayName, userId.value)
+ sp.getString(R.string.state_event_room_third_party_revoked_invite, senderDisambiguatedDisplayName, userDisplayNameOrId)
}
MembershipChange.KNOCKED -> if (memberIsYou) {
sp.getString(R.string.state_event_room_knock_by_you)
@@ -88,9 +89,9 @@ class RoomMembershipContentFormatter @Inject constructor(
sp.getString(R.string.state_event_room_knock, senderDisambiguatedDisplayName)
}
MembershipChange.KNOCK_ACCEPTED -> if (senderIsYou) {
- sp.getString(R.string.state_event_room_knock_accepted_by_you, userId.value)
+ sp.getString(R.string.state_event_room_knock_accepted_by_you, userDisplayNameOrId)
} else {
- sp.getString(R.string.state_event_room_knock_accepted, senderDisambiguatedDisplayName, userId.value)
+ sp.getString(R.string.state_event_room_knock_accepted, senderDisambiguatedDisplayName, userDisplayNameOrId)
}
MembershipChange.KNOCK_RETRACTED -> if (memberIsYou) {
sp.getString(R.string.state_event_room_knock_retracted_by_you)
@@ -98,11 +99,11 @@ class RoomMembershipContentFormatter @Inject constructor(
sp.getString(R.string.state_event_room_knock_retracted, senderDisambiguatedDisplayName)
}
MembershipChange.KNOCK_DENIED -> if (senderIsYou) {
- sp.getString(R.string.state_event_room_knock_denied_by_you, userId.value)
+ sp.getString(R.string.state_event_room_knock_denied_by_you, userDisplayNameOrId)
} else if (memberIsYou) {
sp.getString(R.string.state_event_room_knock_denied_you, senderDisambiguatedDisplayName)
} else {
- sp.getString(R.string.state_event_room_knock_denied, senderDisambiguatedDisplayName, userId.value)
+ sp.getString(R.string.state_event_room_knock_denied, senderDisambiguatedDisplayName, userDisplayNameOrId)
}
MembershipChange.NONE -> if (senderIsYou) {
sp.getString(R.string.state_event_room_none_by_you)
diff --git a/libraries/eventformatter/impl/src/main/res/values-es/translations.xml b/libraries/eventformatter/impl/src/main/res/values-es/translations.xml
index dc732d9e97..33ed87e423 100644
--- a/libraries/eventformatter/impl/src/main/res/values-es/translations.xml
+++ b/libraries/eventformatter/impl/src/main/res/values-es/translations.xml
@@ -3,12 +3,16 @@
"(el avatar también cambió)"
"%1$s cambió su avatar"
"Cambiaste tu avatar"
+ "%1$s fue degradado a miembro"
+ "%1$s fue degradado a moderador"
"%1$s cambió su nombre de %2$s a %3$s"
"Cambiaste tu nombre de %1$s a %2$s"
"%1$s eliminó su nombre (era %2$s)"
"Eliminaste tu nombre (era %1$s)"
"%1$s cambió su nombre a %2$s"
"Cambiaste tu nombre a %1$s"
+ "%1$s fue ascendido a administrador"
+ "%1$s fue ascendido a moderador"
"%1$s cambió el avatar de la sala"
"Cambiaste el avatar de la sala"
"%1$s eliminó el avatar de la sala"
@@ -39,6 +43,8 @@
"Cambiaste el nombre de la sala a: %1$s"
"%1$s eliminó el nombre de la sala"
"Eliminaste el nombre de la sala"
+ "%1$s no hizo cambios"
+ "No has hecho ningún cambio"
"%1$s rechazó la invitación"
"Rechazaste la invitación"
"%1$s echó a %2$s"
diff --git a/libraries/eventformatter/impl/src/main/res/values-it/translations.xml b/libraries/eventformatter/impl/src/main/res/values-it/translations.xml
index f5250ab40e..2d391404c7 100644
--- a/libraries/eventformatter/impl/src/main/res/values-it/translations.xml
+++ b/libraries/eventformatter/impl/src/main/res/values-it/translations.xml
@@ -30,7 +30,7 @@
"Ti sei unito alla stanza"
"%1$s ha chiesto di unirsi"
"%1$s ha permesso a %2$s di unirsi"
- "%1$s ti ha permesso di unirti"
+ "Hai permesso a %1$s di partecipare"
"Hai richiesto di unirti"
"%1$s ha rifiutato la richiesta di unirsi di %2$s"
"Hai rifiutato la richiesta di unirsi di %1$s"
diff --git a/libraries/eventformatter/impl/src/main/res/values-ka/translations.xml b/libraries/eventformatter/impl/src/main/res/values-ka/translations.xml
new file mode 100644
index 0000000000..7fa4f65716
--- /dev/null
+++ b/libraries/eventformatter/impl/src/main/res/values-ka/translations.xml
@@ -0,0 +1,57 @@
+
+
+ "(ფოტოც შეიცვალა)"
+ "%1$s პროფილის ფოტო შეცვალა"
+ "თქვენ შეცვალეთ პროფილის ფოტო"
+ "%1$s თავისი ნაჩვენები სახელი შეცვალა %2$s დან %3$s ზე"
+ "თქვენ შეცვალეთ თქვენი ნაჩვენები სახელი %1$s -დან %2$s -ზე"
+ "%1$s წაშალა თავისი ნაჩვენები სახელი (იყო %2$s)"
+ "თქვენ წაშალეთ ნაჩვენები სახელი (იყო %1$s)"
+ "%1$s თავისი ნაჩვენები სახელი შეცვალა %2$s"
+ "თქვენი ახალი ნაჩვენები სახელი - %1$s"
+ "%1$s ოთახის ფოტო შეცვალა"
+ "თქვენ შეცვალეთ ოთახის ფოტო"
+ "%1$s წაშალა ოთახის ფოტო"
+ "თქვენ წაშალეთ ოთახის ფოტო"
+ "%1$s დაბლოკა %2$s"
+ "თქვენ დაბლოკეთ %1$s"
+ "%1$s შექმნა ოთახი"
+ "თქვენ შექმენით ოთახი"
+ "%1$s მოიწვია %2$s"
+ "%1$s მიიღო მოწვევა"
+ "თქვენ მიიღეთ მოწვევა"
+ "თქვენ მოიწვიეთ %1$s"
+ "%1$s მოგიწვიათ"
+ "%1$s გაწევრიანდა ოთახში"
+ "თქვენ გაწევრიანდით ოთახში"
+ "%1$s გაწევრიანება მოითხოვა"
+ "%1$s გაწევრიანების უფლება მისცა %2$s"
+ "თქვენ %1$s გაწევრიანების უფლება მიეცით"
+ "თქვენ მოითხოვეთ გაწევრიანება"
+ "%1$s უარი თქვა %2$s-ს გაწევრიანების მოთხოვნაზე"
+ "თქვენ უარი თქვით %1$s გაწევრიანების თხოვნაზე"
+ "%1$s უარი თქვა თქვენს მოთხოვნაზე გაწევრიანების შესახებ"
+ "%1$s აღარ არის დაინტერესებული გაწევრიანებით"
+ "თქვენ გააუქმეთ გაწევრიანების მოთხოვნა"
+ "%1$s დატოვა ოთახი"
+ "თქვენ დატოვეთ ოთახი"
+ "%1$s შეცვალა ოთახის სახელი: %2$s"
+ "თქვენ შეცვალეთ ოთახის სახელი: %1$s"
+ "%1$s წაშალა ოთახის სახელი"
+ "თქვენ წაშალეთ ოთახის სახელი"
+ "%1$s მოწვევაზე უარი თქვა"
+ "თქვენ უარი თქვით მოწვევაზე"
+ "%1$s გააგდო %2$s"
+ "თქვენ გააგდეთ %1$s"
+ "%1$s მოიწვია %2$s ოთახში"
+ "თქვენ მოიწვიეთ %1$s ოთახში"
+ "%1$s გააუქმო %2$s-ს ოთახში მოწვევა"
+ "თქვენ %1$s-ს ოთახში მოწვევა გააუქმეთ"
+ "%1$s შეცვალა თემა: %2$s"
+ "თქვენ შეცვალეთ თემა: %1$s"
+ "%1$s წაშალა ოთახის თემა"
+ "თქვენ წაშალეთ ოთახის თემა"
+ "%1$s განბლოკა %2$s"
+ "თქვენ განბლოკეთ %1$s"
+ "%1$s უცნობი ცვლილება შეიტანა თავის წევრობაში"
+
diff --git a/libraries/eventformatter/impl/src/main/res/values-pt/translations.xml b/libraries/eventformatter/impl/src/main/res/values-pt/translations.xml
new file mode 100644
index 0000000000..6d214ab03e
--- /dev/null
+++ b/libraries/eventformatter/impl/src/main/res/values-pt/translations.xml
@@ -0,0 +1,63 @@
+
+
+ "(avatar alterado também)"
+ "%1$s alterou o seu avatar"
+ "Alteraste o teu avatar"
+ "%1$s foi despromovido a participante"
+ "%1$s foi despromovido a moderador"
+ "%1$s alterou o seu pseudónimo de %2$s para %3$s"
+ "Alteraste o teu pseudónimo de %1$s para %2$s"
+ "%1$s removeu o seu pseudónimo (era %2$s)"
+ "Removeste o teu pseudónimo (era %1$s)"
+ "%1$s definiu o seu pseudónimo como %2$s"
+ "Definiste o teu pseudónimo como %1$s"
+ "%1$s foi promovido a administrador"
+ "%1$s foi promovido a moderador"
+ "%1$s alterou o ícone da sala"
+ "Alteraste o ícone da sala"
+ "%1$s removeu o ícone da sala"
+ "Removeste o ícone da sala"
+ "%1$s baniu %2$s"
+ "Baniste %1$s"
+ "%1$s criou a sala"
+ "Criaste a sala"
+ "%1$s convidou %2$s"
+ "%1$s aceitou o convite"
+ "Aceitaste o convite"
+ "Convidaste %1$s"
+ "%1$s convidou-te"
+ "%1$s entrou na sala"
+ "Entraste na sala"
+ "%1$s pediu para entrar"
+ "%1$s permitiu %2$s entrar"
+ "Permitiste a entrada de %1$s"
+ "Pediste para entrar"
+ "%1$s rejeitou o pedido de entrada de %2$s"
+ "Rejeitaste o pedido de entrada e %1$s"
+ "%1$s rejeitou o teu pedido de entrada"
+ "%1$s deixou de querer entrar"
+ "Cancelaste o teu pedido de entrada"
+ "%1$s saiu da sala"
+ "Saíste da sala"
+ "%1$s alterou o nome da sala para: %2$s"
+ "Alteraste o nome da sala para:%1$s"
+ "%1$s removeu o nome da sala"
+ "Removeste o nome da sala"
+ "%1$s não fiz nenhuma alteração"
+ "Não fizeste nenhuma alteração"
+ "%1$s rejeitou o convite"
+ "Rejeitaste o convite"
+ "%1$s removeu %2$s"
+ "Removeste %1$s"
+ "%1$s enviou um convite a %2$s"
+ "Enviaste um convite a %1$s"
+ "%1$s revogou o convite de %2$s"
+ "Revogaste o convite de %1$s"
+ "%1$s alterou a descrição para: %2$s"
+ "Alteraste a descrição para: %1$s"
+ "%1$s removeu a descrição da sala"
+ "Removeste a descrição da sala"
+ "%1$s desbaniu %2$s"
+ "Anulaste o banimento de %1$s"
+ "%1$s efetuou uma alteração desconhecida à sua participação na sala"
+
diff --git a/libraries/eventformatter/impl/src/main/res/values-ro/translations.xml b/libraries/eventformatter/impl/src/main/res/values-ro/translations.xml
index e3009c4648..8669ff4211 100644
--- a/libraries/eventformatter/impl/src/main/res/values-ro/translations.xml
+++ b/libraries/eventformatter/impl/src/main/res/values-ro/translations.xml
@@ -3,12 +3,16 @@
"(s-a schimbat si avatarul)"
"%1$s și-a schimbat avatarul"
"V-ați schimbat avatarul"
+ "%1$s a fost retrogradat la funcția de membru"
+ "%1$s a fost retrogradat la funcția de moderator"
"%1$s și-a schimbat numele din %2$s în %3$s"
"V-ați schimbat numele din %1$s în %2$s"
"%1$s și-a sters numele (era %2$s)"
"V-ați sters numele (era %1$s)"
"%1$s și-a schimbat numele %2$s"
"V-ați schimbat numele în %1$s"
+ "%1$s a fost promovat în funcția de administrator"
+ "%1$s a fost promovat la funcția de moderator"
"%1$s a schimbat avatarul camerei"
"Ați schimbat avatarul camerei"
"%1$s a șters avatarul camerei"
@@ -26,7 +30,7 @@
"Ați intrat în cameră"
"%1$s a solicitat să se alăture camerei"
"%1$s i-a permis lui %2$s să se alăture camerei"
- "%1$s v-a permis să vă alăturați camerei"
+ "I-ați permis lui %1$s să se alăture"
"Ați solicitat să vă alăturați camerei"
"%1$s a respins solicitarea de alăturare a lui %2$s"
"Ați respins solicitarea de alăturare a lui %1$s"
diff --git a/libraries/eventformatter/impl/src/main/res/values-ru/translations.xml b/libraries/eventformatter/impl/src/main/res/values-ru/translations.xml
index 5e1cde283e..186c594be2 100644
--- a/libraries/eventformatter/impl/src/main/res/values-ru/translations.xml
+++ b/libraries/eventformatter/impl/src/main/res/values-ru/translations.xml
@@ -30,7 +30,7 @@
"Вы присоединились к комнате"
"%1$s запросил присоединение"
"%1$s разрешил %2$s присоединиться"
- "%1$s разрешил вам присоединиться"
+ "Вы разрешили %1$s присоединиться"
"Вы запросили присоединение"
"%1$s отклонил запрос %2$s на присоединение"
"Вы отклонили запрос %1$s на присоединение"
diff --git a/libraries/eventformatter/impl/src/main/res/values-zh/translations.xml b/libraries/eventformatter/impl/src/main/res/values-zh/translations.xml
new file mode 100644
index 0000000000..76a61c6ccc
--- /dev/null
+++ b/libraries/eventformatter/impl/src/main/res/values-zh/translations.xml
@@ -0,0 +1,63 @@
+
+
+ "(头像也更改了)"
+ "%1$s 更换了头像"
+ "你更换了头像"
+ "%1$s 降级为成员"
+ "%1$s 降级为协管员"
+ "%1$s 把显示名称从 %2$s 更改为 %3$s"
+ "你将显示名称从 %1$s 更改为 %2$s"
+ "%1$s 移除了其显示名称(原为 %2$s)"
+ "你移除了自己的显示名称(原为 %1$s)"
+ "%1$s 将其显示名称设置为 %2$s"
+ "你将显示名称设置为 %1$s"
+ "%1$s 晋升为管理员"
+ "%1$s 晋升为协管员"
+ "%1$s 更换了房间头像"
+ "你更换了房间头像"
+ "%1$s 移除了房间头像"
+ "你移除了房间头像"
+ "%1$s 封禁了 %2$s"
+ "你封禁了 %1$s"
+ "%1$s 创建了房间"
+ "你创建了房间"
+ "%1$s 邀请了 %2$s"
+ "%1$s 接受了邀请"
+ "你接受了邀请"
+ "你邀请了 %1$s"
+ "%1$s 邀请了你"
+ "%1$s 加入了房间"
+ "你加入了房间"
+ "%1$s 请求加入"
+ "%1$s 允许 %2$s 加入"
+ "您已允许 %1$s 加入"
+ "你已请求加入"
+ "%1$s 拒绝了 %2$s 的加入请求"
+ "你拒绝了 %1$s 的加入请求"
+ "%1$s 拒绝了你的加入请求"
+ "%1$s 已不再想加入"
+ "你取消了加入申请"
+ "%1$s 离开了房间"
+ "你离开了房间"
+ "%1$s 将房间名称改为 %2$s"
+ "你把房间名称改为 %1$s"
+ "%1$s 移除了房间名称"
+ "你移除了房间名称"
+ "%1$s 没有任何更改"
+ "您未进行任何更改"
+ "%1$s 拒绝了邀请"
+ "你拒绝了邀请"
+ "%1$s 移除了 %2$s"
+ "你移除了 %1$s"
+ "%1$s向%2$s发送了加入房间的邀请"
+ "你邀请 %1$s 加入房间"
+ "%1$s 撤销了 %2$s 加入房间的邀请"
+ "你撤销了 %1$s 加入房间的邀请"
+ "%1$s 将主题改为:%2$s"
+ "你将主题改为:%1$s"
+ "%1$s 移除了房间主题"
+ "你移除了房间主题"
+ "%1$s 解禁了 %2$s"
+ "你解禁了 %1$s"
+ "%1$s 对其成员资格进行了未知更改"
+
diff --git a/libraries/eventformatter/impl/src/test/kotlin/io/element/android/libraries/eventformatter/impl/DefaultRoomLastMessageFormatterTest.kt b/libraries/eventformatter/impl/src/test/kotlin/io/element/android/libraries/eventformatter/impl/DefaultRoomLastMessageFormatterTest.kt
index 9ee1dce352..f5e151b541 100644
--- a/libraries/eventformatter/impl/src/test/kotlin/io/element/android/libraries/eventformatter/impl/DefaultRoomLastMessageFormatterTest.kt
+++ b/libraries/eventformatter/impl/src/test/kotlin/io/element/android/libraries/eventformatter/impl/DefaultRoomLastMessageFormatterTest.kt
@@ -254,9 +254,9 @@ class DefaultRoomLastMessageFormatterTest {
@Test
@Config(qualifiers = "en")
fun `Membership change - joined`() {
- val otherName = "Someone"
- val youContent = RoomMembershipContent(A_USER_ID, MembershipChange.JOINED)
- val someoneContent = RoomMembershipContent(UserId("@someone_else:domain"), MembershipChange.JOINED)
+ val otherName = "Other"
+ val youContent = RoomMembershipContent(A_USER_ID, null, MembershipChange.JOINED)
+ val someoneContent = RoomMembershipContent(UserId("@someone_else:domain"), otherName, MembershipChange.JOINED)
val youJoinedRoomEvent = createRoomEvent(sentByYou = true, senderDisplayName = null, content = youContent)
val youJoinedRoom = formatter.format(youJoinedRoomEvent, false)
@@ -270,9 +270,9 @@ class DefaultRoomLastMessageFormatterTest {
@Test
@Config(qualifiers = "en")
fun `Membership change - left`() {
- val otherName = "Someone"
- val youContent = RoomMembershipContent(A_USER_ID, MembershipChange.LEFT)
- val someoneContent = RoomMembershipContent(UserId("@someone_else:domain"), MembershipChange.LEFT)
+ val otherName = "Other"
+ val youContent = RoomMembershipContent(A_USER_ID, null, MembershipChange.LEFT)
+ val someoneContent = RoomMembershipContent(UserId("@someone_else:domain"), otherName, MembershipChange.LEFT)
val youLeftRoomEvent = createRoomEvent(sentByYou = true, senderDisplayName = null, content = youContent)
val youLeftRoom = formatter.format(youLeftRoomEvent, false)
@@ -286,67 +286,71 @@ class DefaultRoomLastMessageFormatterTest {
@Test
@Config(qualifiers = "en")
fun `Membership change - banned`() {
- val otherName = "Someone"
- val youContent = RoomMembershipContent(UserId("@someone_else:domain"), MembershipChange.BANNED)
- val youKickedContent = RoomMembershipContent(UserId("@someone_else:domain"), MembershipChange.KICKED_AND_BANNED)
- val someoneContent = RoomMembershipContent(UserId("@someone_else:domain"), MembershipChange.BANNED)
- val someoneKickedContent = RoomMembershipContent(UserId("@someone_else:domain"), MembershipChange.KICKED_AND_BANNED)
+ val otherName = "Other"
+ val third = "Someone"
+ val youContent = RoomMembershipContent(UserId("@someone_else:domain"), third, MembershipChange.BANNED)
+ val youKickedContent = RoomMembershipContent(UserId("@someone_else:domain"), third, MembershipChange.KICKED_AND_BANNED)
+ val someoneContent = RoomMembershipContent(UserId("@someone_else:domain"), third, MembershipChange.BANNED)
+ val someoneKickedContent = RoomMembershipContent(UserId("@someone_else:domain"), third, MembershipChange.KICKED_AND_BANNED)
val youBannedEvent = createRoomEvent(sentByYou = true, senderDisplayName = null, content = youContent)
val youBanned = formatter.format(youBannedEvent, false)
- assertThat(youBanned).isEqualTo("You banned ${youContent.userId}")
+ assertThat(youBanned).isEqualTo("You banned $third")
val youKickBannedEvent = createRoomEvent(sentByYou = true, senderDisplayName = null, content = youKickedContent)
val youKickedBanned = formatter.format(youKickBannedEvent, false)
- assertThat(youKickedBanned).isEqualTo("You banned ${youContent.userId}")
+ assertThat(youKickedBanned).isEqualTo("You banned $third")
val someoneBannedEvent = createRoomEvent(sentByYou = false, senderDisplayName = otherName, content = someoneContent)
val someoneBanned = formatter.format(someoneBannedEvent, false)
- assertThat(someoneBanned).isEqualTo("$otherName banned ${someoneContent.userId}")
+ assertThat(someoneBanned).isEqualTo("$otherName banned $third")
val someoneKickBannedEvent = createRoomEvent(sentByYou = false, senderDisplayName = otherName, content = someoneKickedContent)
val someoneKickBanned = formatter.format(someoneKickBannedEvent, false)
- assertThat(someoneKickBanned).isEqualTo("$otherName banned ${someoneContent.userId}")
+ assertThat(someoneKickBanned).isEqualTo("$otherName banned $third")
}
@Test
@Config(qualifiers = "en")
fun `Membership change - unban`() {
- val otherName = "Someone"
- val youContent = RoomMembershipContent(UserId("@someone_else:domain"), MembershipChange.UNBANNED)
- val someoneContent = RoomMembershipContent(UserId("@someone_else:domain"), MembershipChange.UNBANNED)
+ val otherName = "Other"
+ val third = "Someone"
+ val youContent = RoomMembershipContent(UserId("@someone_else:domain"), third, MembershipChange.UNBANNED)
+ val someoneContent = RoomMembershipContent(UserId("@someone_else:domain"), third, MembershipChange.UNBANNED)
val youUnbannedEvent = createRoomEvent(sentByYou = true, senderDisplayName = null, content = youContent)
val youUnbanned = formatter.format(youUnbannedEvent, false)
- assertThat(youUnbanned).isEqualTo("You unbanned ${youContent.userId}")
+ assertThat(youUnbanned).isEqualTo("You unbanned $third")
val someoneUnbannedEvent = createRoomEvent(sentByYou = false, senderDisplayName = otherName, content = someoneContent)
val someoneUnbanned = formatter.format(someoneUnbannedEvent, false)
- assertThat(someoneUnbanned).isEqualTo("$otherName unbanned ${someoneContent.userId}")
+ assertThat(someoneUnbanned).isEqualTo("$otherName unbanned $third")
}
@Test
@Config(qualifiers = "en")
fun `Membership change - kicked`() {
- val otherName = "Someone"
- val youContent = RoomMembershipContent(UserId("@someone_else:domain"), MembershipChange.KICKED)
- val someoneContent = RoomMembershipContent(UserId("@someone_else:domain"), MembershipChange.KICKED)
+ val otherName = "Other"
+ val third = "Someone"
+ val youContent = RoomMembershipContent(UserId("@someone_else:domain"), third, MembershipChange.KICKED)
+ val someoneContent = RoomMembershipContent(UserId("@someone_else:domain"), third, MembershipChange.KICKED)
val youKickedEvent = createRoomEvent(sentByYou = true, senderDisplayName = null, content = youContent)
val youKicked = formatter.format(youKickedEvent, false)
- assertThat(youKicked).isEqualTo("You removed ${youContent.userId}")
+ assertThat(youKicked).isEqualTo("You removed $third")
val someoneKickedEvent = createRoomEvent(sentByYou = false, senderDisplayName = otherName, content = someoneContent)
val someoneKicked = formatter.format(someoneKickedEvent, false)
- assertThat(someoneKicked).isEqualTo("$otherName removed ${someoneContent.userId}")
+ assertThat(someoneKicked).isEqualTo("$otherName removed $third")
}
@Test
@Config(qualifiers = "en")
fun `Membership change - invited`() {
- val otherName = "Someone"
- val youContent = RoomMembershipContent(A_USER_ID, MembershipChange.INVITED)
- val someoneContent = RoomMembershipContent(UserId("@someone_else:domain"), MembershipChange.INVITED)
+ val otherName = "Other"
+ val third = "Someone"
+ val youContent = RoomMembershipContent(A_USER_ID, null, MembershipChange.INVITED)
+ val someoneContent = RoomMembershipContent(UserId("@someone_else:domain"), third, MembershipChange.INVITED)
val youWereInvitedEvent = createRoomEvent(sentByYou = false, senderDisplayName = otherName, content = youContent)
val youWereInvited = formatter.format(youWereInvitedEvent, false)
@@ -354,19 +358,19 @@ class DefaultRoomLastMessageFormatterTest {
val youInvitedEvent = createRoomEvent(sentByYou = true, senderDisplayName = null, content = someoneContent)
val youInvited = formatter.format(youInvitedEvent, false)
- assertThat(youInvited).isEqualTo("You invited ${someoneContent.userId}")
+ assertThat(youInvited).isEqualTo("You invited $third")
val someoneInvitedEvent = createRoomEvent(sentByYou = false, senderDisplayName = otherName, content = someoneContent)
val someoneInvited = formatter.format(someoneInvitedEvent, false)
- assertThat(someoneInvited).isEqualTo("$otherName invited ${someoneContent.userId}")
+ assertThat(someoneInvited).isEqualTo("$otherName invited $third")
}
@Test
@Config(qualifiers = "en")
fun `Membership change - invitation accepted`() {
- val otherName = "Someone"
- val youContent = RoomMembershipContent(A_USER_ID, MembershipChange.INVITATION_ACCEPTED)
- val someoneContent = RoomMembershipContent(UserId("@someone_else:domain"), MembershipChange.INVITATION_ACCEPTED)
+ val otherName = "Other"
+ val youContent = RoomMembershipContent(A_USER_ID, null, MembershipChange.INVITATION_ACCEPTED)
+ val someoneContent = RoomMembershipContent(UserId("@someone_else:domain"), otherName, MembershipChange.INVITATION_ACCEPTED)
val youAcceptedInviteEvent = createRoomEvent(sentByYou = true, senderDisplayName = null, content = youContent)
val youAcceptedInvite = formatter.format(youAcceptedInviteEvent, false)
@@ -374,15 +378,15 @@ class DefaultRoomLastMessageFormatterTest {
val someoneAcceptedInviteEvent = createRoomEvent(sentByYou = false, senderDisplayName = otherName, content = someoneContent)
val someoneAcceptedInvite = formatter.format(someoneAcceptedInviteEvent, false)
- assertThat(someoneAcceptedInvite).isEqualTo("${someoneContent.userId} accepted the invite")
+ assertThat(someoneAcceptedInvite).isEqualTo("$otherName accepted the invite")
}
@Test
@Config(qualifiers = "en")
fun `Membership change - invitation rejected`() {
- val otherName = "Someone"
- val youContent = RoomMembershipContent(A_USER_ID, MembershipChange.INVITATION_REJECTED)
- val someoneContent = RoomMembershipContent(UserId("@someone_else:domain"), MembershipChange.INVITATION_REJECTED)
+ val otherName = "Other"
+ val youContent = RoomMembershipContent(A_USER_ID, null, MembershipChange.INVITATION_REJECTED)
+ val someoneContent = RoomMembershipContent(UserId("@someone_else:domain"), otherName, MembershipChange.INVITATION_REJECTED)
val youRejectedInviteEvent = createRoomEvent(sentByYou = true, senderDisplayName = null, content = youContent)
val youRejectedInvite = formatter.format(youRejectedInviteEvent, false)
@@ -390,30 +394,31 @@ class DefaultRoomLastMessageFormatterTest {
val someoneRejectedInviteEvent = createRoomEvent(sentByYou = false, senderDisplayName = otherName, content = someoneContent)
val someoneRejectedInvite = formatter.format(someoneRejectedInviteEvent, false)
- assertThat(someoneRejectedInvite).isEqualTo("${someoneContent.userId} rejected the invitation")
+ assertThat(someoneRejectedInvite).isEqualTo("$otherName rejected the invitation")
}
@Test
@Config(qualifiers = "en")
fun `Membership change - invitation revoked`() {
- val otherName = "Someone"
- val someoneContent = RoomMembershipContent(UserId("@someone_else:domain"), MembershipChange.INVITATION_REVOKED)
+ val otherName = "Other"
+ val third = "Someone"
+ val someoneContent = RoomMembershipContent(UserId("@someone_else:domain"), third, MembershipChange.INVITATION_REVOKED)
val youRevokedInviteEvent = createRoomEvent(sentByYou = true, senderDisplayName = null, content = someoneContent)
val youRevokedInvite = formatter.format(youRevokedInviteEvent, false)
- assertThat(youRevokedInvite).isEqualTo("You revoked the invitation for ${someoneContent.userId} to join the room")
+ assertThat(youRevokedInvite).isEqualTo("You revoked the invitation for $third to join the room")
val someoneRevokedInviteEvent = createRoomEvent(sentByYou = false, senderDisplayName = otherName, content = someoneContent)
val someoneRevokedInvite = formatter.format(someoneRevokedInviteEvent, false)
- assertThat(someoneRevokedInvite).isEqualTo("$otherName revoked the invitation for ${someoneContent.userId} to join the room")
+ assertThat(someoneRevokedInvite).isEqualTo("$otherName revoked the invitation for $third to join the room")
}
@Test
@Config(qualifiers = "en")
fun `Membership change - knocked`() {
- val otherName = "Someone"
- val youContent = RoomMembershipContent(A_USER_ID, MembershipChange.KNOCKED)
- val someoneContent = RoomMembershipContent(UserId("@someone_else:domain"), MembershipChange.KNOCKED)
+ val otherName = "Other"
+ val youContent = RoomMembershipContent(A_USER_ID, null, MembershipChange.KNOCKED)
+ val someoneContent = RoomMembershipContent(UserId("@someone_else:domain"), otherName, MembershipChange.KNOCKED)
val youKnockedEvent = createRoomEvent(sentByYou = true, senderDisplayName = null, content = youContent)
val youKnocked = formatter.format(youKnockedEvent, false)
@@ -427,24 +432,25 @@ class DefaultRoomLastMessageFormatterTest {
@Test
@Config(qualifiers = "en")
fun `Membership change - knock accepted`() {
- val otherName = "Someone"
- val someoneContent = RoomMembershipContent(UserId("@someone_else:domain"), MembershipChange.KNOCK_ACCEPTED)
+ val otherName = "Other"
+ val third = "Someone"
+ val someoneContent = RoomMembershipContent(UserId("@someone_else:domain"), third, MembershipChange.KNOCK_ACCEPTED)
val youAcceptedKnockEvent = createRoomEvent(sentByYou = true, senderDisplayName = null, content = someoneContent)
val youAcceptedKnock = formatter.format(youAcceptedKnockEvent, false)
- assertThat(youAcceptedKnock).isEqualTo("You allowed ${someoneContent.userId} to join")
+ assertThat(youAcceptedKnock).isEqualTo("You allowed $third to join")
val someoneAcceptedKnockEvent = createRoomEvent(sentByYou = false, senderDisplayName = otherName, content = someoneContent)
val someoneAcceptedKnock = formatter.format(someoneAcceptedKnockEvent, false)
- assertThat(someoneAcceptedKnock).isEqualTo("$otherName allowed ${someoneContent.userId} to join")
+ assertThat(someoneAcceptedKnock).isEqualTo("$otherName allowed $third to join")
}
@Test
@Config(qualifiers = "en")
fun `Membership change - knock retracted`() {
- val otherName = "Someone"
- val youContent = RoomMembershipContent(A_USER_ID, MembershipChange.KNOCK_RETRACTED)
- val someoneContent = RoomMembershipContent(UserId("@someone_else:domain"), MembershipChange.KNOCK_RETRACTED)
+ val otherName = "Other"
+ val youContent = RoomMembershipContent(A_USER_ID, null, MembershipChange.KNOCK_RETRACTED)
+ val someoneContent = RoomMembershipContent(UserId("@someone_else:domain"), null, MembershipChange.KNOCK_RETRACTED)
val youRetractedKnockEvent = createRoomEvent(sentByYou = true, senderDisplayName = null, content = youContent)
val youRetractedKnock = formatter.format(youRetractedKnockEvent, false)
@@ -458,17 +464,18 @@ class DefaultRoomLastMessageFormatterTest {
@Test
@Config(qualifiers = "en")
fun `Membership change - knock denied`() {
- val otherName = "Someone"
- val youContent = RoomMembershipContent(A_USER_ID, MembershipChange.KNOCK_DENIED)
- val someoneContent = RoomMembershipContent(UserId("@someone_else:domain"), MembershipChange.KNOCK_DENIED)
+ val otherName = "Other"
+ val third = "Someone"
+ val youContent = RoomMembershipContent(A_USER_ID, third, MembershipChange.KNOCK_DENIED)
+ val someoneContent = RoomMembershipContent(UserId("@someone_else:domain"), third, MembershipChange.KNOCK_DENIED)
val youDeniedKnockEvent = createRoomEvent(sentByYou = true, senderDisplayName = null, content = someoneContent)
val youDeniedKnock = formatter.format(youDeniedKnockEvent, false)
- assertThat(youDeniedKnock).isEqualTo("You rejected ${someoneContent.userId}'s request to join")
+ assertThat(youDeniedKnock).isEqualTo("You rejected $third's request to join")
val someoneDeniedKnockEvent = createRoomEvent(sentByYou = false, senderDisplayName = otherName, content = someoneContent)
val someoneDeniedKnock = formatter.format(someoneDeniedKnockEvent, false)
- assertThat(someoneDeniedKnock).isEqualTo("$otherName rejected ${someoneContent.userId}'s request to join")
+ assertThat(someoneDeniedKnock).isEqualTo("$otherName rejected $third's request to join")
val someoneDeniedYourKnockEvent = createRoomEvent(sentByYou = false, senderDisplayName = otherName, content = youContent)
val someoneDeniedYourKnock = formatter.format(someoneDeniedYourKnockEvent, false)
@@ -478,9 +485,9 @@ class DefaultRoomLastMessageFormatterTest {
@Test
@Config(qualifiers = "en")
fun `Membership change - None`() {
- val otherName = "Someone"
- val youContent = RoomMembershipContent(A_USER_ID, MembershipChange.NONE)
- val someoneContent = RoomMembershipContent(UserId("@someone_else:domain"), MembershipChange.NONE)
+ val otherName = "Other"
+ val youContent = RoomMembershipContent(A_USER_ID, null, MembershipChange.NONE)
+ val someoneContent = RoomMembershipContent(UserId("@someone_else:domain"), otherName, MembershipChange.NONE)
val youNoneRoomEvent = createRoomEvent(sentByYou = true, senderDisplayName = null, content = youContent)
val youNoneRoom = formatter.format(youNoneRoomEvent, false)
@@ -497,7 +504,7 @@ class DefaultRoomLastMessageFormatterTest {
val otherChanges = arrayOf(MembershipChange.ERROR, MembershipChange.NOT_IMPLEMENTED, null)
val results = otherChanges.map { change ->
- val content = RoomMembershipContent(A_USER_ID, change)
+ val content = RoomMembershipContent(A_USER_ID, null, change)
val event = createRoomEvent(sentByYou = false, senderDisplayName = "Someone", content = content)
val result = formatter.format(event, false)
change to result
@@ -513,7 +520,7 @@ class DefaultRoomLastMessageFormatterTest {
@Test
@Config(qualifiers = "en")
fun `Room state change - avatar`() {
- val otherName = "Someone"
+ val otherName = "Other"
val changedContent = StateContent("", OtherState.RoomAvatar("new_avatar"))
val removedContent = StateContent("", OtherState.RoomAvatar(null))
@@ -537,7 +544,7 @@ class DefaultRoomLastMessageFormatterTest {
@Test
@Config(qualifiers = "en")
fun `Room state change - create`() {
- val otherName = "Someone"
+ val otherName = "Other"
val content = StateContent("", OtherState.RoomCreate)
val youCreatedRoomMessage = createRoomEvent(sentByYou = true, senderDisplayName = null, content = content)
@@ -552,7 +559,7 @@ class DefaultRoomLastMessageFormatterTest {
@Test
@Config(qualifiers = "en")
fun `Room state change - encryption`() {
- val otherName = "Someone"
+ val otherName = "Other"
val content = StateContent("", OtherState.RoomEncryption)
val youCreatedRoomMessage = createRoomEvent(sentByYou = true, senderDisplayName = null, content = content)
@@ -567,7 +574,7 @@ class DefaultRoomLastMessageFormatterTest {
@Test
@Config(qualifiers = "en")
fun `Room state change - room name`() {
- val otherName = "Someone"
+ val otherName = "Other"
val newName = "New name"
val changedContent = StateContent("", OtherState.RoomName(newName))
val removedContent = StateContent("", OtherState.RoomName(null))
@@ -592,7 +599,7 @@ class DefaultRoomLastMessageFormatterTest {
@Test
@Config(qualifiers = "en")
fun `Room state change - third party invite`() {
- val otherName = "Someone"
+ val otherName = "Other"
val inviteeName = "Alice"
val changedContent = StateContent("", OtherState.RoomThirdPartyInvite(inviteeName))
val removedContent = StateContent("", OtherState.RoomThirdPartyInvite(null))
@@ -617,7 +624,7 @@ class DefaultRoomLastMessageFormatterTest {
@Test
@Config(qualifiers = "en")
fun `Room state change - room topic`() {
- val otherName = "Someone"
+ val otherName = "Other"
val roomTopic = "New topic"
val changedContent = StateContent("", OtherState.RoomTopic(roomTopic))
val removedContent = StateContent("", OtherState.RoomTopic(null))
@@ -677,7 +684,7 @@ class DefaultRoomLastMessageFormatterTest {
@Test
@Config(qualifiers = "en")
fun `Profile change - avatar`() {
- val otherName = "Someone"
+ val otherName = "Other"
val changedContent = aProfileChangeMessageContent(avatarUrl = "new_avatar_url", prevAvatarUrl = "old_avatar_url")
val setContent = aProfileChangeMessageContent(avatarUrl = "new_avatar_url", prevAvatarUrl = null)
val removedContent = aProfileChangeMessageContent(avatarUrl = null, prevAvatarUrl = "old_avatar_url")
@@ -722,7 +729,7 @@ class DefaultRoomLastMessageFormatterTest {
fun `Profile change - display name`() {
val newDisplayName = "New"
val oldDisplayName = "Old"
- val otherName = "Someone"
+ val otherName = "Other"
val changedContent = aProfileChangeMessageContent(displayName = newDisplayName, prevDisplayName = oldDisplayName)
val setContent = aProfileChangeMessageContent(displayName = newDisplayName, prevDisplayName = null)
val removedContent = aProfileChangeMessageContent(displayName = null, prevDisplayName = oldDisplayName)
diff --git a/libraries/indicator/impl/src/main/kotlin/io/element/android/libraries/indicator/impl/DefaultIndicatorService.kt b/libraries/indicator/impl/src/main/kotlin/io/element/android/libraries/indicator/impl/DefaultIndicatorService.kt
index aae0f1f913..6b72b31d19 100644
--- a/libraries/indicator/impl/src/main/kotlin/io/element/android/libraries/indicator/impl/DefaultIndicatorService.kt
+++ b/libraries/indicator/impl/src/main/kotlin/io/element/android/libraries/indicator/impl/DefaultIndicatorService.kt
@@ -38,7 +38,7 @@ class DefaultIndicatorService @Inject constructor(
) : IndicatorService {
@Composable
override fun showRoomListTopBarIndicator(): State {
- val canVerifySession by sessionVerificationService.canVerifySessionFlow.collectAsState(initial = false)
+ val canVerifySession by sessionVerificationService.needsSessionVerification.collectAsState(initial = false)
val settingChatBackupIndicator = showSettingChatBackupIndicator()
return remember {
diff --git a/libraries/matrix/api/build.gradle.kts b/libraries/matrix/api/build.gradle.kts
index 6219296732..b551dfa919 100644
--- a/libraries/matrix/api/build.gradle.kts
+++ b/libraries/matrix/api/build.gradle.kts
@@ -38,6 +38,7 @@ dependencies {
implementation(libs.dagger)
implementation(projects.libraries.androidutils)
implementation(projects.libraries.core)
+ implementation(projects.services.analytics.api)
implementation(libs.serialization.json)
api(projects.libraries.sessionStorage.api)
implementation(libs.coroutines.core)
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 fb20e16c9d..a4b808d653 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
@@ -19,7 +19,6 @@ package io.element.android.libraries.matrix.api
import io.element.android.libraries.matrix.api.core.ProgressCallback
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.SessionId
import io.element.android.libraries.matrix.api.core.UserId
import io.element.android.libraries.matrix.api.createroom.CreateRoomParameters
@@ -32,6 +31,7 @@ import io.element.android.libraries.matrix.api.pusher.PushersService
import io.element.android.libraries.matrix.api.room.MatrixRoom
import io.element.android.libraries.matrix.api.room.MatrixRoomInfo
import io.element.android.libraries.matrix.api.room.RoomMembershipObserver
+import io.element.android.libraries.matrix.api.room.alias.ResolvedRoomAlias
import io.element.android.libraries.matrix.api.room.preview.RoomPreview
import io.element.android.libraries.matrix.api.roomdirectory.RoomDirectoryService
import io.element.android.libraries.matrix.api.roomlist.RoomListService
@@ -66,6 +66,7 @@ interface MatrixClient : Closeable {
suspend fun uploadAvatar(mimeType: String, data: ByteArray): Result
suspend fun removeAvatar(): Result
suspend fun joinRoom(roomId: RoomId): Result
+ suspend fun joinRoomByIdOrAlias(roomId: RoomId, serverNames: List): Result
suspend fun knockRoom(roomId: RoomId): Result
fun syncService(): SyncService
fun sessionVerificationService(): SessionVerificationService
@@ -102,6 +103,6 @@ interface MatrixClient : Closeable {
suspend fun trackRecentlyVisitedRoom(roomId: RoomId): Result
suspend fun getRecentlyVisitedRooms(): Result>
- suspend fun resolveRoomAlias(roomAlias: RoomAlias): Result
- suspend fun getRoomPreview(roomIdOrAlias: RoomIdOrAlias): Result
+ suspend fun resolveRoomAlias(roomAlias: RoomAlias): Result
+ suspend fun getRoomPreviewFromRoomId(roomId: RoomId, serverNames: List): Result
}
diff --git a/services/analytics/api/src/main/kotlin/io/element/android/services/analytics/api/extensions/ViewRoomExt.kt b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/analytics/ViewRoomExt.kt
similarity index 81%
rename from services/analytics/api/src/main/kotlin/io/element/android/services/analytics/api/extensions/ViewRoomExt.kt
rename to libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/analytics/ViewRoomExt.kt
index 2845129fa8..ecc5ce8d7c 100644
--- a/services/analytics/api/src/main/kotlin/io/element/android/services/analytics/api/extensions/ViewRoomExt.kt
+++ b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/analytics/ViewRoomExt.kt
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2022 New Vector Ltd
+ * Copyright (c) 2024 New Vector Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -14,12 +14,16 @@
* limitations under the License.
*/
-package io.element.android.services.analytics.api.extensions
+package io.element.android.libraries.matrix.api.analytics
import im.vector.app.features.analytics.plan.ViewRoom
import io.element.android.libraries.matrix.api.room.MatrixRoom
-fun MatrixRoom.toAnalyticsViewRoom(trigger: ViewRoom.Trigger? = null, selectedSpace: MatrixRoom? = null, viaKeyboard: Boolean? = null): ViewRoom {
+fun MatrixRoom.toAnalyticsViewRoom(
+ trigger: ViewRoom.Trigger? = null,
+ selectedSpace: MatrixRoom? = null,
+ viaKeyboard: Boolean? = null,
+): ViewRoom {
val activeSpace = selectedSpace?.toActiveSpace() ?: ViewRoom.ActiveSpace.Home
return ViewRoom(
diff --git a/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/pusher/PushersService.kt b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/pusher/PushersService.kt
index 71a642965f..2a16e7be35 100644
--- a/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/pusher/PushersService.kt
+++ b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/pusher/PushersService.kt
@@ -18,5 +18,5 @@ package io.element.android.libraries.matrix.api.pusher
interface PushersService {
suspend fun setHttpPusher(setHttpPusherData: SetHttpPusherData): Result
- suspend fun unsetHttpPusher(): Result
+ suspend fun unsetHttpPusher(unsetHttpPusherData: UnsetHttpPusherData): Result
}
diff --git a/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/pusher/UnsetHttpPusherData.kt b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/pusher/UnsetHttpPusherData.kt
new file mode 100644
index 0000000000..2bd91a6d02
--- /dev/null
+++ b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/pusher/UnsetHttpPusherData.kt
@@ -0,0 +1,22 @@
+/*
+ * Copyright (c) 2024 New Vector Ltd
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package io.element.android.libraries.matrix.api.pusher
+
+data class UnsetHttpPusherData(
+ val pushKey: String,
+ val appId: String,
+)
diff --git a/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/room/MatrixRoomInfo.kt b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/room/MatrixRoomInfo.kt
index eea1cc9c1b..8379d30781 100644
--- a/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/room/MatrixRoomInfo.kt
+++ b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/room/MatrixRoomInfo.kt
@@ -27,7 +27,10 @@ import kotlinx.collections.immutable.ImmutableMap
@Immutable
data class MatrixRoomInfo(
val id: RoomId,
+ /** The room's name from the room state event if received from sync, or one that's been computed otherwise. */
val name: String?,
+ /** Room name as defined by the room state event only. */
+ val rawName: String?,
val topic: String?,
val avatarUrl: String?,
val isDirect: Boolean,
diff --git a/features/roomdirectory/impl/src/main/kotlin/io/element/android/features/roomdirectory/impl/root/di/JoinRoom.kt b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/room/alias/ResolvedRoomAlias.kt
similarity index 54%
rename from features/roomdirectory/impl/src/main/kotlin/io/element/android/features/roomdirectory/impl/root/di/JoinRoom.kt
rename to libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/room/alias/ResolvedRoomAlias.kt
index 477b49e4f6..9046664917 100644
--- a/features/roomdirectory/impl/src/main/kotlin/io/element/android/features/roomdirectory/impl/root/di/JoinRoom.kt
+++ b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/room/alias/ResolvedRoomAlias.kt
@@ -14,19 +14,20 @@
* limitations under the License.
*/
-package io.element.android.features.roomdirectory.impl.root.di
+package io.element.android.libraries.matrix.api.room.alias
-import com.squareup.anvil.annotations.ContributesBinding
-import io.element.android.libraries.di.SessionScope
-import io.element.android.libraries.matrix.api.MatrixClient
import io.element.android.libraries.matrix.api.core.RoomId
-import javax.inject.Inject
-interface JoinRoom {
- suspend operator fun invoke(roomId: RoomId): Result
-}
-
-@ContributesBinding(SessionScope::class)
-class DefaultJoinRoom @Inject constructor(private val client: MatrixClient) : JoinRoom {
- override suspend fun invoke(roomId: RoomId) = client.joinRoom(roomId)
-}
+/**
+ * Information about a room, that was resolved from a room alias.
+ */
+data class ResolvedRoomAlias(
+ /**
+ * The room ID that the alias resolved to.
+ */
+ val roomId: RoomId,
+ /**
+ * A list of servers that can be used to find the room by its room ID.
+ */
+ val servers: List
+)
diff --git a/features/roomdirectory/impl/src/test/kotlin/io/element/android/features/roomdirectory/impl/root/FakeJoinRoom.kt b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/room/join/JoinRoom.kt
similarity index 69%
rename from features/roomdirectory/impl/src/test/kotlin/io/element/android/features/roomdirectory/impl/root/FakeJoinRoom.kt
rename to libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/room/join/JoinRoom.kt
index 6251bcaefa..fe6a2d9e47 100644
--- a/features/roomdirectory/impl/src/test/kotlin/io/element/android/features/roomdirectory/impl/root/FakeJoinRoom.kt
+++ b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/room/join/JoinRoom.kt
@@ -14,13 +14,15 @@
* limitations under the License.
*/
-package io.element.android.features.roomdirectory.impl.root
+package io.element.android.libraries.matrix.api.room.join
-import io.element.android.features.roomdirectory.impl.root.di.JoinRoom
+import im.vector.app.features.analytics.plan.JoinedRoom
import io.element.android.libraries.matrix.api.core.RoomId
-class FakeJoinRoom(
- var lambda: (RoomId) -> Result = { Result.success(Unit) }
-) : JoinRoom {
- override suspend fun invoke(roomId: RoomId) = lambda(roomId)
+interface JoinRoom {
+ suspend operator fun invoke(
+ roomId: RoomId,
+ serverNames: List,
+ trigger: JoinedRoom.Trigger,
+ ): Result
}
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 c0aac298a8..0150c78a4a 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
@@ -73,6 +73,7 @@ data class UnableToDecryptContent(
data class RoomMembershipContent(
val userId: UserId,
+ val userDisplayName: String?,
val change: MembershipChange?
) : EventContent
diff --git a/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/verification/SessionVerificationService.kt b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/verification/SessionVerificationService.kt
index 8d22fc174e..01687d754a 100644
--- a/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/verification/SessionVerificationService.kt
+++ b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/verification/SessionVerificationService.kt
@@ -26,12 +26,6 @@ interface SessionVerificationService {
*/
val verificationFlowState: StateFlow
- /**
- * The internal service that checks verification can only run after the initial sync.
- * This [StateFlow] will notify consumers when the service is ready to be used.
- */
- val isReady: StateFlow
-
/**
* Returns whether the current verification status is either: [SessionVerifiedStatus.Unknown], [SessionVerifiedStatus.NotVerified]
* or [SessionVerifiedStatus.Verified].
@@ -39,9 +33,9 @@ interface SessionVerificationService {
val sessionVerifiedStatus: StateFlow
/**
- * Returns whether the current session needs to be verified and the SDK is ready to start the verification.
+ * Returns whether the current session needs to be verified.
*/
- val canVerifySessionFlow: Flow
+ val needsSessionVerification: Flow
/**
* Request verification of the current session.
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 7b6ec13268..2dd28a1ae0 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
@@ -25,7 +25,6 @@ import io.element.android.libraries.matrix.api.MatrixClient
import io.element.android.libraries.matrix.api.core.ProgressCallback
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.createroom.CreateRoomParameters
import io.element.android.libraries.matrix.api.createroom.RoomPreset
@@ -39,6 +38,7 @@ import io.element.android.libraries.matrix.api.pusher.PushersService
import io.element.android.libraries.matrix.api.room.MatrixRoom
import io.element.android.libraries.matrix.api.room.MatrixRoomInfo
import io.element.android.libraries.matrix.api.room.RoomMembershipObserver
+import io.element.android.libraries.matrix.api.room.alias.ResolvedRoomAlias
import io.element.android.libraries.matrix.api.room.preview.RoomPreview
import io.element.android.libraries.matrix.api.roomdirectory.RoomDirectoryService
import io.element.android.libraries.matrix.api.roomlist.RoomListService
@@ -443,6 +443,23 @@ class RustMatrixClient(
}
}
+ override suspend fun joinRoomByIdOrAlias(
+ roomId: RoomId,
+ serverNames: List,
+ ): Result = withContext(sessionDispatcher) {
+ runCatching {
+ client.joinRoomByIdOrAlias(
+ roomIdOrAlias = roomId.value,
+ serverNames = serverNames,
+ ).destroy()
+ try {
+ awaitRoom(roomId, 10.seconds)
+ } catch (e: Exception) {
+ Timber.e(e, "Timeout waiting for the room to be available in the room list")
+ }
+ }
+ }
+
override suspend fun knockRoom(roomId: RoomId): Result {
return Result.failure(NotImplementedError("Not yet implemented"))
}
@@ -459,15 +476,22 @@ class RustMatrixClient(
}
}
- override suspend fun resolveRoomAlias(roomAlias: RoomAlias): Result = withContext(sessionDispatcher) {
+ override suspend fun resolveRoomAlias(roomAlias: RoomAlias): Result = withContext(sessionDispatcher) {
runCatching {
- client.resolveRoomAlias(roomAlias.value).roomId.let(::RoomId)
+ val result = client.resolveRoomAlias(roomAlias.value)
+ ResolvedRoomAlias(
+ roomId = RoomId(result.roomId),
+ servers = result.servers,
+ )
}
}
- override suspend fun getRoomPreview(roomIdOrAlias: RoomIdOrAlias): Result = withContext(sessionDispatcher) {
+ override suspend fun getRoomPreviewFromRoomId(roomId: RoomId, serverNames: List): Result = withContext(sessionDispatcher) {
runCatching {
- client.getRoomPreview(roomIdOrAlias.identifier).let(RoomPreviewMapper::map)
+ client.getRoomPreviewFromRoomId(
+ roomId = roomId.value,
+ viaServers = serverNames,
+ ).let(RoomPreviewMapper::map)
}
}
diff --git a/services/analytics/api/src/main/kotlin/io/element/android/services/analytics/api/extensions/JoinedRoomExt.kt b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/analytics/JoinedRoomExt.kt
similarity index 88%
rename from services/analytics/api/src/main/kotlin/io/element/android/services/analytics/api/extensions/JoinedRoomExt.kt
rename to libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/analytics/JoinedRoomExt.kt
index c8ab1fad06..955a6b0f8a 100644
--- a/services/analytics/api/src/main/kotlin/io/element/android/services/analytics/api/extensions/JoinedRoomExt.kt
+++ b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/analytics/JoinedRoomExt.kt
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2021 New Vector Ltd
+ * Copyright (c) 2024 New Vector Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -14,12 +14,12 @@
* limitations under the License.
*/
-package io.element.android.services.analytics.api.extensions
+package io.element.android.libraries.matrix.impl.analytics
import im.vector.app.features.analytics.plan.JoinedRoom
import io.element.android.libraries.matrix.api.room.MatrixRoom
-fun Long?.toAnalyticsRoomSize(): JoinedRoom.RoomSize {
+private fun Long?.toAnalyticsRoomSize(): JoinedRoom.RoomSize {
return when (this) {
null,
2L -> JoinedRoom.RoomSize.Two
diff --git a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/pushers/RustPushersService.kt b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/pushers/RustPushersService.kt
index 60ca4df311..2686d03c6b 100644
--- a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/pushers/RustPushersService.kt
+++ b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/pushers/RustPushersService.kt
@@ -19,6 +19,7 @@ package io.element.android.libraries.matrix.impl.pushers
import io.element.android.libraries.core.coroutine.CoroutineDispatchers
import io.element.android.libraries.matrix.api.pusher.PushersService
import io.element.android.libraries.matrix.api.pusher.SetHttpPusherData
+import io.element.android.libraries.matrix.api.pusher.UnsetHttpPusherData
import kotlinx.coroutines.withContext
import org.matrix.rustcomponents.sdk.Client
import org.matrix.rustcomponents.sdk.HttpPusherData
@@ -54,8 +55,16 @@ class RustPushersService(
}
}
- override suspend fun unsetHttpPusher(): Result {
- // TODO Missing client API. We need to set the pusher with Kind == null, but we do not have access to this field from the SDK.
- return Result.success(Unit)
+ override suspend fun unsetHttpPusher(unsetHttpPusherData: UnsetHttpPusherData): Result {
+ return withContext(dispatchers.io) {
+ runCatching {
+ client.deletePusher(
+ identifiers = PusherIdentifiers(
+ pushkey = unsetHttpPusherData.pushKey,
+ appId = unsetHttpPusherData.appId
+ ),
+ )
+ }
+ }
}
}
diff --git a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/room/MatrixRoomInfoMapper.kt b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/room/MatrixRoomInfoMapper.kt
index 3fe4dcf1b7..8063c67069 100644
--- a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/room/MatrixRoomInfoMapper.kt
+++ b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/room/MatrixRoomInfoMapper.kt
@@ -39,6 +39,7 @@ class MatrixRoomInfoMapper(
return MatrixRoomInfo(
id = RoomId(it.id),
name = it.displayName,
+ rawName = it.rawName,
topic = it.topic,
avatarUrl = it.avatarUrl,
isDirect = it.isDirect,
diff --git a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/room/join/DefaultJoinRoom.kt b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/room/join/DefaultJoinRoom.kt
new file mode 100644
index 0000000000..d2ce4e61d5
--- /dev/null
+++ b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/room/join/DefaultJoinRoom.kt
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2024 New Vector Ltd
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package io.element.android.libraries.matrix.impl.room.join
+
+import com.squareup.anvil.annotations.ContributesBinding
+import im.vector.app.features.analytics.plan.JoinedRoom
+import io.element.android.libraries.di.SessionScope
+import io.element.android.libraries.matrix.api.MatrixClient
+import io.element.android.libraries.matrix.api.core.RoomId
+import io.element.android.libraries.matrix.api.room.join.JoinRoom
+import io.element.android.libraries.matrix.impl.analytics.toAnalyticsJoinedRoom
+import io.element.android.services.analytics.api.AnalyticsService
+import javax.inject.Inject
+
+@ContributesBinding(SessionScope::class)
+class DefaultJoinRoom @Inject constructor(
+ private val client: MatrixClient,
+ private val analyticsService: AnalyticsService,
+) : JoinRoom {
+ override suspend fun invoke(
+ roomId: RoomId,
+ serverNames: List,
+ trigger: JoinedRoom.Trigger,
+ ): Result {
+ return if (serverNames.isEmpty()) {
+ client.joinRoom(roomId)
+ } else {
+ client.joinRoomByIdOrAlias(roomId, serverNames)
+ }.onSuccess {
+ client.getRoom(roomId)?.use { room ->
+ analyticsService.capture(room.toAnalyticsJoinedRoom(trigger))
+ }
+ }
+ }
+}
diff --git a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/timeline/MatrixTimelineItemMapper.kt b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/timeline/MatrixTimelineItemMapper.kt
index 5bf55105cc..c8cb4eef1c 100644
--- a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/timeline/MatrixTimelineItemMapper.kt
+++ b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/timeline/MatrixTimelineItemMapper.kt
@@ -31,7 +31,7 @@ class MatrixTimelineItemMapper(
private val eventTimelineItemMapper: EventTimelineItemMapper = EventTimelineItemMapper(),
) {
fun map(timelineItem: TimelineItem): MatrixTimelineItem = timelineItem.use {
- val uniqueId = timelineItem.uniqueId().toString()
+ val uniqueId = timelineItem.uniqueId()
val asEvent = it.asEvent()
if (asEvent != null) {
val eventTimelineItem = eventTimelineItemMapper.map(asEvent)
diff --git a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/timeline/RustTimeline.kt b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/timeline/RustTimeline.kt
index fb051e7a35..fee898988e 100644
--- a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/timeline/RustTimeline.kt
+++ b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/timeline/RustTimeline.kt
@@ -174,23 +174,25 @@ class RustTimeline(
// Use NonCancellable to avoid breaking the timeline when the coroutine is cancelled.
override suspend fun paginate(direction: Timeline.PaginationDirection): Result = withContext(NonCancellable) {
- initLatch.await()
- runCatching {
- if (!canPaginate(direction)) throw TimelineException.CannotPaginate
- updatePaginationStatus(direction) { it.copy(isPaginating = true) }
- when (direction) {
- Timeline.PaginationDirection.BACKWARDS -> inner.paginateBackwards(PAGINATION_SIZE.toUShort())
- Timeline.PaginationDirection.FORWARDS -> inner.focusedPaginateForwards(PAGINATION_SIZE.toUShort())
+ withContext(dispatcher) {
+ initLatch.await()
+ runCatching {
+ if (!canPaginate(direction)) throw TimelineException.CannotPaginate
+ updatePaginationStatus(direction) { it.copy(isPaginating = true) }
+ when (direction) {
+ Timeline.PaginationDirection.BACKWARDS -> inner.paginateBackwards(PAGINATION_SIZE.toUShort())
+ Timeline.PaginationDirection.FORWARDS -> inner.focusedPaginateForwards(PAGINATION_SIZE.toUShort())
+ }
+ }.onFailure { error ->
+ updatePaginationStatus(direction) { it.copy(isPaginating = false) }
+ if (error is TimelineException.CannotPaginate) {
+ Timber.d("Can't paginate $direction on room ${matrixRoom.roomId} with paginationStatus: ${backPaginationStatus.value}")
+ } else {
+ Timber.e(error, "Error paginating $direction on room ${matrixRoom.roomId}")
+ }
+ }.onSuccess { hasReachedEnd ->
+ updatePaginationStatus(direction) { it.copy(isPaginating = false, hasMoreToLoad = !hasReachedEnd) }
}
- }.onFailure { error ->
- updatePaginationStatus(direction) { it.copy(isPaginating = false) }
- if (error is TimelineException.CannotPaginate) {
- Timber.d("Can't paginate $direction on room ${matrixRoom.roomId} with paginationStatus: ${backPaginationStatus.value}")
- } else {
- Timber.e(error, "Error paginating $direction on room ${matrixRoom.roomId}")
- }
- }.onSuccess { hasReachedEnd ->
- updatePaginationStatus(direction) { it.copy(isPaginating = false, hasMoreToLoad = !hasReachedEnd) }
}
}
@@ -214,18 +216,20 @@ class RustTimeline(
backPaginationStatus.map { it.hasMoreToLoad }.distinctUntilChanged(),
forwardPaginationStatus.map { it.hasMoreToLoad }.distinctUntilChanged(),
) { timelineItems, hasMoreToLoadBackward, hasMoreToLoadForward ->
- timelineItems
- .let { items -> encryptedHistoryPostProcessor.process(items) }
- .let { items ->
- roomBeginningPostProcessor.process(
- items = items,
- isDm = matrixRoom.isDm,
- hasMoreToLoadBackwards = hasMoreToLoadBackward
- )
- }
- .let { items -> loadingIndicatorsPostProcessor.process(items, hasMoreToLoadBackward, hasMoreToLoadForward) }
- // Keep lastForwardIndicatorsPostProcessor last
- .let { items -> lastForwardIndicatorsPostProcessor.process(items) }
+ withContext(dispatcher) {
+ timelineItems
+ .let { items -> encryptedHistoryPostProcessor.process(items) }
+ .let { items ->
+ roomBeginningPostProcessor.process(
+ items = items,
+ isDm = matrixRoom.isDm,
+ hasMoreToLoadBackwards = hasMoreToLoadBackward
+ )
+ }
+ .let { items -> loadingIndicatorsPostProcessor.process(items, hasMoreToLoadBackward, hasMoreToLoadForward) }
+ // Keep lastForwardIndicatorsPostProcessor last
+ .let { items -> lastForwardIndicatorsPostProcessor.process(items) }
+ }
}
override fun close() {
diff --git a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/timeline/item/event/TimelineEventContentMapper.kt b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/timeline/item/event/TimelineEventContentMapper.kt
index 14ea994d38..04e3632d09 100644
--- a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/timeline/item/event/TimelineEventContentMapper.kt
+++ b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/timeline/item/event/TimelineEventContentMapper.kt
@@ -88,8 +88,9 @@ class TimelineEventContentMapper(private val eventMessageMapper: EventMessageMap
}
is TimelineItemContentKind.RoomMembership -> {
RoomMembershipContent(
- UserId(kind.userId),
- kind.change?.map()
+ userId = UserId(kind.userId),
+ userDisplayName = kind.userDisplayName,
+ change = kind.change?.map()
)
}
is TimelineItemContentKind.State -> {
diff --git a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/verification/RustSessionVerificationService.kt b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/verification/RustSessionVerificationService.kt
index 88403e8928..5b6d960d09 100644
--- a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/verification/RustSessionVerificationService.kt
+++ b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/verification/RustSessionVerificationService.kt
@@ -30,8 +30,8 @@ import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.asStateFlow
-import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.launchIn
+import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.flow.stateIn
import kotlinx.coroutines.launch
@@ -80,10 +80,14 @@ class RustSessionVerificationService(
private val _sessionVerifiedStatus = MutableStateFlow(SessionVerifiedStatus.Unknown)
override val sessionVerifiedStatus: StateFlow = _sessionVerifiedStatus.asStateFlow()
- override val isReady = isSyncServiceReady.stateIn(sessionCoroutineScope, SharingStarted.Eagerly, false)
+ /**
+ * The internal service that checks verification can only run after the initial sync.
+ * This [StateFlow] will notify consumers when the service is ready to be used.
+ */
+ private val isReady = isSyncServiceReady.stateIn(sessionCoroutineScope, SharingStarted.Eagerly, false)
- override val canVerifySessionFlow = combine(sessionVerifiedStatus, isReady) { verificationStatus, isReady ->
- isReady && verificationStatus == SessionVerifiedStatus.NotVerified
+ override val needsSessionVerification = sessionVerifiedStatus.map { verificationStatus ->
+ verificationStatus == SessionVerifiedStatus.NotVerified
}
init {
diff --git a/libraries/matrix/impl/src/test/kotlin/io/element/android/libraries/matrix/impl/room/join/DefaultJoinRoomTest.kt b/libraries/matrix/impl/src/test/kotlin/io/element/android/libraries/matrix/impl/room/join/DefaultJoinRoomTest.kt
new file mode 100644
index 0000000000..8bbdf47e21
--- /dev/null
+++ b/libraries/matrix/impl/src/test/kotlin/io/element/android/libraries/matrix/impl/room/join/DefaultJoinRoomTest.kt
@@ -0,0 +1,102 @@
+/*
+ * Copyright (c) 2024 New Vector Ltd
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package io.element.android.libraries.matrix.impl.room.join
+
+import com.google.common.truth.Truth.assertThat
+import im.vector.app.features.analytics.plan.JoinedRoom
+import io.element.android.libraries.matrix.api.MatrixClient
+import io.element.android.libraries.matrix.api.core.RoomId
+import io.element.android.libraries.matrix.impl.analytics.toAnalyticsJoinedRoom
+import io.element.android.libraries.matrix.test.A_ROOM_ID
+import io.element.android.libraries.matrix.test.A_SERVER_LIST
+import io.element.android.libraries.matrix.test.FakeMatrixClient
+import io.element.android.libraries.matrix.test.room.FakeMatrixRoom
+import io.element.android.services.analytics.test.FakeAnalyticsService
+import io.element.android.tests.testutils.lambda.lambdaRecorder
+import io.element.android.tests.testutils.lambda.value
+import kotlinx.coroutines.test.runTest
+import org.junit.Test
+
+class DefaultJoinRoomTest {
+ @Test
+ fun `when there is no server names, the classic join room API is used`() = runTest {
+ val joinRoomLambda = lambdaRecorder { _: RoomId -> Result.success(Unit) }
+ val joinRoomByIdOrAliasLambda = lambdaRecorder { _: RoomId, _: List -> Result.success(Unit) }
+ val roomResult = FakeMatrixRoom()
+ val aTrigger = JoinedRoom.Trigger.MobilePermalink
+ val client: MatrixClient = FakeMatrixClient().also {
+ it.joinRoomLambda = joinRoomLambda
+ it.joinRoomByIdOrAliasLambda = joinRoomByIdOrAliasLambda
+ it.givenGetRoomResult(
+ roomId = A_ROOM_ID,
+ result = roomResult
+ )
+ }
+ val analyticsService = FakeAnalyticsService()
+ val sut = DefaultJoinRoom(
+ client = client,
+ analyticsService = analyticsService,
+ )
+ sut.invoke(A_ROOM_ID, emptyList(), aTrigger)
+ joinRoomByIdOrAliasLambda
+ .assertions()
+ .isNeverCalled()
+ joinRoomLambda
+ .assertions()
+ .isCalledExactly(1)
+ .withSequence(
+ listOf(value(A_ROOM_ID))
+ )
+ assertThat(analyticsService.capturedEvents).containsExactly(
+ roomResult.toAnalyticsJoinedRoom(aTrigger)
+ )
+ }
+
+ @Test
+ fun `when server names are available, joinRoomByIdOrAlias API is used`() = runTest {
+ val joinRoomLambda = lambdaRecorder { _: RoomId -> Result.success(Unit) }
+ val joinRoomByIdOrAliasLambda = lambdaRecorder { _: RoomId, _: List -> Result.success(Unit) }
+ val roomResult = FakeMatrixRoom()
+ val aTrigger = JoinedRoom.Trigger.MobilePermalink
+ val client: MatrixClient = FakeMatrixClient().also {
+ it.joinRoomLambda = joinRoomLambda
+ it.joinRoomByIdOrAliasLambda = joinRoomByIdOrAliasLambda
+ it.givenGetRoomResult(
+ roomId = A_ROOM_ID,
+ result = roomResult
+ )
+ }
+ val analyticsService = FakeAnalyticsService()
+ val sut = DefaultJoinRoom(
+ client = client,
+ analyticsService = analyticsService,
+ )
+ sut.invoke(A_ROOM_ID, A_SERVER_LIST, aTrigger)
+ joinRoomByIdOrAliasLambda
+ .assertions()
+ .isCalledExactly(1)
+ .withSequence(
+ listOf(value(A_ROOM_ID), value(A_SERVER_LIST))
+ )
+ joinRoomLambda
+ .assertions()
+ .isNeverCalled()
+ assertThat(analyticsService.capturedEvents).containsExactly(
+ roomResult.toAnalyticsJoinedRoom(aTrigger)
+ )
+ }
+}
diff --git a/libraries/matrix/impl/src/test/kotlin/io/element/android/libraries/matrix/impl/timeline/postprocessor/RoomBeginningPostProcessorTest.kt b/libraries/matrix/impl/src/test/kotlin/io/element/android/libraries/matrix/impl/timeline/postprocessor/RoomBeginningPostProcessorTest.kt
index 2c72481a25..63b0664bc7 100644
--- a/libraries/matrix/impl/src/test/kotlin/io/element/android/libraries/matrix/impl/timeline/postprocessor/RoomBeginningPostProcessorTest.kt
+++ b/libraries/matrix/impl/src/test/kotlin/io/element/android/libraries/matrix/impl/timeline/postprocessor/RoomBeginningPostProcessorTest.kt
@@ -34,7 +34,7 @@ class RoomBeginningPostProcessorTest {
fun `processor removes room creation event and self-join event from DM timeline`() {
val timelineItems = listOf(
MatrixTimelineItem.Event("m.room.create", anEventTimelineItem(sender = A_USER_ID, content = StateContent("", OtherState.RoomCreate))),
- MatrixTimelineItem.Event("m.room.member", anEventTimelineItem(content = RoomMembershipContent(A_USER_ID, MembershipChange.JOINED))),
+ MatrixTimelineItem.Event("m.room.member", anEventTimelineItem(content = RoomMembershipContent(A_USER_ID, null, MembershipChange.JOINED))),
)
val processor = RoomBeginningPostProcessor()
val processedItems = processor.process(timelineItems, isDm = true, hasMoreToLoadBackwards = false)
@@ -44,13 +44,13 @@ class RoomBeginningPostProcessorTest {
@Test
fun `processor removes room creation event and self-join event from DM timeline even if they're not the first items`() {
val timelineItems = listOf(
- MatrixTimelineItem.Event("m.room.member_other", anEventTimelineItem(content = RoomMembershipContent(A_USER_ID_2, MembershipChange.JOINED))),
+ MatrixTimelineItem.Event("m.room.member_other", anEventTimelineItem(content = RoomMembershipContent(A_USER_ID_2, null, MembershipChange.JOINED))),
MatrixTimelineItem.Event("m.room.create", anEventTimelineItem(sender = A_USER_ID, content = StateContent("", OtherState.RoomCreate))),
MatrixTimelineItem.Event("m.room.message", anEventTimelineItem(content = aMessageContent("hi"))),
- MatrixTimelineItem.Event("m.room.member", anEventTimelineItem(content = RoomMembershipContent(A_USER_ID, MembershipChange.JOINED))),
+ MatrixTimelineItem.Event("m.room.member", anEventTimelineItem(content = RoomMembershipContent(A_USER_ID, null, MembershipChange.JOINED))),
)
val expected = listOf(
- MatrixTimelineItem.Event("m.room.member_other", anEventTimelineItem(content = RoomMembershipContent(A_USER_ID_2, MembershipChange.JOINED))),
+ MatrixTimelineItem.Event("m.room.member_other", anEventTimelineItem(content = RoomMembershipContent(A_USER_ID_2, null, MembershipChange.JOINED))),
MatrixTimelineItem.Event("m.room.message", anEventTimelineItem(content = aMessageContent("hi"))),
)
val processor = RoomBeginningPostProcessor()
@@ -62,7 +62,7 @@ class RoomBeginningPostProcessorTest {
fun `processor will add beginning of room item if it's not a DM`() {
val timelineItems = listOf(
MatrixTimelineItem.Event("m.room.create", anEventTimelineItem(sender = A_USER_ID, content = StateContent("", OtherState.RoomCreate))),
- MatrixTimelineItem.Event("m.room.member", anEventTimelineItem(content = RoomMembershipContent(A_USER_ID, MembershipChange.JOINED))),
+ MatrixTimelineItem.Event("m.room.member", anEventTimelineItem(content = RoomMembershipContent(A_USER_ID, null, MembershipChange.JOINED))),
)
val processor = RoomBeginningPostProcessor()
val processedItems = processor.process(timelineItems, isDm = false, hasMoreToLoadBackwards = false)
@@ -85,7 +85,7 @@ class RoomBeginningPostProcessorTest {
fun `processor won't remove items if it's not at the start of the timeline`() {
val timelineItems = listOf(
MatrixTimelineItem.Event("m.room.create", anEventTimelineItem(sender = A_USER_ID, content = StateContent("", OtherState.RoomCreate))),
- MatrixTimelineItem.Event("m.room.member", anEventTimelineItem(content = RoomMembershipContent(A_USER_ID, MembershipChange.JOINED))),
+ MatrixTimelineItem.Event("m.room.member", anEventTimelineItem(content = RoomMembershipContent(A_USER_ID, null, MembershipChange.JOINED))),
)
val processor = RoomBeginningPostProcessor()
val processedItems = processor.process(timelineItems, isDm = true, hasMoreToLoadBackwards = true)
@@ -95,7 +95,7 @@ class RoomBeginningPostProcessorTest {
@Test
fun `processor won't remove the first member join event if it can't find the room creation event`() {
val timelineItems = listOf(
- MatrixTimelineItem.Event("m.room.member", anEventTimelineItem(content = RoomMembershipContent(A_USER_ID, MembershipChange.JOINED))),
+ MatrixTimelineItem.Event("m.room.member", anEventTimelineItem(content = RoomMembershipContent(A_USER_ID, null, MembershipChange.JOINED))),
)
val processor = RoomBeginningPostProcessor()
val processedItems = processor.process(timelineItems, isDm = true, hasMoreToLoadBackwards = true)
@@ -106,7 +106,7 @@ class RoomBeginningPostProcessorTest {
fun `processor won't remove the first member join event if it's not from the room creator`() {
val timelineItems = listOf(
MatrixTimelineItem.Event("m.room.create", anEventTimelineItem(sender = A_USER_ID, content = StateContent("", OtherState.RoomCreate))),
- MatrixTimelineItem.Event("m.room.member", anEventTimelineItem(content = RoomMembershipContent(A_USER_ID_2, MembershipChange.JOINED))),
+ MatrixTimelineItem.Event("m.room.member", anEventTimelineItem(content = RoomMembershipContent(A_USER_ID_2, null, MembershipChange.JOINED))),
)
val processor = RoomBeginningPostProcessor()
val processedItems = processor.process(timelineItems, isDm = true, hasMoreToLoadBackwards = true)
diff --git a/libraries/matrix/test/build.gradle.kts b/libraries/matrix/test/build.gradle.kts
index 9c41948bd7..8e06adeece 100644
--- a/libraries/matrix/test/build.gradle.kts
+++ b/libraries/matrix/test/build.gradle.kts
@@ -27,6 +27,7 @@ dependencies {
api(projects.libraries.matrix.api)
api(libs.coroutines.core)
implementation(libs.coroutines.test)
+ implementation(projects.services.analytics.api)
implementation(projects.tests.testutils)
implementation(libs.kotlinx.collections.immutable)
}
diff --git a/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/FakeMatrixClient.kt b/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/FakeMatrixClient.kt
index 015f764ff5..17e9bedfcf 100644
--- a/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/FakeMatrixClient.kt
+++ b/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/FakeMatrixClient.kt
@@ -20,7 +20,6 @@ import io.element.android.libraries.matrix.api.MatrixClient
import io.element.android.libraries.matrix.api.core.ProgressCallback
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.SessionId
import io.element.android.libraries.matrix.api.core.UserId
import io.element.android.libraries.matrix.api.createroom.CreateRoomParameters
@@ -33,6 +32,7 @@ import io.element.android.libraries.matrix.api.pusher.PushersService
import io.element.android.libraries.matrix.api.room.MatrixRoom
import io.element.android.libraries.matrix.api.room.MatrixRoomInfo
import io.element.android.libraries.matrix.api.room.RoomMembershipObserver
+import io.element.android.libraries.matrix.api.room.alias.ResolvedRoomAlias
import io.element.android.libraries.matrix.api.room.preview.RoomPreview
import io.element.android.libraries.matrix.api.roomdirectory.RoomDirectoryService
import io.element.android.libraries.matrix.api.roomlist.RoomListService
@@ -53,7 +53,6 @@ import kotlinx.collections.immutable.ImmutableList
import kotlinx.collections.immutable.persistentListOf
import kotlinx.collections.immutable.toImmutableList
import kotlinx.coroutines.CoroutineScope
-import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.flowOf
@@ -76,8 +75,8 @@ class FakeMatrixClient(
private val encryptionService: FakeEncryptionService = FakeEncryptionService(),
private val roomDirectoryService: RoomDirectoryService = FakeRoomDirectoryService(),
private val accountManagementUrlString: Result = Result.success(null),
- private val resolveRoomAliasResult: (RoomAlias) -> Result = { Result.success(A_ROOM_ID) },
- private val getRoomPreviewResult: (RoomIdOrAlias) -> Result = { Result.failure(AN_EXCEPTION) },
+ private val resolveRoomAliasResult: (RoomAlias) -> Result = { Result.success(ResolvedRoomAlias(A_ROOM_ID, emptyList())) },
+ private val getRoomPreviewFromRoomIdResult: (RoomId, List) -> Result = { _, _ -> Result.failure(AN_EXCEPTION) },
) : MatrixClient {
var setDisplayNameCalled: Boolean = false
private set
@@ -95,7 +94,6 @@ class FakeMatrixClient(
private var createRoomResult: Result = Result.success(A_ROOM_ID)
private var createDmResult: Result = Result.success(A_ROOM_ID)
private var findDmResult: RoomId? = A_ROOM_ID
- private var logoutFailure: Throwable? = null
private val getRoomResults = mutableMapOf()
private val searchUserResults = mutableMapOf>()
private val getProfileResults = mutableMapOf>()
@@ -106,12 +104,18 @@ class FakeMatrixClient(
var joinRoomLambda: (RoomId) -> Result = {
Result.success(Unit)
}
+ var joinRoomByIdOrAliasLambda: (RoomId, List) -> Result = { _, _ ->
+ Result.success(Unit)
+ }
var knockRoomLambda: (RoomId) -> Result = {
Result.success(Unit)
}
var getRoomInfoFlowLambda = { _: RoomId ->
flowOf>(Optional.empty())
}
+ var logoutLambda: (Boolean) -> String? = {
+ null
+ }
override suspend fun getRoom(roomId: RoomId): MatrixRoom? {
return getRoomResults[roomId]
@@ -156,12 +160,8 @@ class FakeMatrixClient(
override suspend fun clearCache() {
}
- override suspend fun logout(ignoreSdkError: Boolean): String? {
- delay(100)
- if (ignoreSdkError.not()) {
- logoutFailure?.let { throw it }
- }
- return null
+ override suspend fun logout(ignoreSdkError: Boolean): String? = simulateLongTask {
+ return logoutLambda(ignoreSdkError)
}
override fun close() = Unit
@@ -201,6 +201,10 @@ class FakeMatrixClient(
override suspend fun joinRoom(roomId: RoomId): Result = joinRoomLambda(roomId)
+ override suspend fun joinRoomByIdOrAlias(roomId: RoomId, serverNames: List): Result {
+ return joinRoomByIdOrAliasLambda(roomId, serverNames)
+ }
+
override suspend fun knockRoom(roomId: RoomId): Result = knockRoomLambda(roomId)
override fun sessionVerificationService(): SessionVerificationService = sessionVerificationService
@@ -221,10 +225,6 @@ class FakeMatrixClient(
// Mocks
- fun givenLogoutError(failure: Throwable?) {
- logoutFailure = failure
- }
-
fun givenCreateRoomResult(result: Result) {
createRoomResult = result
}
@@ -285,12 +285,12 @@ class FakeMatrixClient(
return Result.success(Unit)
}
- override suspend fun resolveRoomAlias(roomAlias: RoomAlias): Result = simulateLongTask {
+ override suspend fun resolveRoomAlias(roomAlias: RoomAlias): Result = simulateLongTask {
resolveRoomAliasResult(roomAlias)
}
- override suspend fun getRoomPreview(roomIdOrAlias: RoomIdOrAlias): Result = simulateLongTask {
- getRoomPreviewResult(roomIdOrAlias)
+ override suspend fun getRoomPreviewFromRoomId(roomId: RoomId, serverNames: List) = simulateLongTask {
+ getRoomPreviewFromRoomIdResult(roomId, serverNames)
}
override suspend fun getRecentlyVisitedRooms(): Result> {
diff --git a/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/TestData.kt b/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/TestData.kt
index 96346574ce..e507e34033 100644
--- a/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/TestData.kt
+++ b/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/TestData.kt
@@ -56,6 +56,7 @@ val A_TRANSACTION_ID = TransactionId("aTransactionId")
const val A_UNIQUE_ID = "aUniqueId"
const val A_ROOM_NAME = "A room name"
+const val A_ROOM_RAW_NAME = "A room raw name"
const val A_MESSAGE = "Hello world!"
const val A_REPLY = "OK, I'll be there!"
const val ANOTHER_MESSAGE = "Hello universe!"
@@ -76,3 +77,5 @@ val A_THROWABLE = Throwable(A_FAILURE_REASON)
val AN_EXCEPTION = Exception(A_FAILURE_REASON)
const val A_RECOVERY_KEY = "1234 5678"
+
+val A_SERVER_LIST = listOf("server1", "server2")
diff --git a/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/auth/FakeAuthenticationService.kt b/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/auth/FakeAuthenticationService.kt
index 2cf6b77a78..c24df7d717 100644
--- a/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/auth/FakeAuthenticationService.kt
+++ b/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/auth/FakeAuthenticationService.kt
@@ -39,13 +39,13 @@ class FakeAuthenticationService : MatrixAuthenticationService {
private var changeServerError: Throwable? = null
private var matrixClient: MatrixClient? = null
+ var getLatestSessionIdLambda: (() -> SessionId?) = { null }
+
override fun loggedInStateFlow(): Flow {
return flowOf(LoggedInState.NotLoggedIn)
}
- override suspend fun getLatestSessionId(): SessionId? {
- return null
- }
+ override suspend fun getLatestSessionId(): SessionId? = getLatestSessionIdLambda()
override suspend fun restoreSession(sessionId: SessionId): Result {
return if (matrixClient != null) {
diff --git a/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/permalink/FakePermalinkBuilder.kt b/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/permalink/FakePermalinkBuilder.kt
index 273899e762..f700c3b6af 100644
--- a/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/permalink/FakePermalinkBuilder.kt
+++ b/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/permalink/FakePermalinkBuilder.kt
@@ -20,9 +20,9 @@ import io.element.android.libraries.matrix.api.core.UserId
import io.element.android.libraries.matrix.api.permalink.PermalinkBuilder
class FakePermalinkBuilder(
- private val result: () -> Result = { Result.failure(Exception("Not implemented")) }
+ private val result: (UserId) -> Result = { Result.failure(Exception("Not implemented")) }
) : PermalinkBuilder {
override fun permalinkForUser(userId: UserId): Result {
- return result()
+ return result(userId)
}
}
diff --git a/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/pushers/FakePushersService.kt b/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/pushers/FakePushersService.kt
index 6ff7e4a20b..05a40e9995 100644
--- a/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/pushers/FakePushersService.kt
+++ b/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/pushers/FakePushersService.kt
@@ -18,8 +18,9 @@ package io.element.android.libraries.matrix.test.pushers
import io.element.android.libraries.matrix.api.pusher.PushersService
import io.element.android.libraries.matrix.api.pusher.SetHttpPusherData
+import io.element.android.libraries.matrix.api.pusher.UnsetHttpPusherData
class FakePushersService : PushersService {
override suspend fun setHttpPusher(setHttpPusherData: SetHttpPusherData) = Result.success(Unit)
- override suspend fun unsetHttpPusher(): Result = Result.success(Unit)
+ override suspend fun unsetHttpPusher(unsetHttpPusherData: UnsetHttpPusherData): Result = Result.success(Unit)
}
diff --git a/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/room/FakeMatrixRoom.kt b/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/room/FakeMatrixRoom.kt
index fff0ce8247..a780d33ecd 100644
--- a/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/room/FakeMatrixRoom.kt
+++ b/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/room/FakeMatrixRoom.kt
@@ -735,6 +735,7 @@ data class EndPollInvocation(
fun aRoomInfo(
id: RoomId = A_ROOM_ID,
name: String? = A_ROOM_NAME,
+ rawName: String? = name,
topic: String? = "A topic",
avatarUrl: String? = AN_AVATAR_URL,
isDirect: Boolean = false,
@@ -759,6 +760,7 @@ fun aRoomInfo(
) = MatrixRoomInfo(
id = id,
name = name,
+ rawName = rawName,
topic = topic,
avatarUrl = avatarUrl,
isDirect = isDirect,
diff --git a/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/room/join/FakeJoinRoom.kt b/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/room/join/FakeJoinRoom.kt
new file mode 100644
index 0000000000..55eade69d4
--- /dev/null
+++ b/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/room/join/FakeJoinRoom.kt
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2024 New Vector Ltd
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package io.element.android.libraries.matrix.test.room.join
+
+import im.vector.app.features.analytics.plan.JoinedRoom
+import io.element.android.libraries.matrix.api.core.RoomId
+import io.element.android.libraries.matrix.api.room.join.JoinRoom
+import io.element.android.tests.testutils.simulateLongTask
+
+class FakeJoinRoom(
+ var lambda: (RoomId, List, JoinedRoom.Trigger) -> Result
+) : JoinRoom {
+ override suspend fun invoke(
+ roomId: RoomId,
+ serverNames: List,
+ trigger: JoinedRoom.Trigger,
+ ): Result = simulateLongTask {
+ lambda(roomId, serverNames, trigger)
+ }
+}
diff --git a/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/verification/FakeSessionVerificationService.kt b/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/verification/FakeSessionVerificationService.kt
index cde77d7c61..780758acbe 100644
--- a/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/verification/FakeSessionVerificationService.kt
+++ b/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/verification/FakeSessionVerificationService.kt
@@ -25,17 +25,14 @@ import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
class FakeSessionVerificationService : SessionVerificationService {
- private val _isReady = MutableStateFlow(false)
private val _sessionVerifiedStatus = MutableStateFlow(SessionVerifiedStatus.Unknown)
private var _verificationFlowState = MutableStateFlow(VerificationFlowState.Initial)
- private var _canVerifySessionFlow = MutableStateFlow(true)
+ private var _needsSessionVerification = MutableStateFlow(true)
var shouldFail = false
override val verificationFlowState: StateFlow = _verificationFlowState
override val sessionVerifiedStatus: StateFlow = _sessionVerifiedStatus
- override val canVerifySessionFlow: Flow = _canVerifySessionFlow
-
- override val isReady: StateFlow = _isReady
+ override val needsSessionVerification: Flow = _needsSessionVerification
override suspend fun requestVerification() {
if (!shouldFail) {
@@ -85,12 +82,8 @@ class FakeSessionVerificationService : SessionVerificationService {
_verificationFlowState.value = state
}
- fun givenCanVerifySession(canVerify: Boolean) {
- _canVerifySessionFlow.value = canVerify
- }
-
- fun givenIsReady(value: Boolean) {
- _isReady.value = value
+ fun givenNeedsSessionVerification(needsVerification: Boolean) {
+ _needsSessionVerification.value = needsVerification
}
override suspend fun reset() {
diff --git a/libraries/matrixui/build.gradle.kts b/libraries/matrixui/build.gradle.kts
index 6d955a7c05..ed7f3d068d 100644
--- a/libraries/matrixui/build.gradle.kts
+++ b/libraries/matrixui/build.gradle.kts
@@ -39,6 +39,7 @@ dependencies {
implementation(projects.libraries.designsystem)
implementation(projects.libraries.core)
implementation(projects.libraries.uiStrings)
+ implementation(projects.libraries.testtags)
implementation(libs.coil.compose)
implementation(libs.coil.gif)
implementation(libs.jsoup)
diff --git a/libraries/matrixui/src/main/kotlin/io/element/android/libraries/matrix/ui/components/AvatarActionBottomSheet.kt b/libraries/matrixui/src/main/kotlin/io/element/android/libraries/matrix/ui/components/AvatarActionBottomSheet.kt
index fd154928ef..84caa006d2 100644
--- a/libraries/matrixui/src/main/kotlin/io/element/android/libraries/matrix/ui/components/AvatarActionBottomSheet.kt
+++ b/libraries/matrixui/src/main/kotlin/io/element/android/libraries/matrix/ui/components/AvatarActionBottomSheet.kt
@@ -14,25 +14,23 @@
* limitations under the License.
*/
-@file:OptIn(ExperimentalMaterialApi::class)
-@file:Suppress("UsingMaterialAndMaterial3Libraries")
+@file:OptIn(ExperimentalMaterial3Api::class)
package io.element.android.libraries.matrix.ui.components
+import androidx.activity.compose.BackHandler
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.imePadding
import androidx.compose.foundation.layout.navigationBarsPadding
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.items
-import androidx.compose.material.ExperimentalMaterialApi
-import androidx.compose.material.ModalBottomSheetState
-import androidx.compose.material.ModalBottomSheetValue
+import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.MaterialTheme
+import androidx.compose.material3.rememberModalBottomSheetState
import androidx.compose.runtime.Composable
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.ui.Modifier
-import androidx.compose.ui.platform.LocalDensity
import androidx.compose.ui.res.stringResource
import io.element.android.compound.theme.ElementTheme
import io.element.android.libraries.designsystem.components.list.ListItemContent
@@ -41,33 +39,44 @@ import io.element.android.libraries.designsystem.preview.PreviewsDayNight
import io.element.android.libraries.designsystem.theme.components.IconSource
import io.element.android.libraries.designsystem.theme.components.ListItem
import io.element.android.libraries.designsystem.theme.components.ListItemStyle
-import io.element.android.libraries.designsystem.theme.components.ModalBottomSheetLayout
+import io.element.android.libraries.designsystem.theme.components.ModalBottomSheet
import io.element.android.libraries.designsystem.theme.components.Text
+import io.element.android.libraries.designsystem.theme.components.hide
import io.element.android.libraries.matrix.ui.media.AvatarAction
import kotlinx.collections.immutable.ImmutableList
import kotlinx.collections.immutable.persistentListOf
-import kotlinx.coroutines.launch
+@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun AvatarActionBottomSheet(
actions: ImmutableList,
- modalBottomSheetState: ModalBottomSheetState,
+ isVisible: Boolean,
onActionSelected: (action: AvatarAction) -> Unit,
+ onDismiss: () -> Unit,
modifier: Modifier = Modifier,
) {
val coroutineScope = rememberCoroutineScope()
- fun onItemActionClicked(itemAction: AvatarAction) {
- onActionSelected(itemAction)
- coroutineScope.launch {
- modalBottomSheetState.hide()
- }
+ val sheetState = rememberModalBottomSheetState(
+ skipPartiallyExpanded = true
+ )
+
+ BackHandler(enabled = isVisible) {
+ sheetState.hide(coroutineScope, then = { onDismiss() })
}
- ModalBottomSheetLayout(
- modifier = modifier,
- sheetState = modalBottomSheetState,
- displayHandle = true,
- sheetContent = {
+ fun onItemActionClicked(itemAction: AvatarAction) {
+ onActionSelected(itemAction)
+ sheetState.hide(coroutineScope, then = { onDismiss() })
+ }
+
+ if (isVisible) {
+ ModalBottomSheet(
+ onDismissRequest = {
+ sheetState.hide(coroutineScope, then = { onDismiss() })
+ },
+ modifier = modifier,
+ sheetState = sheetState,
+ ) {
AvatarActionBottomSheetContent(
actions = actions,
onActionClicked = ::onItemActionClicked,
@@ -76,7 +85,7 @@ fun AvatarActionBottomSheet(
.imePadding()
)
}
- )
+ }
}
@Composable
@@ -115,10 +124,8 @@ private fun AvatarActionBottomSheetContent(
internal fun AvatarActionBottomSheetPreview() = ElementPreview {
AvatarActionBottomSheet(
actions = persistentListOf(AvatarAction.TakePhoto, AvatarAction.ChoosePhoto, AvatarAction.Remove),
- modalBottomSheetState = ModalBottomSheetState(
- initialValue = ModalBottomSheetValue.Expanded,
- density = LocalDensity.current,
- ),
+ isVisible = true,
onActionSelected = { },
+ onDismiss = { },
)
}
diff --git a/libraries/matrixui/src/main/kotlin/io/element/android/libraries/matrix/ui/components/EditableAvatarView.kt b/libraries/matrixui/src/main/kotlin/io/element/android/libraries/matrix/ui/components/EditableAvatarView.kt
index 07010329d3..ad9babb4a4 100644
--- a/libraries/matrixui/src/main/kotlin/io/element/android/libraries/matrix/ui/components/EditableAvatarView.kt
+++ b/libraries/matrixui/src/main/kotlin/io/element/android/libraries/matrix/ui/components/EditableAvatarView.kt
@@ -33,23 +33,32 @@ import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
+import androidx.compose.ui.tooling.preview.PreviewParameter
+import androidx.compose.ui.tooling.preview.PreviewParameterProvider
import androidx.compose.ui.unit.dp
import io.element.android.compound.tokens.generated.CompoundIcons
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.preview.ElementPreview
+import io.element.android.libraries.designsystem.preview.PreviewsDayNight
import io.element.android.libraries.designsystem.theme.components.Icon
+import io.element.android.libraries.testtags.TestTags
+import io.element.android.libraries.testtags.testTag
@Composable
fun EditableAvatarView(
- userId: String?,
+ matrixId: String,
displayName: String?,
avatarUrl: Uri?,
avatarSize: AvatarSize,
onAvatarClicked: () -> Unit,
modifier: Modifier = Modifier,
) {
- Column(modifier = modifier.fillMaxWidth(), horizontalAlignment = Alignment.CenterHorizontally) {
+ Column(
+ modifier = modifier.fillMaxWidth(),
+ horizontalAlignment = Alignment.CenterHorizontally,
+ ) {
Box(
modifier = Modifier
.size(avatarSize.dp)
@@ -58,15 +67,14 @@ fun EditableAvatarView(
onClick = onAvatarClicked,
indication = rememberRipple(bounded = false),
)
+ .testTag(TestTags.editAvatar)
) {
when (avatarUrl?.scheme) {
null, "mxc" -> {
- userId?.let {
- Avatar(
- avatarData = AvatarData(it, displayName, avatarUrl?.toString(), size = avatarSize),
- modifier = Modifier.fillMaxSize(),
- )
- }
+ Avatar(
+ avatarData = AvatarData(matrixId, displayName, avatarUrl?.toString(), size = avatarSize),
+ modifier = Modifier.fillMaxSize(),
+ )
}
else -> {
UnsavedAvatar(
@@ -94,3 +102,26 @@ fun EditableAvatarView(
}
}
}
+
+@PreviewsDayNight
+@Composable
+internal fun EditableAvatarViewPreview(
+ @PreviewParameter(EditableAvatarViewUriProvider::class) uri: Uri?
+) = ElementPreview {
+ EditableAvatarView(
+ matrixId = "id",
+ displayName = "A room",
+ avatarUrl = uri,
+ avatarSize = AvatarSize.EditRoomDetails,
+ onAvatarClicked = {},
+ )
+}
+
+open class EditableAvatarViewUriProvider : PreviewParameterProvider {
+ override val values: Sequence
+ get() = sequenceOf(
+ null,
+ Uri.parse("mxc://matrix.org/123456"),
+ Uri.parse("https://example.com/avatar.jpg"),
+ )
+}
diff --git a/libraries/matrixui/src/main/kotlin/io/element/android/libraries/matrix/ui/room/MatrixRoomState.kt b/libraries/matrixui/src/main/kotlin/io/element/android/libraries/matrix/ui/room/MatrixRoomState.kt
index aa3121146a..ab3c80a6e2 100644
--- a/libraries/matrixui/src/main/kotlin/io/element/android/libraries/matrix/ui/room/MatrixRoomState.kt
+++ b/libraries/matrixui/src/main/kotlin/io/element/android/libraries/matrix/ui/room/MatrixRoomState.kt
@@ -62,3 +62,21 @@ fun MatrixRoom.isOwnUserAdmin(): Boolean {
val powerLevel = roomInfo?.userPowerLevels?.get(sessionId) ?: 0L
return RoomMember.Role.forPowerLevel(powerLevel) == RoomMember.Role.ADMIN
}
+
+@Composable
+fun MatrixRoom.rawName(): String? {
+ val roomInfo by roomInfoFlow.collectAsState(initial = null)
+ return roomInfo?.rawName
+}
+
+@Composable
+fun MatrixRoom.topic(): String? {
+ val roomInfo by roomInfoFlow.collectAsState(initial = null)
+ return roomInfo?.topic
+}
+
+@Composable
+fun MatrixRoom.avatarUrl(): String? {
+ val roomInfo by roomInfoFlow.collectAsState(initial = null)
+ return roomInfo?.avatarUrl
+}
diff --git a/libraries/matrixui/src/main/res/values-ka/translations.xml b/libraries/matrixui/src/main/res/values-ka/translations.xml
new file mode 100644
index 0000000000..07619e7dfd
--- /dev/null
+++ b/libraries/matrixui/src/main/res/values-ka/translations.xml
@@ -0,0 +1,4 @@
+
+
+ "%1$s (%2$s) მოგიწვიათ"
+
diff --git a/libraries/matrixui/src/main/res/values-pt/translations.xml b/libraries/matrixui/src/main/res/values-pt/translations.xml
new file mode 100644
index 0000000000..5b5f826912
--- /dev/null
+++ b/libraries/matrixui/src/main/res/values-pt/translations.xml
@@ -0,0 +1,4 @@
+
+
+ "%1$s (%2$s) convidou-te"
+
diff --git a/libraries/matrixui/src/main/res/values-zh/translations.xml b/libraries/matrixui/src/main/res/values-zh/translations.xml
new file mode 100644
index 0000000000..6b0d478317
--- /dev/null
+++ b/libraries/matrixui/src/main/res/values-zh/translations.xml
@@ -0,0 +1,4 @@
+
+
+ "%1$s (%2$s)邀请了你"
+
diff --git a/libraries/permissions/api/src/main/res/values-ka/translations.xml b/libraries/permissions/api/src/main/res/values-ka/translations.xml
new file mode 100644
index 0000000000..ffeb3a4312
--- /dev/null
+++ b/libraries/permissions/api/src/main/res/values-ka/translations.xml
@@ -0,0 +1,7 @@
+
+
+ "იმისათვის, რომ აპლიკაციამ გამოიყენოს კამერა, გთხოვთ, მიანიჭოთ ნებართვა სისტემის პარამეტრებში."
+ "გთხოვთ, მიანიჭოთ ნებართვა სისტემის პარამეტრებში."
+ "იმისათვის, რომ აპლიკაციამ მიკროფონი გამოიყენოს, გთხოვთ, მიანიჭოთ ნებართვა სისტემის პარამეტრებში."
+ "იმისათვის, რომ აპლიკაციამ გამოაჩინოს შეტყობინებები, გთხოვთ, მიანიჭოთ ნებართვა სისტემის პარამეტრებში."
+
diff --git a/libraries/permissions/api/src/main/res/values-pt/translations.xml b/libraries/permissions/api/src/main/res/values-pt/translations.xml
new file mode 100644
index 0000000000..6a029c68d6
--- /dev/null
+++ b/libraries/permissions/api/src/main/res/values-pt/translations.xml
@@ -0,0 +1,7 @@
+
+
+ "Para que a aplicação possa utilizar a câmara, concede a permissão nas configurações do sistema."
+ "Concede a permissão nas configurações do sistema."
+ "Para que a aplicação possa utilizar o microfone, concede essa permissão nas configurações do sistema."
+ "Para permitir que a aplicação apresente notificações, concede a permissão nas configurações do sistema."
+
diff --git a/libraries/permissions/api/src/main/res/values-zh/translations.xml b/libraries/permissions/api/src/main/res/values-zh/translations.xml
new file mode 100644
index 0000000000..eb093046a3
--- /dev/null
+++ b/libraries/permissions/api/src/main/res/values-zh/translations.xml
@@ -0,0 +1,7 @@
+
+
+ "为了让应用程序使用相机,请在系统设置中授予权限。"
+ "请在系统设置中授予权限。"
+ "为了让应用程序使用麦克风,请在系统设置中授予权限。"
+ "为了让应用程序显示通知,请在系统设置中授予权限。"
+
diff --git a/libraries/permissions/impl/src/main/res/values-pt/translations.xml b/libraries/permissions/impl/src/main/res/values-pt/translations.xml
new file mode 100644
index 0000000000..128711fa89
--- /dev/null
+++ b/libraries/permissions/impl/src/main/res/values-pt/translations.xml
@@ -0,0 +1,5 @@
+
+
+ "Verificar se a aplicação consegue mostrar notificações."
+ "Verificar permissões"
+
diff --git a/libraries/permissions/impl/src/main/res/values-ro/translations.xml b/libraries/permissions/impl/src/main/res/values-ro/translations.xml
new file mode 100644
index 0000000000..af6b9d23f3
--- /dev/null
+++ b/libraries/permissions/impl/src/main/res/values-ro/translations.xml
@@ -0,0 +1,5 @@
+
+
+ "Verificați dacă aplicația poate afișa notificări."
+ "Verificați permisiunile"
+
diff --git a/libraries/permissions/impl/src/main/res/values-zh/translations.xml b/libraries/permissions/impl/src/main/res/values-zh/translations.xml
new file mode 100644
index 0000000000..ac123464ed
--- /dev/null
+++ b/libraries/permissions/impl/src/main/res/values-zh/translations.xml
@@ -0,0 +1,5 @@
+
+
+ "检查应用程序是否可以显示通知。"
+ "检查权限"
+
diff --git a/libraries/preferences/api/src/main/kotlin/io/element/android/features/preferences/api/store/AppPreferencesStore.kt b/libraries/preferences/api/src/main/kotlin/io/element/android/features/preferences/api/store/AppPreferencesStore.kt
index 4e78978873..8bdea34727 100644
--- a/libraries/preferences/api/src/main/kotlin/io/element/android/features/preferences/api/store/AppPreferencesStore.kt
+++ b/libraries/preferences/api/src/main/kotlin/io/element/android/features/preferences/api/store/AppPreferencesStore.kt
@@ -19,9 +19,6 @@ package io.element.android.features.preferences.api.store
import kotlinx.coroutines.flow.Flow
interface AppPreferencesStore {
- suspend fun setRichTextEditorEnabled(enabled: Boolean)
- fun isRichTextEditorEnabledFlow(): Flow
-
suspend fun setDeveloperModeEnabled(enabled: Boolean)
fun isDeveloperModeEnabledFlow(): Flow
diff --git a/libraries/preferences/impl/src/main/kotlin/io/element/android/libraries/preferences/impl/store/DefaultAppPreferencesStore.kt b/libraries/preferences/impl/src/main/kotlin/io/element/android/libraries/preferences/impl/store/DefaultAppPreferencesStore.kt
index fdbd7dde8c..95b455a99f 100644
--- a/libraries/preferences/impl/src/main/kotlin/io/element/android/libraries/preferences/impl/store/DefaultAppPreferencesStore.kt
+++ b/libraries/preferences/impl/src/main/kotlin/io/element/android/libraries/preferences/impl/store/DefaultAppPreferencesStore.kt
@@ -25,7 +25,6 @@ import androidx.datastore.preferences.core.stringPreferencesKey
import androidx.datastore.preferences.preferencesDataStore
import com.squareup.anvil.annotations.ContributesBinding
import io.element.android.features.preferences.api.store.AppPreferencesStore
-import io.element.android.libraries.core.bool.orTrue
import io.element.android.libraries.core.meta.BuildMeta
import io.element.android.libraries.core.meta.BuildType
import io.element.android.libraries.di.AppScope
@@ -36,7 +35,6 @@ import javax.inject.Inject
private val Context.dataStore: DataStore by preferencesDataStore(name = "elementx_preferences")
-private val richTextEditorKey = booleanPreferencesKey("richTextEditor")
private val developerModeKey = booleanPreferencesKey("developerMode")
private val customElementCallBaseUrlKey = stringPreferencesKey("elementCallBaseUrl")
private val themeKey = stringPreferencesKey("theme")
@@ -48,19 +46,6 @@ class DefaultAppPreferencesStore @Inject constructor(
) : AppPreferencesStore {
private val store = context.dataStore
- override suspend fun setRichTextEditorEnabled(enabled: Boolean) {
- store.edit { prefs ->
- prefs[richTextEditorKey] = enabled
- }
- }
-
- override fun isRichTextEditorEnabledFlow(): Flow {
- return store.data.map { prefs ->
- // enabled by default
- prefs[richTextEditorKey].orTrue()
- }
- }
-
override suspend fun setDeveloperModeEnabled(enabled: Boolean) {
store.edit { prefs ->
prefs[developerModeKey] = enabled
diff --git a/libraries/preferences/test/src/main/kotlin/io/element/android/libraries/preferences/test/InMemoryAppPreferencesStore.kt b/libraries/preferences/test/src/main/kotlin/io/element/android/libraries/preferences/test/InMemoryAppPreferencesStore.kt
index e29c4758ca..25563d59eb 100644
--- a/libraries/preferences/test/src/main/kotlin/io/element/android/libraries/preferences/test/InMemoryAppPreferencesStore.kt
+++ b/libraries/preferences/test/src/main/kotlin/io/element/android/libraries/preferences/test/InMemoryAppPreferencesStore.kt
@@ -21,24 +21,14 @@ import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableStateFlow
class InMemoryAppPreferencesStore(
- isRichTextEditorEnabled: Boolean = false,
isDeveloperModeEnabled: Boolean = false,
customElementCallBaseUrl: String? = null,
theme: String? = null,
) : AppPreferencesStore {
- private val isRichTextEditorEnabled = MutableStateFlow(isRichTextEditorEnabled)
private val isDeveloperModeEnabled = MutableStateFlow(isDeveloperModeEnabled)
private val customElementCallBaseUrl = MutableStateFlow(customElementCallBaseUrl)
private val theme = MutableStateFlow(theme)
- override suspend fun setRichTextEditorEnabled(enabled: Boolean) {
- isRichTextEditorEnabled.value = enabled
- }
-
- override fun isRichTextEditorEnabledFlow(): Flow {
- return isRichTextEditorEnabled
- }
-
override suspend fun setDeveloperModeEnabled(enabled: Boolean) {
isDeveloperModeEnabled.value = enabled
}
diff --git a/libraries/push/api/src/main/kotlin/io/element/android/libraries/push/api/PushService.kt b/libraries/push/api/src/main/kotlin/io/element/android/libraries/push/api/PushService.kt
index abfc328e9f..607213953d 100644
--- a/libraries/push/api/src/main/kotlin/io/element/android/libraries/push/api/PushService.kt
+++ b/libraries/push/api/src/main/kotlin/io/element/android/libraries/push/api/PushService.kt
@@ -24,6 +24,11 @@ interface PushService {
// TODO Move away
fun notificationStyleChanged()
+ /**
+ * Return the current push provider, or null if none.
+ */
+ suspend fun getCurrentPushProvider(): PushProvider?
+
/**
* Return the list of push providers, available at compile time, and
* available at runtime, sorted by index.
@@ -35,7 +40,11 @@ interface PushService {
*
* The method has effect only if the [PushProvider] is different than the current one.
*/
- suspend fun registerWith(matrixClient: MatrixClient, pushProvider: PushProvider, distributor: Distributor)
+ suspend fun registerWith(
+ matrixClient: MatrixClient,
+ pushProvider: PushProvider,
+ distributor: Distributor,
+ ): Result
/**
* Return false in case of early error.
diff --git a/libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/DefaultPushService.kt b/libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/DefaultPushService.kt
index cff18cfb3d..4396337883 100644
--- a/libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/DefaultPushService.kt
+++ b/libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/DefaultPushService.kt
@@ -25,6 +25,7 @@ import io.element.android.libraries.push.impl.notifications.DefaultNotificationD
import io.element.android.libraries.pushproviders.api.Distributor
import io.element.android.libraries.pushproviders.api.PushProvider
import io.element.android.libraries.pushstore.api.UserPushStoreFactory
+import timber.log.Timber
import javax.inject.Inject
@ContributesBinding(AppScope::class)
@@ -39,6 +40,11 @@ class DefaultPushService @Inject constructor(
defaultNotificationDrawerManager.notificationStyleChanged()
}
+ override suspend fun getCurrentPushProvider(): PushProvider? {
+ val currentPushProvider = getCurrentPushProvider.getCurrentPushProvider()
+ return pushProviders.find { it.name == currentPushProvider }
+ }
+
override fun getAvailablePushProviders(): List {
return pushProviders
.filter { it.isAvailable() }
@@ -48,21 +54,31 @@ class DefaultPushService @Inject constructor(
/**
* Get current push provider, compare with provided one, then unregister and register if different, and store change.
*/
- override suspend fun registerWith(matrixClient: MatrixClient, pushProvider: PushProvider, distributor: Distributor) {
+ override suspend fun registerWith(
+ matrixClient: MatrixClient,
+ pushProvider: PushProvider,
+ distributor: Distributor,
+ ): Result {
val userPushStore = userPushStoreFactory.getOrCreate(matrixClient.sessionId)
val currentPushProviderName = userPushStore.getPushProviderName()
- if (currentPushProviderName != pushProvider.name) {
+ val currentPushProvider = pushProviders.find { it.name == currentPushProviderName }
+ val currentDistributorValue = currentPushProvider?.getCurrentDistributor(matrixClient)?.value
+ if (currentPushProviderName != pushProvider.name || currentDistributorValue != distributor.value) {
// Unregister previous one if any
- pushProviders.find { it.name == currentPushProviderName }?.unregister(matrixClient)
+ currentPushProvider?.unregister(matrixClient)
+ ?.onFailure {
+ Timber.w(it, "Failed to unregister previous push provider")
+ return Result.failure(it)
+ }
}
- pushProvider.registerWith(matrixClient, distributor)
// Store new value
userPushStore.setPushProviderName(pushProvider.name)
+ // Then try to register
+ return pushProvider.registerWith(matrixClient, distributor)
}
override suspend fun testPush(): Boolean {
- val currentPushProvider = getCurrentPushProvider.getCurrentPushProvider()
- val pushProvider = pushProviders.find { it.name == currentPushProvider } ?: return false
+ val pushProvider = getCurrentPushProvider() ?: return false
val config = pushProvider.getCurrentUserPushConfig() ?: return false
pushersManager.testPush(config)
return true
diff --git a/libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/PushersManager.kt b/libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/PushersManager.kt
index 4306072e48..7dba9f5678 100644
--- a/libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/PushersManager.kt
+++ b/libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/PushersManager.kt
@@ -26,6 +26,7 @@ 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.pusher.SetHttpPusherData
+import io.element.android.libraries.matrix.api.pusher.UnsetHttpPusherData
import io.element.android.libraries.push.impl.pushgateway.PushGatewayNotifyRequest
import io.element.android.libraries.pushproviders.api.CurrentUserPushConfig
import io.element.android.libraries.pushproviders.api.PusherSubscriber
@@ -62,22 +63,26 @@ class PushersManager @Inject constructor(
/**
* Register a pusher to the server if not done yet.
*/
- override suspend fun registerPusher(matrixClient: MatrixClient, pushKey: String, gateway: String) {
+ override suspend fun registerPusher(
+ matrixClient: MatrixClient,
+ pushKey: String,
+ gateway: String,
+ ): Result {
val userDataStore = userPushStoreFactory.getOrCreate(matrixClient.sessionId)
if (userDataStore.getCurrentRegisteredPushKey() == pushKey) {
Timber.tag(loggerTag.value)
.d("Unnecessary to register again the same pusher, but do it in case the pusher has been removed from the server")
}
- matrixClient.pushersService().setHttpPusher(
- createHttpPusher(pushKey, gateway, matrixClient.sessionId)
- ).fold(
- {
+ return matrixClient.pushersService()
+ .setHttpPusher(
+ createHttpPusher(pushKey, gateway, matrixClient.sessionId)
+ )
+ .onSuccess {
userDataStore.setCurrentRegisteredPushKey(pushKey)
- },
- { throwable ->
+ }
+ .onFailure { throwable ->
Timber.tag(loggerTag.value).e(throwable, "Unable to register the pusher")
}
- )
}
private suspend fun createHttpPusher(
@@ -106,8 +111,25 @@ class PushersManager @Inject constructor(
return "{\"cs\":\"$secretForUser\"}"
}
- override suspend fun unregisterPusher(matrixClient: MatrixClient, pushKey: String, gateway: String) {
- matrixClient.pushersService().unsetHttpPusher()
+ override suspend fun unregisterPusher(
+ matrixClient: MatrixClient,
+ pushKey: String,
+ gateway: String,
+ ): Result {
+ val userDataStore = userPushStoreFactory.getOrCreate(matrixClient.sessionId)
+ return matrixClient.pushersService()
+ .unsetHttpPusher(
+ unsetHttpPusherData = UnsetHttpPusherData(
+ pushKey = pushKey,
+ appId = PushConfig.PUSHER_APP_ID
+ )
+ )
+ .onSuccess {
+ userDataStore.setCurrentRegisteredPushKey(null)
+ }
+ .onFailure { throwable ->
+ Timber.tag(loggerTag.value).e(throwable, "Unable to unregister the pusher")
+ }
}
companion object {
diff --git a/libraries/push/impl/src/main/res/values-be/translations.xml b/libraries/push/impl/src/main/res/values-be/translations.xml
index 686d10a281..fd85f11ac3 100644
--- a/libraries/push/impl/src/main/res/values-be/translations.xml
+++ b/libraries/push/impl/src/main/res/values-be/translations.xml
@@ -52,7 +52,6 @@
- "%d пакоя"
- "%d пакояў"
- "Выберыце спосаб атрымання апавяшчэнняў"
"Фонавая сінхранізацыя"
"Сэрвісы Google"
"Службы Google Play не знойдзены. Апавяшчэнні могуць не працаваць належным чынам."
diff --git a/libraries/push/impl/src/main/res/values-cs/translations.xml b/libraries/push/impl/src/main/res/values-cs/translations.xml
index fac2a69784..c2d93dc94b 100644
--- a/libraries/push/impl/src/main/res/values-cs/translations.xml
+++ b/libraries/push/impl/src/main/res/values-cs/translations.xml
@@ -52,7 +52,6 @@
- "%d místnosti"
- "%d místností"
- "Vyberte, jak chcete přijímat oznámení"
"Synchronizace na pozadí"
"Služby Google"
"Nebyly nalezeny žádné funkční služby Google Play. Oznámení nemusí fungovat správně."
diff --git a/libraries/push/impl/src/main/res/values-de/translations.xml b/libraries/push/impl/src/main/res/values-de/translations.xml
index 2757e89dea..0d1988ecba 100644
--- a/libraries/push/impl/src/main/res/values-de/translations.xml
+++ b/libraries/push/impl/src/main/res/values-de/translations.xml
@@ -46,7 +46,6 @@
- "%d Raum"
- "%d Räume"
- "Wähle aus, wie du Benachrichtigungen erhalten möchtest"
"Hintergrundsynchronisation"
"Google-Dienste"
"Keine gültigen Google Play-Dienste gefunden. Benachrichtigungen funktionieren möglicherweise nicht richtig."
diff --git a/libraries/push/impl/src/main/res/values-es/translations.xml b/libraries/push/impl/src/main/res/values-es/translations.xml
index 9fd13f5768..37f495a163 100644
--- a/libraries/push/impl/src/main/res/values-es/translations.xml
+++ b/libraries/push/impl/src/main/res/values-es/translations.xml
@@ -28,6 +28,7 @@
- "%d mensajes nuevos"
"Reaccionó con %1$s"
+ "Marcar como leído"
"Respuesta rápida"
"Te invitó a unirte a la sala"
"Yo"
@@ -45,7 +46,6 @@
- "%d sala"
- "%d salas"
- "Elige cómo recibir las notificaciones"
"Sincronización en segundo plano"
"Servicios de Google"
"No se han encontrado Servicios de Google Play válidos. Es posible que las notificaciones no funcionen correctamente."
diff --git a/libraries/push/impl/src/main/res/values-fr/translations.xml b/libraries/push/impl/src/main/res/values-fr/translations.xml
index 8501b8ad76..6173724762 100644
--- a/libraries/push/impl/src/main/res/values-fr/translations.xml
+++ b/libraries/push/impl/src/main/res/values-fr/translations.xml
@@ -46,7 +46,6 @@
- "%d salon"
- "%d salons"
- "Choisissez le mode de réception des notifications"
"Synchronisation en arrière-plan"
"Services Google"
"Aucun service Google Play valide n’a été trouvé. Les notifications peuvent ne pas fonctionner correctement."
diff --git a/libraries/push/impl/src/main/res/values-hu/translations.xml b/libraries/push/impl/src/main/res/values-hu/translations.xml
index 7b0c66aa65..75804dd0a2 100644
--- a/libraries/push/impl/src/main/res/values-hu/translations.xml
+++ b/libraries/push/impl/src/main/res/values-hu/translations.xml
@@ -46,7 +46,6 @@
- "%d szoba"
- "%d szoba"
- "Válassza ki az értesítések fogadási módját"
"Háttérszinkronizálás"
"Google szolgáltatások"
"A Google Play szolgáltatások nem találhatók. Előfordulhat, hogy az értesítések nem működnek megfelelően."
diff --git a/libraries/push/impl/src/main/res/values-in/translations.xml b/libraries/push/impl/src/main/res/values-in/translations.xml
index b933330be1..cfc6621d17 100644
--- a/libraries/push/impl/src/main/res/values-in/translations.xml
+++ b/libraries/push/impl/src/main/res/values-in/translations.xml
@@ -40,7 +40,6 @@
- "%d ruangan"
- "Pilih cara menerima notifikasi"
"Sinkronisasi latar belakang"
"Layanan Google"
"Tidak ditemukan Layanan Google Play yang valid. Pemberitahuan mungkin tidak berfungsi dengan baik."
diff --git a/libraries/push/impl/src/main/res/values-it/translations.xml b/libraries/push/impl/src/main/res/values-it/translations.xml
index fe52cd7433..a15e3daa14 100644
--- a/libraries/push/impl/src/main/res/values-it/translations.xml
+++ b/libraries/push/impl/src/main/res/values-it/translations.xml
@@ -46,7 +46,6 @@
- "%d stanza"
- "%d stanze"
- "Scegli come ricevere le notifiche"
"Sincronizzazione in background"
"Servizi Google"
"Google Play Services non trovato. Le notifiche non funzioneranno bene."
@@ -67,5 +66,11 @@
"La notifica è stata cliccata!"
"Mostra notifica"
"Clicca sulla notifica per continuare il test."
+ "Assicurati che l\'applicazione riceva le notifiche push"
+ "Errore: il servizio push ha rifiutato la richiesta."
"Errore: %1$s."
+ "Errore, impossibile testare le notifiche push."
+ "Errore, tempo scaduto in attesa della notifica push."
+ "Il test push loop back ha impiegato %1$d ms."
+ "Prova invio notifica push loop back"
diff --git a/libraries/push/impl/src/main/res/values-ka/translations.xml b/libraries/push/impl/src/main/res/values-ka/translations.xml
new file mode 100644
index 0000000000..4f02db32fa
--- /dev/null
+++ b/libraries/push/impl/src/main/res/values-ka/translations.xml
@@ -0,0 +1,50 @@
+
+
+ "ზარი"
+ "მოვლენებისთვის მოსმენა"
+ "ხმაურიანი შეტყობინებები"
+ "ჩუმი შეტყობინებები"
+
+ - "%1$s: %2$d შეტყობინება"
+ - "%1$s: %2$d შეტყობინება"
+
+
+ - "%d შეტყობინება"
+ - "%d შეტყობინება"
+
+ "შეტყობინება"
+ "** გაგზავნა ვერ მოხერხდა - გთხოვთ, გახსნათ ოთახი"
+ "გაწევრიანება"
+ "უარყოფა"
+
+ - "%d მოწვევა"
+ - "%d მოწვევები"
+
+ "მოგიწვიათ ჩატში"
+ "ახალი შეტყობინებები"
+
+ - "%d ახალი მესიჯი"
+ - "%d ახალი მესიჯი"
+
+ "რეაგირება მოხდა: %1$s"
+ "Სწრაფი პასუხი"
+ "მოგიწვიათ ოთახში"
+ "მე"
+ "თქვენ ხედავთ შეტყობინებას! დამაწკაპუნეთ!"
+ "%1$s: %2$s"
+ "%1$s: %2$s %3$s"
+
+ - "%d წაუკითხავი შეტყობინება"
+ - "%d წაუკითხავი შეტყობინება"
+
+ "%1$s და %2$s"
+ "%1$s %2$s-ში"
+ "%1$s %2$s-ში და %3$s"
+
+ - "%d ოთახი"
+ - "%d ოთახი"
+
+ "ფონის სინქრონიზაცია"
+ "Google სერვისები"
+ "მოქმედი Google Play სერვისები ვერ მოიძებნა. შეტყობინებები შეიძლება ვერ იმუშაოს სწორად."
+
diff --git a/libraries/push/impl/src/main/res/values-pt/translations.xml b/libraries/push/impl/src/main/res/values-pt/translations.xml
new file mode 100644
index 0000000000..c5513675f5
--- /dev/null
+++ b/libraries/push/impl/src/main/res/values-pt/translations.xml
@@ -0,0 +1,76 @@
+
+
+ "Chamada"
+ "À escuta de eventos"
+ "Notificações barulhentas"
+ "Notificações silenciosas"
+
+ - "%1$s: %2$d mensagem"
+ - "%1$s: %2$d mensagens"
+
+
+ - "%d notificação"
+ - "%d notificações"
+
+ "Notificação"
+ "** Falha no envio - por favor abre a sala"
+ "Entrar"
+ "Rejeitar"
+
+ - "%d convite"
+ - "%d convites"
+
+ "Convidou-te para conversar"
+ "Mencionou-te: %1$s"
+ "Mensagens novas"
+
+ - "%d mensagem nova"
+ - "%d mensagens novas"
+
+ "Reagiu com %1$s"
+ "Marcar como lida"
+ "Resposta rápida"
+ "Convidou-te a entrar na sala"
+ "Eu"
+ "Estás a ver a notificação! Clica em mim!"
+ "%1$s: %2$s"
+ "%1$s: %2$s %3$s"
+
+ - "%d mensagem notificada não lida"
+ - "%d mensagens notificadas não lidas"
+
+ "%1$s e %2$s"
+ "%1$s em %2$s"
+ "%1$s em %2$s e %3$s"
+
+ - "%d sala"
+ - "%d salas"
+
+ "Sincronização em segundo plano"
+ "Serviços do Google Play"
+ "Nenhuns Serviços do Google Play válidos encontrados. As notificações poderão não funcionar devidamente."
+ "Obtém o nome do fornecedor atual."
+ "Nenhum fornecedor de envio selecionado."
+ "Fornecedor de envio atual: %1$s."
+ "Fornecedor de envio atual"
+ "Certifica que a aplicação tem pelo menos um fornecedor de envio."
+ "Nenhum fornecedor de envio encontrado."
+
+ - "%1$d fornecedor de envio encontrado: %2$s"
+ - "%1$d fornecedores de envio encontrados: %2$s"
+
+ "Detetar fornecedores de envio"
+ "Verificar se a aplicação consegue mostrar notificações."
+ "Não clicaste na notificação."
+ "Não foi possível mostrar a notificação."
+ "Clicaste na notificação!"
+ "Mostrar notificação"
+ "Por favor, carrega na notificação para continuar o teste."
+ "Certifica que a aplicação está a receber notificações instantâneas."
+ "Erro: fornecedor de envio rejeitou o pedido"
+ "Erro: %1$s."
+ "Erro: não foi possível testar envio"
+ "Erro: envio demorou demasiado"
+ "O ciclo de envio demorou %1$d ms."
+ "Testar ciclo de envio"
+
diff --git a/libraries/push/impl/src/main/res/values-ro/translations.xml b/libraries/push/impl/src/main/res/values-ro/translations.xml
index f242c96ee5..b9862a69a3 100644
--- a/libraries/push/impl/src/main/res/values-ro/translations.xml
+++ b/libraries/push/impl/src/main/res/values-ro/translations.xml
@@ -46,8 +46,32 @@
- "%d cameră"
- "%d camere"
- "Alegeți modul de primire a notificărilor"
"Sincronizare în fundal"
"Servicii Google"
"Nu au fost găsite servicii Google Play valide. Este posibil ca notificările să nu funcționeze corect."
+ "Obțineți numele furnizorului curent."
+ "Niciun furnizor push selectat."
+ "Furnizor de push actual: %1$s."
+ "Furnizor de push curent"
+ "Asigurați-vă că aplicația are cel puțin un furnizor push."
+ "Nu s-au găsit furnizori push."
+
+ - "S-a găsit %1$d furnizor push: %2$s"
+ - "S-au găsit %1$d furnizori push: %2$s"
+ - "S-au găsit %1$d furnizori push: %2$s"
+
+ "Detectați furnizorii push"
+ "Verificați dacă aplicația poate afișa notificări."
+ "Notificarea nu a fost apăsată."
+ "Nu s-a putut afișa notificarea."
+ "Notificarea a fost apăsată!"
+ "Afișați notificarea"
+ "Vă rugăm să faceți clic pe notificare pentru a continua testul."
+ "Asigurați-vă că aplicația primește push-uri."
+ "Eroare: pusher-ul a respins cererea."
+ "Eroare: %1$s."
+ "Eroare, nu se poate testa push-ul."
+ "Eroare, timeout în așteptare pentru push."
+ "Push-ul înapoi a durat %1$d ms."
+ "Testați că push-ul se întoarce"
diff --git a/libraries/push/impl/src/main/res/values-ru/translations.xml b/libraries/push/impl/src/main/res/values-ru/translations.xml
index 65242651b2..ff78cba4ee 100644
--- a/libraries/push/impl/src/main/res/values-ru/translations.xml
+++ b/libraries/push/impl/src/main/res/values-ru/translations.xml
@@ -52,7 +52,6 @@
- "%d комнаты"
- "%d комнат"
- "Выберите способ получения уведомлений"
"Фоновая синхронизация"
"Сервисы Google"
"Не найдены действующие службы Google Play. Уведомления могут работать некорректно."
diff --git a/libraries/push/impl/src/main/res/values-sk/translations.xml b/libraries/push/impl/src/main/res/values-sk/translations.xml
index 95aed49bd3..e984d1547c 100644
--- a/libraries/push/impl/src/main/res/values-sk/translations.xml
+++ b/libraries/push/impl/src/main/res/values-sk/translations.xml
@@ -52,7 +52,6 @@
- "%d miestnosti"
- "%d miestností"
- "Vyberte spôsob prijímania oznámení"
"Synchronizácia na pozadí"
"Služby Google"
"Nenašli sa žiadne platné služby Google Play. Oznámenia nemusia fungovať správne."
diff --git a/libraries/push/impl/src/main/res/values-sv/translations.xml b/libraries/push/impl/src/main/res/values-sv/translations.xml
index 6930a3b13e..8d26670c34 100644
--- a/libraries/push/impl/src/main/res/values-sv/translations.xml
+++ b/libraries/push/impl/src/main/res/values-sv/translations.xml
@@ -45,7 +45,6 @@
- "%d rum"
- "%d rum"
- "Välj hur du vill ta emot aviseringar"
"Bakgrundssynkronisering"
"Google-tjänster"
"Inga giltiga Google Play-tjänster hittades. Aviseringar kanske inte fungerar korrekt."
diff --git a/libraries/push/impl/src/main/res/values-uk/translations.xml b/libraries/push/impl/src/main/res/values-uk/translations.xml
index a447f7ea2c..e1a3f8bf47 100644
--- a/libraries/push/impl/src/main/res/values-uk/translations.xml
+++ b/libraries/push/impl/src/main/res/values-uk/translations.xml
@@ -52,8 +52,8 @@
- "%d кімнати"
- "%d кімнат"
- "Виберіть спосіб отримання сповіщень"
"Фонова синхронізація"
"Сервіси Google"
"Не знайдено дійсних сервісів Google Play. Сповіщення можуть не працювати належним чином."
+ "Не вдається відобразити сповіщення."
diff --git a/libraries/push/impl/src/main/res/values-zh-rTW/translations.xml b/libraries/push/impl/src/main/res/values-zh-rTW/translations.xml
index 86b8661c35..7b9e1a44f9 100644
--- a/libraries/push/impl/src/main/res/values-zh-rTW/translations.xml
+++ b/libraries/push/impl/src/main/res/values-zh-rTW/translations.xml
@@ -31,7 +31,6 @@
- "%d 個聊天室"
- "選擇接收通知的機制"
"背景同步"
"Google 服務"
diff --git a/libraries/push/impl/src/main/res/values-zh/translations.xml b/libraries/push/impl/src/main/res/values-zh/translations.xml
new file mode 100644
index 0000000000..9a4e2f47d2
--- /dev/null
+++ b/libraries/push/impl/src/main/res/values-zh/translations.xml
@@ -0,0 +1,69 @@
+
+
+ "通话"
+ "监听事件"
+ "嘈杂通知"
+ "静默通知"
+
+ - "%1$s:%2$d 条消息"
+
+
+ - "%d 条通知"
+
+ "通知"
+ "** 无法发送——请打开房间"
+ "加入"
+ "拒绝"
+
+ - "%d 个邀请"
+
+ "邀请您聊天"
+ "提到了你:%1$s"
+ "新消息"
+
+ - "%d 条新消息"
+
+ "使用 %1$s 回应"
+ "标记为已读"
+ "快速回复"
+ "邀请你加入房间"
+ "我"
+ "您正在查看通知!点击我!"
+ "%1$s:%2$s"
+ "%1$s: %2$s %3$s"
+
+ - "%d 条未读消息"
+
+ "%1$s 和 %2$s"
+ "%2$s 中的 %1$s"
+ "在 %2$s 和 %3$s 中的 %1$s"
+
+ - "%d 个房间"
+
+ "后台同步"
+ "谷歌服务"
+ "找不到有效的 Google Play 服务。通知可能无法正常工作。"
+ "获取当前推送提供者的名称。"
+ "未选择任何推送提供者。"
+ "当前推送提供者:%1$s。"
+ "当前推送提供者"
+ "确保应用程序至少有一个推送提供者。"
+ "未找到推送提供者。"
+
+ - "找到了 %1$d 个推送提供者:%2$s"
+
+ "检测推送提供者"
+ "检查应用程序是否可以显示通知。"
+ "通知未被点击。"
+ "无法显示通知。"
+ "通知已被点击!"
+ "显示通知"
+ "请点击通知继续测试。"
+ "确保应用程序正在接收推送。"
+ "错误:推送者拒绝了该请求。"
+ "错误:%1$s。"
+ "错误,无法测试推送。"
+ "错误,等待推送超时。"
+ "推送回路耗时%1$d 毫秒。"
+ "测试推送回路"
+
diff --git a/libraries/push/impl/src/main/res/values/localazy.xml b/libraries/push/impl/src/main/res/values/localazy.xml
index c9d7627d07..1064d5c31e 100644
--- a/libraries/push/impl/src/main/res/values/localazy.xml
+++ b/libraries/push/impl/src/main/res/values/localazy.xml
@@ -46,7 +46,6 @@
- "%d room"
- "%d rooms"
- "Choose how to receive notifications"
"Background synchronization"
"Google Services"
"No valid Google Play Services found. Notifications may not work properly."
diff --git a/libraries/push/test/src/main/kotlin/io/element/android/libraries/push/test/FakePushService.kt b/libraries/push/test/src/main/kotlin/io/element/android/libraries/push/test/FakePushService.kt
index 969815ec66..a148e5f6a2 100644
--- a/libraries/push/test/src/main/kotlin/io/element/android/libraries/push/test/FakePushService.kt
+++ b/libraries/push/test/src/main/kotlin/io/element/android/libraries/push/test/FakePushService.kt
@@ -23,16 +23,29 @@ import io.element.android.libraries.pushproviders.api.PushProvider
import io.element.android.tests.testutils.simulateLongTask
class FakePushService(
- private val testPushBlock: suspend () -> Boolean = { true }
+ private val testPushBlock: suspend () -> Boolean = { true },
+ private val availablePushProviders: List = emptyList(),
+ private val registerWithLambda: suspend (MatrixClient, PushProvider, Distributor) -> Result = { _, _, _ ->
+ Result.success(Unit)
+ },
) : PushService {
override fun notificationStyleChanged() {
}
- override fun getAvailablePushProviders(): List {
- return emptyList()
+ override suspend fun getCurrentPushProvider(): PushProvider? {
+ return availablePushProviders.firstOrNull()
}
- override suspend fun registerWith(matrixClient: MatrixClient, pushProvider: PushProvider, distributor: Distributor) {
+ override fun getAvailablePushProviders(): List {
+ return availablePushProviders
+ }
+
+ override suspend fun registerWith(
+ matrixClient: MatrixClient,
+ pushProvider: PushProvider,
+ distributor: Distributor,
+ ): Result = simulateLongTask {
+ return registerWithLambda(matrixClient, pushProvider, distributor)
}
override suspend fun testPush(): Boolean = simulateLongTask {
diff --git a/libraries/pushproviders/api/src/main/kotlin/io/element/android/libraries/pushproviders/api/Distributor.kt b/libraries/pushproviders/api/src/main/kotlin/io/element/android/libraries/pushproviders/api/Distributor.kt
index 7eda80fed9..1db3dc2610 100644
--- a/libraries/pushproviders/api/src/main/kotlin/io/element/android/libraries/pushproviders/api/Distributor.kt
+++ b/libraries/pushproviders/api/src/main/kotlin/io/element/android/libraries/pushproviders/api/Distributor.kt
@@ -16,6 +16,14 @@
package io.element.android.libraries.pushproviders.api
+/**
+ * Firebase does not have the concept of distributor. So for Firebase, there will be one distributor:
+ * Distributor("Firebase", "Firebase").
+ *
+ * For UnifiedPush, for instance, the Distributor can be:
+ * Distributor("io.heckel.ntfy", "ntfy").
+ * But other values are possible.
+ */
data class Distributor(
val value: String,
val name: String,
diff --git a/libraries/pushproviders/api/src/main/kotlin/io/element/android/libraries/pushproviders/api/PushProvider.kt b/libraries/pushproviders/api/src/main/kotlin/io/element/android/libraries/pushproviders/api/PushProvider.kt
index 4e9b818dd4..d111dc139f 100644
--- a/libraries/pushproviders/api/src/main/kotlin/io/element/android/libraries/pushproviders/api/PushProvider.kt
+++ b/libraries/pushproviders/api/src/main/kotlin/io/element/android/libraries/pushproviders/api/PushProvider.kt
@@ -42,12 +42,17 @@ interface PushProvider {
/**
* Register the pusher to the homeserver.
*/
- suspend fun registerWith(matrixClient: MatrixClient, distributor: Distributor)
+ suspend fun registerWith(matrixClient: MatrixClient, distributor: Distributor): Result
+
+ /**
+ * Return the current distributor, or null if none.
+ */
+ suspend fun getCurrentDistributor(matrixClient: MatrixClient): Distributor?
/**
* Unregister the pusher.
*/
- suspend fun unregister(matrixClient: MatrixClient)
+ suspend fun unregister(matrixClient: MatrixClient): Result
suspend fun getCurrentUserPushConfig(): CurrentUserPushConfig?
}
diff --git a/libraries/pushproviders/api/src/main/kotlin/io/element/android/libraries/pushproviders/api/PusherSubscriber.kt b/libraries/pushproviders/api/src/main/kotlin/io/element/android/libraries/pushproviders/api/PusherSubscriber.kt
index 2529e4bb96..d38f5dec1e 100644
--- a/libraries/pushproviders/api/src/main/kotlin/io/element/android/libraries/pushproviders/api/PusherSubscriber.kt
+++ b/libraries/pushproviders/api/src/main/kotlin/io/element/android/libraries/pushproviders/api/PusherSubscriber.kt
@@ -19,6 +19,6 @@ package io.element.android.libraries.pushproviders.api
import io.element.android.libraries.matrix.api.MatrixClient
interface PusherSubscriber {
- suspend fun registerPusher(matrixClient: MatrixClient, pushKey: String, gateway: String)
- suspend fun unregisterPusher(matrixClient: MatrixClient, pushKey: String, gateway: String)
+ suspend fun registerPusher(matrixClient: MatrixClient, pushKey: String, gateway: String): Result
+ suspend fun unregisterPusher(matrixClient: MatrixClient, pushKey: String, gateway: String): Result
}
diff --git a/libraries/pushproviders/firebase/src/main/kotlin/io/element/android/libraries/pushproviders/firebase/FirebaseNewTokenHandler.kt b/libraries/pushproviders/firebase/src/main/kotlin/io/element/android/libraries/pushproviders/firebase/FirebaseNewTokenHandler.kt
index 20d0de4ebf..e61ea4bc91 100644
--- a/libraries/pushproviders/firebase/src/main/kotlin/io/element/android/libraries/pushproviders/firebase/FirebaseNewTokenHandler.kt
+++ b/libraries/pushproviders/firebase/src/main/kotlin/io/element/android/libraries/pushproviders/firebase/FirebaseNewTokenHandler.kt
@@ -16,6 +16,7 @@
package io.element.android.libraries.pushproviders.firebase
+import io.element.android.libraries.core.extensions.flatMap
import io.element.android.libraries.core.log.logger.LoggerTag
import io.element.android.libraries.matrix.api.auth.MatrixAuthenticationService
import io.element.android.libraries.matrix.api.core.SessionId
@@ -43,12 +44,24 @@ class FirebaseNewTokenHandler @Inject constructor(
// Register the pusher for all the sessions
sessionStore.getAllSessions().toUserList()
.map { SessionId(it) }
- .forEach { userId ->
- val userDataStore = userPushStoreFactory.getOrCreate(userId)
+ .forEach { sessionId ->
+ val userDataStore = userPushStoreFactory.getOrCreate(sessionId)
if (userDataStore.getPushProviderName() == FirebaseConfig.NAME) {
- matrixAuthenticationService.restoreSession(userId).getOrNull()?.use { client ->
- pusherSubscriber.registerPusher(client, firebaseToken, FirebaseConfig.PUSHER_HTTP_URL)
- }
+ matrixAuthenticationService
+ .restoreSession(sessionId)
+ .onFailure {
+ Timber.tag(loggerTag.value).e(it, "Failed to restore session $sessionId")
+ }
+ .flatMap { client ->
+ pusherSubscriber.registerPusher(
+ matrixClient = client,
+ pushKey = firebaseToken,
+ gateway = FirebaseConfig.PUSHER_HTTP_URL,
+ )
+ }
+ .onFailure {
+ Timber.tag(loggerTag.value).e(it, "Failed to register pusher for session $sessionId")
+ }
} else {
Timber.tag(loggerTag.value).d("This session is not using Firebase pusher")
}
diff --git a/libraries/pushproviders/firebase/src/main/kotlin/io/element/android/libraries/pushproviders/firebase/FirebasePushProvider.kt b/libraries/pushproviders/firebase/src/main/kotlin/io/element/android/libraries/pushproviders/firebase/FirebasePushProvider.kt
index 317d49f3b6..b88d70b157 100644
--- a/libraries/pushproviders/firebase/src/main/kotlin/io/element/android/libraries/pushproviders/firebase/FirebasePushProvider.kt
+++ b/libraries/pushproviders/firebase/src/main/kotlin/io/element/android/libraries/pushproviders/firebase/FirebasePushProvider.kt
@@ -43,21 +43,35 @@ class FirebasePushProvider @Inject constructor(
}
override fun getDistributors(): List {
- return listOf(Distributor("Firebase", "Firebase"))
+ return listOf(firebaseDistributor)
}
- override suspend fun registerWith(matrixClient: MatrixClient, distributor: Distributor) {
- val pushKey = firebaseStore.getFcmToken() ?: return Unit.also {
+ override suspend fun registerWith(matrixClient: MatrixClient, distributor: Distributor): Result {
+ val pushKey = firebaseStore.getFcmToken() ?: return Result.failure(
+ IllegalStateException(
+ "Unable to register pusher, Firebase token is not known."
+ )
+ ).also {
Timber.tag(loggerTag.value).w("Unable to register pusher, Firebase token is not known.")
}
- pusherSubscriber.registerPusher(matrixClient, pushKey, FirebaseConfig.PUSHER_HTTP_URL)
+ return pusherSubscriber.registerPusher(
+ matrixClient = matrixClient,
+ pushKey = pushKey,
+ gateway = FirebaseConfig.PUSHER_HTTP_URL,
+ )
}
- override suspend fun unregister(matrixClient: MatrixClient) {
- val pushKey = firebaseStore.getFcmToken() ?: return Unit.also {
+ override suspend fun getCurrentDistributor(matrixClient: MatrixClient) = firebaseDistributor
+
+ override suspend fun unregister(matrixClient: MatrixClient): Result {
+ val pushKey = firebaseStore.getFcmToken() ?: return Result.failure(
+ IllegalStateException(
+ "Unable to unregister pusher, Firebase token is not known."
+ )
+ ).also {
Timber.tag(loggerTag.value).w("Unable to unregister pusher, Firebase token is not known.")
}
- pusherSubscriber.unregisterPusher(matrixClient, pushKey, FirebaseConfig.PUSHER_HTTP_URL)
+ return pusherSubscriber.unregisterPusher(matrixClient, pushKey, FirebaseConfig.PUSHER_HTTP_URL)
}
override suspend fun getCurrentUserPushConfig(): CurrentUserPushConfig? {
@@ -68,4 +82,8 @@ class FirebasePushProvider @Inject constructor(
)
}
}
+
+ companion object {
+ private val firebaseDistributor = Distributor("Firebase", "Firebase")
+ }
}
diff --git a/libraries/pushproviders/firebase/src/main/res/values-pt/translations.xml b/libraries/pushproviders/firebase/src/main/res/values-pt/translations.xml
new file mode 100644
index 0000000000..2c9344dcb3
--- /dev/null
+++ b/libraries/pushproviders/firebase/src/main/res/values-pt/translations.xml
@@ -0,0 +1,11 @@
+
+
+ "Certifica que a Firebase está disponível"
+ "Firebase indisponível."
+ "Firebase disponível."
+ "Verificar a Firebase"
+ "Certifica que o \"token\" da Firebase está disponível."
+ "\"Token\" da Firebase desconhecido."
+ "\"Token\" da Firebase: %1$s."
+ "Verificar \"token\" da Firebase"
+
diff --git a/libraries/pushproviders/firebase/src/main/res/values-ro/translations.xml b/libraries/pushproviders/firebase/src/main/res/values-ro/translations.xml
new file mode 100644
index 0000000000..72e13904d5
--- /dev/null
+++ b/libraries/pushproviders/firebase/src/main/res/values-ro/translations.xml
@@ -0,0 +1,11 @@
+
+
+ "Asigurați-vă că Firebase este disponibil."
+ "Firebase nu este disponibil."
+ "Firebase este disponibil."
+ "Verificați Firebase"
+ "Asigurați-vă că tokenul Firebase este disponibil."
+ "Tokenul Firebase nu este cunoscut."
+ "Token Firebase: %1$s."
+ "Verificați token-ul Firebase"
+
diff --git a/libraries/pushproviders/firebase/src/main/res/values-zh/translations.xml b/libraries/pushproviders/firebase/src/main/res/values-zh/translations.xml
new file mode 100644
index 0000000000..661d2d13d7
--- /dev/null
+++ b/libraries/pushproviders/firebase/src/main/res/values-zh/translations.xml
@@ -0,0 +1,11 @@
+
+
+ "确保 Firebase 可用。"
+ "Firebase 不可用。"
+ "Firebase 可用。"
+ "检查 Firebase"
+ "确保 Firebase 令牌可用。"
+ "Firebas 令牌未知。"
+ "Firebase 令牌:%1$s 。"
+ "检查 Firebase 令牌"
+
diff --git a/libraries/pushproviders/test/src/main/kotlin/io/element/android/libraries/pushproviders/test/FakePushProvider.kt b/libraries/pushproviders/test/src/main/kotlin/io/element/android/libraries/pushproviders/test/FakePushProvider.kt
index 8d8b94ec19..44aa1ca18f 100644
--- a/libraries/pushproviders/test/src/main/kotlin/io/element/android/libraries/pushproviders/test/FakePushProvider.kt
+++ b/libraries/pushproviders/test/src/main/kotlin/io/element/android/libraries/pushproviders/test/FakePushProvider.kt
@@ -25,18 +25,22 @@ class FakePushProvider(
override val index: Int = 0,
override val name: String = "aFakePushProvider",
private val isAvailable: Boolean = true,
- private val distributors: List = emptyList()
+ private val distributors: List = listOf(Distributor("aDistributorValue", "aDistributorName")),
) : PushProvider {
override fun isAvailable(): Boolean = isAvailable
override fun getDistributors(): List = distributors
- override suspend fun registerWith(matrixClient: MatrixClient, distributor: Distributor) {
- // No-op
+ override suspend fun registerWith(matrixClient: MatrixClient, distributor: Distributor): Result {
+ return Result.success(Unit)
}
- override suspend fun unregister(matrixClient: MatrixClient) {
- // No-op
+ override suspend fun getCurrentDistributor(matrixClient: MatrixClient): Distributor? {
+ return distributors.firstOrNull()
+ }
+
+ override suspend fun unregister(matrixClient: MatrixClient): Result {
+ return Result.success(Unit)
}
override suspend fun getCurrentUserPushConfig(): CurrentUserPushConfig? {
diff --git a/libraries/pushproviders/unifiedpush/src/main/kotlin/io/element/android/libraries/pushproviders/unifiedpush/RegisterUnifiedPushUseCase.kt b/libraries/pushproviders/unifiedpush/src/main/kotlin/io/element/android/libraries/pushproviders/unifiedpush/RegisterUnifiedPushUseCase.kt
index 8dd71118b3..24f93b88dc 100644
--- a/libraries/pushproviders/unifiedpush/src/main/kotlin/io/element/android/libraries/pushproviders/unifiedpush/RegisterUnifiedPushUseCase.kt
+++ b/libraries/pushproviders/unifiedpush/src/main/kotlin/io/element/android/libraries/pushproviders/unifiedpush/RegisterUnifiedPushUseCase.kt
@@ -18,55 +18,42 @@ package io.element.android.libraries.pushproviders.unifiedpush
import android.content.Context
import io.element.android.libraries.di.ApplicationContext
-import io.element.android.libraries.matrix.api.MatrixClient
import io.element.android.libraries.pushproviders.api.Distributor
-import io.element.android.libraries.pushproviders.api.PusherSubscriber
+import io.element.android.libraries.pushproviders.unifiedpush.registration.EndpointRegistrationHandler
+import kotlinx.coroutines.CompletableDeferred
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.flow.filter
+import kotlinx.coroutines.flow.first
+import kotlinx.coroutines.launch
+import kotlinx.coroutines.withTimeout
import org.unifiedpush.android.connector.UnifiedPush
import javax.inject.Inject
+import kotlin.time.Duration.Companion.seconds
class RegisterUnifiedPushUseCase @Inject constructor(
@ApplicationContext private val context: Context,
- private val pusherSubscriber: PusherSubscriber,
- private val unifiedPushStore: UnifiedPushStore,
+ private val endpointRegistrationHandler: EndpointRegistrationHandler,
+ private val coroutineScope: CoroutineScope,
) {
- sealed interface RegisterUnifiedPushResult {
- data object Success : RegisterUnifiedPushResult
- data object NeedToAskUserForDistributor : RegisterUnifiedPushResult
- data object Error : RegisterUnifiedPushResult
- }
-
- suspend fun execute(matrixClient: MatrixClient, distributor: Distributor, clientSecret: String): RegisterUnifiedPushResult {
- val distributorValue = distributor.value
- if (distributorValue.isNotEmpty()) {
- saveAndRegisterApp(distributorValue, clientSecret)
- val endpoint = unifiedPushStore.getEndpoint(clientSecret) ?: return RegisterUnifiedPushResult.Error
- val gateway = unifiedPushStore.getPushGateway(clientSecret) ?: return RegisterUnifiedPushResult.Error
- pusherSubscriber.registerPusher(matrixClient, endpoint, gateway)
- return RegisterUnifiedPushResult.Success
+ suspend fun execute(distributor: Distributor, clientSecret: String): Result {
+ UnifiedPush.saveDistributor(context, distributor.value)
+ val completable = CompletableDeferred>()
+ val job = coroutineScope.launch {
+ val result = endpointRegistrationHandler.state
+ .filter { it.clientSecret == clientSecret }
+ .first()
+ .result
+ completable.complete(result)
}
-
- // TODO Below should never happen?
- if (UnifiedPush.getDistributor(context).isNotEmpty()) {
- registerApp(clientSecret)
- return RegisterUnifiedPushResult.Success
- }
-
- val distributors = UnifiedPush.getDistributors(context)
-
- return if (distributors.size == 1) {
- saveAndRegisterApp(distributors.first(), clientSecret)
- RegisterUnifiedPushResult.Success
- } else {
- RegisterUnifiedPushResult.NeedToAskUserForDistributor
- }
- }
-
- private fun saveAndRegisterApp(distributor: String, clientSecret: String) {
- UnifiedPush.saveDistributor(context, distributor)
- registerApp(clientSecret)
- }
-
- private fun registerApp(clientSecret: String) {
+ // This will trigger the callback
+ // VectorUnifiedPushMessagingReceiver.onNewEndpoint
UnifiedPush.registerApp(context = context, instance = clientSecret)
+ // Wait for VectorUnifiedPushMessagingReceiver.onNewEndpoint to proceed
+ return withTimeout(30.seconds) {
+ completable.await()
+ }
+ .onFailure {
+ job.cancel()
+ }
}
}
diff --git a/libraries/pushproviders/unifiedpush/src/main/kotlin/io/element/android/libraries/pushproviders/unifiedpush/UnifiedPushNewGatewayHandler.kt b/libraries/pushproviders/unifiedpush/src/main/kotlin/io/element/android/libraries/pushproviders/unifiedpush/UnifiedPushNewGatewayHandler.kt
index 4ee637a3ab..3ae733d261 100644
--- a/libraries/pushproviders/unifiedpush/src/main/kotlin/io/element/android/libraries/pushproviders/unifiedpush/UnifiedPushNewGatewayHandler.kt
+++ b/libraries/pushproviders/unifiedpush/src/main/kotlin/io/element/android/libraries/pushproviders/unifiedpush/UnifiedPushNewGatewayHandler.kt
@@ -16,6 +16,7 @@
package io.element.android.libraries.pushproviders.unifiedpush
+import io.element.android.libraries.core.extensions.flatMap
import io.element.android.libraries.core.log.logger.LoggerTag
import io.element.android.libraries.matrix.api.auth.MatrixAuthenticationService
import io.element.android.libraries.pushproviders.api.PusherSubscriber
@@ -27,7 +28,7 @@ import javax.inject.Inject
private val loggerTag = LoggerTag("UnifiedPushNewGatewayHandler", LoggerTag.PushLoggerTag)
/**
- * Handle new endpoint received from UnifiedPush. Will update all the sessions which are using UnifiedPush as a push provider.
+ * Handle new endpoint received from UnifiedPush. Will update the session matching the client secret.
*/
class UnifiedPushNewGatewayHandler @Inject constructor(
private val pusherSubscriber: PusherSubscriber,
@@ -35,18 +36,25 @@ class UnifiedPushNewGatewayHandler @Inject constructor(
private val pushClientSecret: PushClientSecret,
private val matrixAuthenticationService: MatrixAuthenticationService,
) {
- suspend fun handle(endpoint: String, pushGateway: String, clientSecret: String) {
+ suspend fun handle(endpoint: String, pushGateway: String, clientSecret: String): Result {
// Register the pusher for the session with this client secret, if is it using UnifiedPush.
- val userId = pushClientSecret.getUserIdFromSecret(clientSecret) ?: return Unit.also {
+ val userId = pushClientSecret.getUserIdFromSecret(clientSecret) ?: return Result.failure(
+ IllegalStateException("Unable to retrieve session")
+ ).also {
Timber.w("Unable to retrieve session")
}
val userDataStore = userPushStoreFactory.getOrCreate(userId)
- if (userDataStore.getPushProviderName() == UnifiedPushConfig.NAME) {
- matrixAuthenticationService.restoreSession(userId).getOrNull()?.use { client ->
- pusherSubscriber.registerPusher(client, endpoint, pushGateway)
- }
+ return if (userDataStore.getPushProviderName() == UnifiedPushConfig.NAME) {
+ matrixAuthenticationService
+ .restoreSession(userId)
+ .flatMap { client ->
+ pusherSubscriber.registerPusher(client, endpoint, pushGateway)
+ }
} else {
Timber.tag(loggerTag.value).d("This session is not using UnifiedPush pusher")
+ Result.failure(
+ IllegalStateException("This session is not using UnifiedPush pusher")
+ )
}
}
}
diff --git a/libraries/pushproviders/unifiedpush/src/main/kotlin/io/element/android/libraries/pushproviders/unifiedpush/UnifiedPushProvider.kt b/libraries/pushproviders/unifiedpush/src/main/kotlin/io/element/android/libraries/pushproviders/unifiedpush/UnifiedPushProvider.kt
index e7ea1841c5..4530a4667f 100644
--- a/libraries/pushproviders/unifiedpush/src/main/kotlin/io/element/android/libraries/pushproviders/unifiedpush/UnifiedPushProvider.kt
+++ b/libraries/pushproviders/unifiedpush/src/main/kotlin/io/element/android/libraries/pushproviders/unifiedpush/UnifiedPushProvider.kt
@@ -58,14 +58,22 @@ class UnifiedPushProvider @Inject constructor(
return unifiedPushDistributorProvider.getDistributors()
}
- override suspend fun registerWith(matrixClient: MatrixClient, distributor: Distributor) {
+ override suspend fun registerWith(matrixClient: MatrixClient, distributor: Distributor): Result {
val clientSecret = pushClientSecret.getSecretForUser(matrixClient.sessionId)
- registerUnifiedPushUseCase.execute(matrixClient, distributor, clientSecret)
+ return registerUnifiedPushUseCase.execute(distributor, clientSecret)
+ .onSuccess {
+ unifiedPushStore.setDistributorValue(matrixClient.sessionId, distributor.value)
+ }
}
- override suspend fun unregister(matrixClient: MatrixClient) {
+ override suspend fun getCurrentDistributor(matrixClient: MatrixClient): Distributor? {
+ val distributorValue = unifiedPushStore.getDistributorValue(matrixClient.sessionId)
+ return getDistributors().find { it.value == distributorValue }
+ }
+
+ override suspend fun unregister(matrixClient: MatrixClient): Result {
val clientSecret = pushClientSecret.getSecretForUser(matrixClient.sessionId)
- unRegisterUnifiedPushUseCase.execute(clientSecret)
+ return unRegisterUnifiedPushUseCase.execute(matrixClient, clientSecret)
}
override suspend fun getCurrentUserPushConfig(): CurrentUserPushConfig? {
diff --git a/libraries/pushproviders/unifiedpush/src/main/kotlin/io/element/android/libraries/pushproviders/unifiedpush/UnifiedPushStore.kt b/libraries/pushproviders/unifiedpush/src/main/kotlin/io/element/android/libraries/pushproviders/unifiedpush/UnifiedPushStore.kt
index d063dfce3e..7b6ee5ef37 100644
--- a/libraries/pushproviders/unifiedpush/src/main/kotlin/io/element/android/libraries/pushproviders/unifiedpush/UnifiedPushStore.kt
+++ b/libraries/pushproviders/unifiedpush/src/main/kotlin/io/element/android/libraries/pushproviders/unifiedpush/UnifiedPushStore.kt
@@ -21,6 +21,7 @@ import android.content.SharedPreferences
import androidx.core.content.edit
import io.element.android.libraries.di.ApplicationContext
import io.element.android.libraries.di.DefaultPreferences
+import io.element.android.libraries.matrix.api.core.UserId
import javax.inject.Inject
class UnifiedPushStore @Inject constructor(
@@ -71,8 +72,19 @@ class UnifiedPushStore @Inject constructor(
}
}
+ fun getDistributorValue(userId: UserId): String? {
+ return defaultPrefs.getString(PREFS_DISTRIBUTOR + userId, null)
+ }
+
+ fun setDistributorValue(userId: UserId, value: String) {
+ defaultPrefs.edit {
+ putString(PREFS_DISTRIBUTOR + userId, value)
+ }
+ }
+
companion object {
private const val PREFS_ENDPOINT_OR_TOKEN = "UP_ENDPOINT_OR_TOKEN"
private const val PREFS_PUSH_GATEWAY = "PUSH_GATEWAY"
+ private const val PREFS_DISTRIBUTOR = "DISTRIBUTOR"
}
}
diff --git a/libraries/pushproviders/unifiedpush/src/main/kotlin/io/element/android/libraries/pushproviders/unifiedpush/UnregisterUnifiedPushUseCase.kt b/libraries/pushproviders/unifiedpush/src/main/kotlin/io/element/android/libraries/pushproviders/unifiedpush/UnregisterUnifiedPushUseCase.kt
index b6030564ca..b2dd33c252 100644
--- a/libraries/pushproviders/unifiedpush/src/main/kotlin/io/element/android/libraries/pushproviders/unifiedpush/UnregisterUnifiedPushUseCase.kt
+++ b/libraries/pushproviders/unifiedpush/src/main/kotlin/io/element/android/libraries/pushproviders/unifiedpush/UnregisterUnifiedPushUseCase.kt
@@ -18,29 +18,27 @@ package io.element.android.libraries.pushproviders.unifiedpush
import android.content.Context
import io.element.android.libraries.di.ApplicationContext
+import io.element.android.libraries.matrix.api.MatrixClient
+import io.element.android.libraries.pushproviders.api.PusherSubscriber
import org.unifiedpush.android.connector.UnifiedPush
-import timber.log.Timber
import javax.inject.Inject
class UnregisterUnifiedPushUseCase @Inject constructor(
@ApplicationContext private val context: Context,
- // private val pushDataStore: PushDataStore,
private val unifiedPushStore: UnifiedPushStore,
- // private val unifiedPushGatewayResolver: UnifiedPushGatewayResolver,
+ private val pusherSubscriber: PusherSubscriber,
) {
- suspend fun execute(clientSecret: String) {
- // val mode = BackgroundSyncMode.FDROID_BACKGROUND_SYNC_MODE_FOR_REALTIME
- // pushDataStore.setFdroidSyncBackgroundMode(mode)
- try {
- unifiedPushStore.getEndpoint(clientSecret)?.let {
- Timber.d("Removing $it")
- // TODO pushersManager?.unregisterPusher(it)
- }
- } catch (e: Exception) {
- Timber.d(e, "Probably unregistering a non existing pusher")
+ suspend fun execute(matrixClient: MatrixClient, clientSecret: String): Result {
+ val endpoint = unifiedPushStore.getEndpoint(clientSecret)
+ val gateway = unifiedPushStore.getPushGateway(clientSecret)
+ if (endpoint == null || gateway == null) {
+ return Result.failure(IllegalStateException("No endpoint or gateway found for client secret"))
}
- unifiedPushStore.storeUpEndpoint(null, clientSecret)
- unifiedPushStore.storePushGateway(null, clientSecret)
- UnifiedPush.unregisterApp(context)
+ return pusherSubscriber.unregisterPusher(matrixClient, endpoint, gateway)
+ .onSuccess {
+ unifiedPushStore.storeUpEndpoint(null, clientSecret)
+ unifiedPushStore.storePushGateway(null, clientSecret)
+ UnifiedPush.unregisterApp(context)
+ }
}
}
diff --git a/libraries/pushproviders/unifiedpush/src/main/kotlin/io/element/android/libraries/pushproviders/unifiedpush/VectorUnifiedPushMessagingReceiver.kt b/libraries/pushproviders/unifiedpush/src/main/kotlin/io/element/android/libraries/pushproviders/unifiedpush/VectorUnifiedPushMessagingReceiver.kt
index e28d67ecf7..c47aabae37 100644
--- a/libraries/pushproviders/unifiedpush/src/main/kotlin/io/element/android/libraries/pushproviders/unifiedpush/VectorUnifiedPushMessagingReceiver.kt
+++ b/libraries/pushproviders/unifiedpush/src/main/kotlin/io/element/android/libraries/pushproviders/unifiedpush/VectorUnifiedPushMessagingReceiver.kt
@@ -21,6 +21,8 @@ import android.content.Intent
import io.element.android.libraries.architecture.bindings
import io.element.android.libraries.core.log.logger.LoggerTag
import io.element.android.libraries.pushproviders.api.PushHandler
+import io.element.android.libraries.pushproviders.unifiedpush.registration.EndpointRegistrationHandler
+import io.element.android.libraries.pushproviders.unifiedpush.registration.RegistrationResult
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.SupervisorJob
import kotlinx.coroutines.launch
@@ -37,6 +39,7 @@ class VectorUnifiedPushMessagingReceiver : MessagingReceiver() {
@Inject lateinit var unifiedPushStore: UnifiedPushStore
@Inject lateinit var unifiedPushGatewayResolver: UnifiedPushGatewayResolver
@Inject lateinit var newGatewayHandler: UnifiedPushNewGatewayHandler
+ @Inject lateinit var endpointRegistrationHandler: EndpointRegistrationHandler
private val coroutineScope = CoroutineScope(SupervisorJob())
@@ -69,20 +72,33 @@ class VectorUnifiedPushMessagingReceiver : MessagingReceiver() {
* You should send the endpoint to your application server and sync for missing notifications.
*/
override fun onNewEndpoint(context: Context, endpoint: String, instance: String) {
- Timber.tag(loggerTag.value).i("onNewEndpoint: adding $endpoint")
- // If the endpoint has changed
- // or the gateway has changed
- if (unifiedPushStore.getEndpoint(instance) != endpoint) {
- unifiedPushStore.storeUpEndpoint(endpoint, instance)
- coroutineScope.launch {
- val gateway = unifiedPushGatewayResolver.getGateway(endpoint)
- unifiedPushStore.storePushGateway(gateway, instance)
- gateway?.let { pushGateway ->
- newGatewayHandler.handle(endpoint, pushGateway, instance)
- }
+ Timber.tag(loggerTag.value).i("onNewEndpoint: $endpoint")
+ coroutineScope.launch {
+ val gateway = unifiedPushGatewayResolver.getGateway(endpoint)
+ unifiedPushStore.storePushGateway(gateway, instance)
+ if (gateway == null) {
+ Timber.tag(loggerTag.value).w("No gateway found for endpoint $endpoint")
+ endpointRegistrationHandler.registrationDone(
+ RegistrationResult(
+ clientSecret = instance,
+ result = Result.failure(IllegalStateException("No gateway found for endpoint $endpoint")),
+ )
+ )
+ } else {
+ val result = newGatewayHandler.handle(endpoint, gateway, instance)
+ .onFailure {
+ Timber.tag(loggerTag.value).e(it, "Failed to handle new gateway")
+ }
+ .onSuccess {
+ unifiedPushStore.storeUpEndpoint(endpoint, instance)
+ }
+ endpointRegistrationHandler.registrationDone(
+ RegistrationResult(
+ clientSecret = instance,
+ result = result,
+ )
+ )
}
- } else {
- Timber.tag(loggerTag.value).i("onNewEndpoint: skipped")
}
guardServiceStarter.stop()
}
diff --git a/libraries/pushproviders/unifiedpush/src/main/kotlin/io/element/android/libraries/pushproviders/unifiedpush/registration/EndpointRegistrationHandler.kt b/libraries/pushproviders/unifiedpush/src/main/kotlin/io/element/android/libraries/pushproviders/unifiedpush/registration/EndpointRegistrationHandler.kt
new file mode 100644
index 0000000000..504ae51916
--- /dev/null
+++ b/libraries/pushproviders/unifiedpush/src/main/kotlin/io/element/android/libraries/pushproviders/unifiedpush/registration/EndpointRegistrationHandler.kt
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2024 New Vector Ltd
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package io.element.android.libraries.pushproviders.unifiedpush.registration
+
+import io.element.android.libraries.di.AppScope
+import io.element.android.libraries.di.SingleIn
+import kotlinx.coroutines.flow.MutableSharedFlow
+import kotlinx.coroutines.flow.SharedFlow
+import javax.inject.Inject
+
+data class RegistrationResult(
+ val clientSecret: String,
+ val result: Result,
+)
+
+@SingleIn(AppScope::class)
+class EndpointRegistrationHandler @Inject constructor() {
+ private val _state = MutableSharedFlow()
+ val state: SharedFlow = _state
+
+ suspend fun registrationDone(result: RegistrationResult) {
+ _state.emit(result)
+ }
+}
diff --git a/libraries/pushproviders/unifiedpush/src/main/res/values-it/translations.xml b/libraries/pushproviders/unifiedpush/src/main/res/values-it/translations.xml
index a2ec4fa24a..a92663fd24 100644
--- a/libraries/pushproviders/unifiedpush/src/main/res/values-it/translations.xml
+++ b/libraries/pushproviders/unifiedpush/src/main/res/values-it/translations.xml
@@ -1,4 +1,10 @@
+ "Assicurati che i distributori UnifiedPush siano disponibili."
+ "Nessun distributore di notifiche push trovato."
+
+ - "%1$d distributore trovato: %2$s."
+ - "%1$d distributori trovati: %2$s."
+
"Controlla UnifiedPush"
diff --git a/libraries/pushproviders/unifiedpush/src/main/res/values-pt/translations.xml b/libraries/pushproviders/unifiedpush/src/main/res/values-pt/translations.xml
new file mode 100644
index 0000000000..8fec0ef977
--- /dev/null
+++ b/libraries/pushproviders/unifiedpush/src/main/res/values-pt/translations.xml
@@ -0,0 +1,10 @@
+
+
+ "Certifica que os distribuidores UnifiedPush estão disponíveis."
+ "Nenhum distribuidor encontrado."
+
+ - "%1$d distribuidor encontrado: %2$s."
+ - "%1$d distribuidores encontrados: %2$s."
+
+ "Verificar UnifiedPush"
+
diff --git a/libraries/pushproviders/unifiedpush/src/main/res/values-ro/translations.xml b/libraries/pushproviders/unifiedpush/src/main/res/values-ro/translations.xml
new file mode 100644
index 0000000000..fa96a07474
--- /dev/null
+++ b/libraries/pushproviders/unifiedpush/src/main/res/values-ro/translations.xml
@@ -0,0 +1,11 @@
+
+
+ "Asigurați-vă că distribuitorii UnifiedPush sunt disponibili."
+ "Nu au fost găsiți distribuitori push."
+
+ - "%1$d distribuitor găsit: %2$s."
+ - "%1$d distribuitori găsiți: %2$s."
+ - "%1$d distribuitori găsiți: %2$s."
+
+ "Verificați UnifiedPush"
+
diff --git a/libraries/pushproviders/unifiedpush/src/main/res/values-zh/translations.xml b/libraries/pushproviders/unifiedpush/src/main/res/values-zh/translations.xml
new file mode 100644
index 0000000000..2fac432ca8
--- /dev/null
+++ b/libraries/pushproviders/unifiedpush/src/main/res/values-zh/translations.xml
@@ -0,0 +1,9 @@
+
+
+ "确保 UnifiedPush distributor 可用。"
+ "未找到推送 distributor。"
+
+ - "找到 %1$d 个 distributors:%2$s"
+
+ "检查 UnifiedPush"
+
diff --git a/libraries/pushstore/api/src/main/kotlin/io/element/android/libraries/pushstore/api/UserPushStore.kt b/libraries/pushstore/api/src/main/kotlin/io/element/android/libraries/pushstore/api/UserPushStore.kt
index fcfd6475c3..d24cc5ff5e 100644
--- a/libraries/pushstore/api/src/main/kotlin/io/element/android/libraries/pushstore/api/UserPushStore.kt
+++ b/libraries/pushstore/api/src/main/kotlin/io/element/android/libraries/pushstore/api/UserPushStore.kt
@@ -24,7 +24,7 @@ interface UserPushStore {
suspend fun getPushProviderName(): String?
suspend fun setPushProviderName(value: String)
suspend fun getCurrentRegisteredPushKey(): String?
- suspend fun setCurrentRegisteredPushKey(value: String)
+ suspend fun setCurrentRegisteredPushKey(value: String?)
fun getNotificationEnabledForDevice(): Flow
suspend fun setNotificationEnabledForDevice(enabled: Boolean)
diff --git a/libraries/pushstore/impl/src/main/kotlin/io/element/android/libraries/pushstore/impl/UserPushStoreDataStore.kt b/libraries/pushstore/impl/src/main/kotlin/io/element/android/libraries/pushstore/impl/UserPushStoreDataStore.kt
index f7a159f6c3..cfcc9e3da4 100644
--- a/libraries/pushstore/impl/src/main/kotlin/io/element/android/libraries/pushstore/impl/UserPushStoreDataStore.kt
+++ b/libraries/pushstore/impl/src/main/kotlin/io/element/android/libraries/pushstore/impl/UserPushStoreDataStore.kt
@@ -76,9 +76,13 @@ class UserPushStoreDataStore(
return context.dataStore.data.first()[currentPushKey]
}
- override suspend fun setCurrentRegisteredPushKey(value: String) {
+ override suspend fun setCurrentRegisteredPushKey(value: String?) {
context.dataStore.edit {
- it[currentPushKey] = value
+ if (value == null) {
+ it.remove(currentPushKey)
+ } else {
+ it[currentPushKey] = value
+ }
}
}
diff --git a/libraries/pushstore/test/src/main/kotlin/com/element/android/libraries/pushstore/test/userpushstore/FakeUserPushStore.kt b/libraries/pushstore/test/src/main/kotlin/com/element/android/libraries/pushstore/test/userpushstore/FakeUserPushStore.kt
index 2afbf3210e..3428fb5d3e 100644
--- a/libraries/pushstore/test/src/main/kotlin/com/element/android/libraries/pushstore/test/userpushstore/FakeUserPushStore.kt
+++ b/libraries/pushstore/test/src/main/kotlin/com/element/android/libraries/pushstore/test/userpushstore/FakeUserPushStore.kt
@@ -36,7 +36,7 @@ class FakeUserPushStore : UserPushStore {
return currentRegisteredPushKey
}
- override suspend fun setCurrentRegisteredPushKey(value: String) {
+ override suspend fun setCurrentRegisteredPushKey(value: String?) {
currentRegisteredPushKey = value
}
diff --git a/libraries/session-storage/impl/src/main/kotlin/io/element/android/libraries/sessionstorage/impl/di/SessionStorageModule.kt b/libraries/session-storage/impl/src/main/kotlin/io/element/android/libraries/sessionstorage/impl/di/SessionStorageModule.kt
index 052943388e..8d22dcfa61 100644
--- a/libraries/session-storage/impl/src/main/kotlin/io/element/android/libraries/sessionstorage/impl/di/SessionStorageModule.kt
+++ b/libraries/session-storage/impl/src/main/kotlin/io/element/android/libraries/sessionstorage/impl/di/SessionStorageModule.kt
@@ -35,6 +35,13 @@ object SessionStorageModule {
fun provideMatrixDatabase(@ApplicationContext context: Context): SessionDatabase {
val name = "session_database"
val secretFile = context.getDatabasePath("$name.key")
+
+ // Make sure the parent directory of the key file exists, otherwise it will crash in older Android versions
+ val parentDir = secretFile.parentFile
+ if (parentDir != null && !parentDir.exists()) {
+ parentDir.mkdirs()
+ }
+
val passphraseProvider = RandomSecretPassphraseProvider(context, secretFile)
val driver = SqlCipherDriverFactory(passphraseProvider)
.create(SessionDatabase.Schema, "$name.db", context)
diff --git a/libraries/testtags/src/main/kotlin/io/element/android/libraries/testtags/TestTags.kt b/libraries/testtags/src/main/kotlin/io/element/android/libraries/testtags/TestTags.kt
index 3046ba3372..3bad8f648d 100644
--- a/libraries/testtags/src/main/kotlin/io/element/android/libraries/testtags/TestTags.kt
+++ b/libraries/testtags/src/main/kotlin/io/element/android/libraries/testtags/TestTags.kt
@@ -64,15 +64,25 @@ object TestTags {
*/
val memberDetailAvatar = TestTag("member_detail-avatar")
+ /**
+ * Edit avatar.
+ */
+ val editAvatar = TestTag("edit-avatar")
+
/**
* Welcome screen.
*/
val welcomeScreenTitle = TestTag("welcome_screen-title")
/**
- * RichTextEditor.
+ * TextEditor.
*/
- val richTextEditor = TestTag("rich_text_editor")
+ val textEditor = TestTag("text_editor")
+
+ /**
+ * EditText inside the MarkdownTextInput.
+ */
+ val plainTextEditor = TestTag("plain_text_editor")
/**
* Message bubble.
diff --git a/libraries/textcomposer/impl/build.gradle.kts b/libraries/textcomposer/impl/build.gradle.kts
index 0bbb508b3c..21fd124765 100644
--- a/libraries/textcomposer/impl/build.gradle.kts
+++ b/libraries/textcomposer/impl/build.gradle.kts
@@ -22,6 +22,9 @@ plugins {
android {
namespace = "io.element.android.libraries.textcomposer"
+ testOptions {
+ unitTests.isIncludeAndroidResources = true
+ }
}
dependencies {
@@ -47,9 +50,13 @@ dependencies {
ksp(libs.showkase.processor)
testImplementation(libs.test.junit)
- testImplementation(libs.test.truth)
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/libraries/textcomposer/impl/src/main/kotlin/io/element/android/libraries/textcomposer/ComposerModeView.kt b/libraries/textcomposer/impl/src/main/kotlin/io/element/android/libraries/textcomposer/ComposerModeView.kt
new file mode 100644
index 0000000000..c50c81fb87
--- /dev/null
+++ b/libraries/textcomposer/impl/src/main/kotlin/io/element/android/libraries/textcomposer/ComposerModeView.kt
@@ -0,0 +1,184 @@
+/*
+ * Copyright (c) 2024 New Vector Ltd
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package io.element.android.libraries.textcomposer
+
+import androidx.compose.foundation.background
+import androidx.compose.foundation.clickable
+import androidx.compose.foundation.interaction.MutableInteractionSource
+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.fillMaxWidth
+import androidx.compose.foundation.layout.padding
+import androidx.compose.foundation.layout.size
+import androidx.compose.foundation.layout.width
+import androidx.compose.foundation.shape.RoundedCornerShape
+import androidx.compose.material.ripple.rememberRipple
+import androidx.compose.material3.MaterialTheme
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.remember
+import androidx.compose.ui.Alignment
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.draw.clip
+import androidx.compose.ui.draw.clipToBounds
+import androidx.compose.ui.res.stringResource
+import androidx.compose.ui.text.style.TextAlign
+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.libraries.designsystem.theme.components.Icon
+import io.element.android.libraries.designsystem.theme.components.Text
+import io.element.android.libraries.matrix.ui.components.AttachmentThumbnail
+import io.element.android.libraries.matrix.ui.components.AttachmentThumbnailInfo
+import io.element.android.libraries.textcomposer.model.MessageComposerMode
+import io.element.android.libraries.ui.strings.CommonStrings
+
+@Composable
+internal fun ComposerModeView(
+ composerMode: MessageComposerMode,
+ onResetComposerMode: () -> Unit,
+) {
+ when (composerMode) {
+ is MessageComposerMode.Edit -> {
+ EditingModeView(onResetComposerMode = onResetComposerMode)
+ }
+ is MessageComposerMode.Reply -> {
+ ReplyToModeView(
+ modifier = Modifier.padding(8.dp),
+ senderName = composerMode.senderName,
+ text = composerMode.defaultContent,
+ attachmentThumbnailInfo = composerMode.attachmentThumbnailInfo,
+ onResetComposerMode = onResetComposerMode,
+ )
+ }
+ else -> Unit
+ }
+}
+
+@Composable
+private fun EditingModeView(
+ onResetComposerMode: () -> Unit,
+) {
+ Row(
+ horizontalArrangement = Arrangement.spacedBy(4.dp),
+ verticalAlignment = Alignment.CenterVertically,
+ modifier = Modifier
+ .fillMaxWidth()
+ .padding(start = 12.dp)
+ ) {
+ Icon(
+ imageVector = CompoundIcons.Edit(),
+ contentDescription = stringResource(CommonStrings.common_editing),
+ tint = ElementTheme.materialColors.secondary,
+ modifier = Modifier
+ .padding(vertical = 8.dp)
+ .size(16.dp),
+ )
+ Text(
+ stringResource(CommonStrings.common_editing),
+ style = ElementTheme.typography.fontBodySmRegular,
+ textAlign = TextAlign.Start,
+ color = ElementTheme.materialColors.secondary,
+ modifier = Modifier
+ .padding(vertical = 8.dp)
+ .weight(1f)
+ )
+ Icon(
+ imageVector = CompoundIcons.Close(),
+ contentDescription = stringResource(CommonStrings.action_close),
+ tint = ElementTheme.materialColors.secondary,
+ modifier = Modifier
+ .padding(top = 8.dp, bottom = 8.dp, start = 16.dp, end = 12.dp)
+ .size(16.dp)
+ .clickable(
+ enabled = true,
+ onClick = onResetComposerMode,
+ interactionSource = remember { MutableInteractionSource() },
+ indication = rememberRipple(bounded = false)
+ ),
+ )
+ }
+}
+
+@Composable
+private fun ReplyToModeView(
+ senderName: String,
+ text: String?,
+ attachmentThumbnailInfo: AttachmentThumbnailInfo?,
+ onResetComposerMode: () -> Unit,
+ modifier: Modifier = Modifier,
+) {
+ Row(
+ modifier
+ .clip(RoundedCornerShape(13.dp))
+ .background(MaterialTheme.colorScheme.surface)
+ .padding(4.dp)
+ ) {
+ if (attachmentThumbnailInfo != null) {
+ AttachmentThumbnail(
+ info = attachmentThumbnailInfo,
+ backgroundColor = MaterialTheme.colorScheme.surfaceVariant,
+ modifier = Modifier
+ .size(36.dp)
+ .clip(RoundedCornerShape(9.dp))
+ )
+ }
+ Spacer(modifier = Modifier.width(8.dp))
+ Column(
+ modifier = Modifier
+ .weight(1f)
+ .align(Alignment.CenterVertically)
+ ) {
+ Text(
+ text = senderName,
+ modifier = Modifier
+ .fillMaxWidth()
+ .clipToBounds(),
+ maxLines = 1,
+ overflow = TextOverflow.Ellipsis,
+ style = ElementTheme.typography.fontBodySmMedium,
+ textAlign = TextAlign.Start,
+ color = ElementTheme.materialColors.primary,
+ )
+ Text(
+ modifier = Modifier.fillMaxWidth(),
+ text = text.orEmpty(),
+ style = ElementTheme.typography.fontBodyMdRegular,
+ textAlign = TextAlign.Start,
+ color = ElementTheme.materialColors.secondary,
+ maxLines = if (attachmentThumbnailInfo != null) 1 else 2,
+ overflow = TextOverflow.Ellipsis,
+ )
+ }
+ Icon(
+ imageVector = CompoundIcons.Close(),
+ contentDescription = stringResource(CommonStrings.action_close),
+ tint = MaterialTheme.colorScheme.secondary,
+ modifier = Modifier
+ .padding(end = 4.dp, top = 4.dp, start = 16.dp, bottom = 16.dp)
+ .size(16.dp)
+ .clickable(
+ enabled = true,
+ onClick = onResetComposerMode,
+ interactionSource = remember { MutableInteractionSource() },
+ indication = rememberRipple(bounded = false)
+ ),
+ )
+ }
+}
diff --git a/libraries/textcomposer/impl/src/main/kotlin/io/element/android/libraries/textcomposer/TextComposer.kt b/libraries/textcomposer/impl/src/main/kotlin/io/element/android/libraries/textcomposer/TextComposer.kt
index e31183bd14..3ff2520c35 100644
--- a/libraries/textcomposer/impl/src/main/kotlin/io/element/android/libraries/textcomposer/TextComposer.kt
+++ b/libraries/textcomposer/impl/src/main/kotlin/io/element/android/libraries/textcomposer/TextComposer.kt
@@ -19,8 +19,6 @@ package io.element.android.libraries.textcomposer
import android.net.Uri
import androidx.compose.foundation.background
import androidx.compose.foundation.border
-import androidx.compose.foundation.clickable
-import androidx.compose.foundation.interaction.MutableInteractionSource
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
@@ -34,30 +32,22 @@ import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.requiredHeightIn
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.layout.width
-import androidx.compose.foundation.shape.RoundedCornerShape
-import androidx.compose.material.ripple.rememberRipple
-import androidx.compose.material3.MaterialTheme
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
-import androidx.compose.runtime.derivedStateOf
import androidx.compose.runtime.getValue
import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberUpdatedState
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
-import androidx.compose.ui.draw.clipToBounds
import androidx.compose.ui.res.stringResource
-import androidx.compose.ui.text.style.TextAlign
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.libraries.designsystem.components.media.createFakeWaveform
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.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.TransactionId
@@ -66,7 +56,6 @@ import io.element.android.libraries.matrix.api.media.MediaSource
import io.element.android.libraries.matrix.api.permalink.PermalinkData
import io.element.android.libraries.matrix.api.permalink.PermalinkParser
import io.element.android.libraries.matrix.ui.components.A_BLUR_HASH
-import io.element.android.libraries.matrix.ui.components.AttachmentThumbnail
import io.element.android.libraries.matrix.ui.components.AttachmentThumbnailInfo
import io.element.android.libraries.matrix.ui.components.AttachmentThumbnailType
import io.element.android.libraries.testtags.TestTags
@@ -79,11 +68,13 @@ import io.element.android.libraries.textcomposer.components.VoiceMessageDeleteBu
import io.element.android.libraries.textcomposer.components.VoiceMessagePreview
import io.element.android.libraries.textcomposer.components.VoiceMessageRecorderButton
import io.element.android.libraries.textcomposer.components.VoiceMessageRecording
+import io.element.android.libraries.textcomposer.components.markdown.MarkdownTextInput
+import io.element.android.libraries.textcomposer.components.markdown.aMarkdownTextEditorState
import io.element.android.libraries.textcomposer.components.textInputRoundedCornerShape
import io.element.android.libraries.textcomposer.mentions.rememberMentionSpanProvider
-import io.element.android.libraries.textcomposer.model.Message
import io.element.android.libraries.textcomposer.model.MessageComposerMode
import io.element.android.libraries.textcomposer.model.Suggestion
+import io.element.android.libraries.textcomposer.model.TextEditorState
import io.element.android.libraries.textcomposer.model.VoiceMessagePlayerEvent
import io.element.android.libraries.textcomposer.model.VoiceMessageRecorderEvent
import io.element.android.libraries.textcomposer.model.VoiceMessageState
@@ -98,15 +89,14 @@ import kotlin.time.Duration.Companion.seconds
@Composable
fun TextComposer(
- state: RichTextEditorState,
+ state: TextEditorState,
voiceMessageState: VoiceMessageState,
permalinkParser: PermalinkParser,
composerMode: MessageComposerMode,
- enableTextFormatting: Boolean,
enableVoiceMessages: Boolean,
currentUserId: UserId,
onRequestFocus: () -> Unit,
- onSendMessage: (Message) -> Unit,
+ onSendMessage: () -> Unit,
onResetComposerMode: () -> Unit,
onAddAttachment: () -> Unit,
onDismissTextFormatting: () -> Unit,
@@ -122,9 +112,12 @@ fun TextComposer(
showTextFormatting: Boolean = false,
subcomposing: Boolean = false,
) {
+ val markdown = when (state) {
+ is TextEditorState.Markdown -> state.state.text.value()
+ is TextEditorState.Rich -> state.richTextEditorState.messageMarkdown
+ }
val onSendClicked = {
- val html = if (enableTextFormatting) state.messageHtml else null
- onSendMessage(Message(html = html, markdown = state.messageMarkdown))
+ onSendMessage()
}
val onPlayVoiceMessageClicked = {
@@ -153,32 +146,57 @@ fun TextComposer(
}
}
- val textInput: @Composable () -> Unit = remember(state, subcomposing, composerMode, onResetComposerMode, onError) {
- @Composable {
- val mentionSpanProvider = rememberMentionSpanProvider(
- currentUserId = currentUserId,
- permalinkParser = permalinkParser,
- )
- TextInput(
- state = state,
- subcomposing = subcomposing,
- placeholder = if (composerMode.inThread) {
- stringResource(id = CommonStrings.action_reply_in_thread)
- } else {
- stringResource(id = R.string.rich_text_editor_composer_placeholder)
- },
- composerMode = composerMode,
- onResetComposerMode = onResetComposerMode,
- resolveMentionDisplay = { text, url -> TextDisplay.Custom(mentionSpanProvider.getMentionSpanFor(text, url)) },
- resolveRoomMentionDisplay = { TextDisplay.Custom(mentionSpanProvider.getMentionSpanFor("@room", "#")) },
- onError = onError,
- onTyping = onTyping,
- onRichContentSelected = onRichContentSelected,
- )
+ val placeholder = if (composerMode.inThread) {
+ stringResource(id = CommonStrings.action_reply_in_thread)
+ } else {
+ stringResource(id = R.string.rich_text_editor_composer_placeholder)
+ }
+ val textInput: @Composable () -> Unit = when (state) {
+ is TextEditorState.Rich -> {
+ remember(state.richTextEditorState, subcomposing, composerMode, onResetComposerMode, onError) {
+ @Composable {
+ val mentionSpanProvider = rememberMentionSpanProvider(
+ currentUserId = currentUserId,
+ permalinkParser = permalinkParser,
+ )
+ TextInput(
+ state = state.richTextEditorState,
+ subcomposing = subcomposing,
+ placeholder = placeholder,
+ composerMode = composerMode,
+ onResetComposerMode = onResetComposerMode,
+ resolveMentionDisplay = { text, url -> TextDisplay.Custom(mentionSpanProvider.getMentionSpanFor(text, url)) },
+ resolveRoomMentionDisplay = { TextDisplay.Custom(mentionSpanProvider.getMentionSpanFor("@room", "#")) },
+ onError = onError,
+ onTyping = onTyping,
+ onRichContentSelected = onRichContentSelected,
+ )
+ }
+ }
+ }
+ is TextEditorState.Markdown -> {
+ @Composable {
+ val style = ElementRichTextEditorStyle.composerStyle(hasFocus = state.hasFocus())
+ TextInputBox(
+ composerMode = composerMode,
+ onResetComposerMode = onResetComposerMode,
+ placeholder = placeholder,
+ showPlaceholder = { state.state.text.value().isEmpty() },
+ subcomposing = subcomposing,
+ ) {
+ MarkdownTextInput(
+ state = state.state,
+ subcomposing = subcomposing,
+ onTyping = onTyping,
+ onSuggestionReceived = onSuggestionReceived,
+ richTextEditorStyle = style,
+ )
+ }
+ }
}
}
- val canSendMessage by remember { derivedStateOf { state.messageMarkdown.isNotBlank() } }
+ val canSendMessage = markdown.isNotBlank()
val sendButton = @Composable {
SendButton(
canSendMessage = canSendMessage,
@@ -205,7 +223,9 @@ fun TextComposer(
)
}
- val textFormattingOptions = @Composable { TextFormatting(state = state) }
+ val textFormattingOptions: @Composable (() -> Unit)? = (state as? TextEditorState.Rich)?.let {
+ @Composable { TextFormatting(state = it.richTextEditorState) }
+ }
val sendOrRecordButton = when {
enableVoiceMessages && !canSendMessage ->
@@ -217,8 +237,7 @@ fun TextComposer(
false -> sendVoiceButton
}
}
- else ->
- sendButton
+ else -> sendButton
}
val voiceRecording = @Composable {
@@ -251,7 +270,7 @@ fun TextComposer(
}
}
- if (showTextFormatting) {
+ if (showTextFormatting && textFormattingOptions != null) {
TextFormattingLayout(
modifier = layoutModifier,
textInput = textInput,
@@ -282,14 +301,16 @@ fun TextComposer(
SoftKeyboardEffect(showTextFormatting, onRequestFocus) { it }
}
- val menuAction = state.menuAction
val latestOnSuggestionReceived by rememberUpdatedState(onSuggestionReceived)
- LaunchedEffect(menuAction) {
- if (menuAction is MenuAction.Suggestion) {
- val suggestion = Suggestion(menuAction.suggestionPattern)
- latestOnSuggestionReceived(suggestion)
- } else {
- latestOnSuggestionReceived(null)
+ if (state is TextEditorState.Rich) {
+ val menuAction = state.richTextEditorState.menuAction
+ LaunchedEffect(menuAction) {
+ if (menuAction is MenuAction.Suggestion) {
+ val suggestion = Suggestion(menuAction.suggestionPattern)
+ latestOnSuggestionReceived(suggestion)
+ } else {
+ latestOnSuggestionReceived(null)
+ }
}
}
}
@@ -400,17 +421,13 @@ private fun TextFormattingLayout(
}
@Composable
-private fun TextInput(
- state: RichTextEditorState,
- subcomposing: Boolean,
- placeholder: String,
+private fun TextInputBox(
composerMode: MessageComposerMode,
onResetComposerMode: () -> Unit,
- resolveRoomMentionDisplay: () -> TextDisplay,
- resolveMentionDisplay: (text: String, url: String) -> TextDisplay,
- onError: (Throwable) -> Unit,
- onTyping: (Boolean) -> Unit,
- onRichContentSelected: ((Uri) -> Unit)?,
+ placeholder: String,
+ showPlaceholder: () -> Boolean,
+ subcomposing: Boolean,
+ textInput: @Composable () -> Unit,
) {
val bgColor = ElementTheme.colors.bgSubtleSecondary
val borderColor = ElementTheme.colors.borderDisabled
@@ -431,11 +448,12 @@ private fun TextInput(
Box(
modifier = Modifier
.padding(top = 4.dp, bottom = 4.dp, start = 12.dp, end = 42.dp)
- .testTag(TestTags.richTextEditor),
+ // Apply test tag only once, otherwise 2 nodes will have it (both the normal and subcomposing one) and tests will fail
+ .then(if (!subcomposing) Modifier.testTag(TestTags.textEditor) else Modifier),
contentAlignment = Alignment.CenterStart,
) {
// Placeholder
- if (state.messageHtml.isEmpty()) {
+ if (showPlaceholder()) {
Text(
placeholder,
style = defaultTypography.copy(
@@ -446,155 +464,45 @@ private fun TextInput(
)
}
- RichTextEditor(
- state = state,
- // Disable most of the editor functionality if it's just being measured for a subcomposition.
- // This prevents it gaining focus and mutating the state.
- registerStateUpdates = !subcomposing,
- modifier = Modifier
- .padding(top = 6.dp, bottom = 6.dp)
- .fillMaxWidth(),
- style = ElementRichTextEditorStyle.composerStyle(hasFocus = state.hasFocus),
- resolveMentionDisplay = resolveMentionDisplay,
- resolveRoomMentionDisplay = resolveRoomMentionDisplay,
- onError = onError,
- onRichContentSelected = onRichContentSelected,
- onTyping = onTyping,
- )
+ textInput()
}
}
}
@Composable
-private fun ComposerModeView(
+private fun TextInput(
+ state: RichTextEditorState,
+ subcomposing: Boolean,
+ placeholder: String,
composerMode: MessageComposerMode,
onResetComposerMode: () -> Unit,
+ resolveRoomMentionDisplay: () -> TextDisplay,
+ resolveMentionDisplay: (text: String, url: String) -> TextDisplay,
+ onError: (Throwable) -> Unit,
+ onTyping: (Boolean) -> Unit,
+ onRichContentSelected: ((Uri) -> Unit)?,
) {
- when (composerMode) {
- is MessageComposerMode.Edit -> {
- EditingModeView(onResetComposerMode = onResetComposerMode)
- }
- is MessageComposerMode.Reply -> {
- ReplyToModeView(
- modifier = Modifier.padding(8.dp),
- senderName = composerMode.senderName,
- text = composerMode.defaultContent,
- attachmentThumbnailInfo = composerMode.attachmentThumbnailInfo,
- onResetComposerMode = onResetComposerMode,
- )
- }
- else -> Unit
- }
-}
-
-@Composable
-private fun EditingModeView(
- onResetComposerMode: () -> Unit,
-) {
- Row(
- horizontalArrangement = Arrangement.spacedBy(4.dp),
- verticalAlignment = Alignment.CenterVertically,
- modifier = Modifier
- .fillMaxWidth()
- .padding(start = 12.dp)
+ TextInputBox(
+ composerMode = composerMode,
+ onResetComposerMode = onResetComposerMode,
+ placeholder = placeholder,
+ showPlaceholder = { state.messageHtml.isEmpty() },
+ subcomposing = subcomposing,
) {
- Icon(
- imageVector = CompoundIcons.Edit(),
- contentDescription = stringResource(CommonStrings.common_editing),
- tint = ElementTheme.materialColors.secondary,
+ RichTextEditor(
+ state = state,
+ // Disable most of the editor functionality if it's just being measured for a subcomposition.
+ // This prevents it gaining focus and mutating the state.
+ registerStateUpdates = !subcomposing,
modifier = Modifier
- .padding(vertical = 8.dp)
- .size(16.dp),
- )
- Text(
- stringResource(CommonStrings.common_editing),
- style = ElementTheme.typography.fontBodySmRegular,
- textAlign = TextAlign.Start,
- color = ElementTheme.materialColors.secondary,
- modifier = Modifier
- .padding(vertical = 8.dp)
- .weight(1f)
- )
- Icon(
- imageVector = CompoundIcons.Close(),
- contentDescription = stringResource(CommonStrings.action_close),
- tint = ElementTheme.materialColors.secondary,
- modifier = Modifier
- .padding(top = 8.dp, bottom = 8.dp, start = 16.dp, end = 12.dp)
- .size(16.dp)
- .clickable(
- enabled = true,
- onClick = onResetComposerMode,
- interactionSource = remember { MutableInteractionSource() },
- indication = rememberRipple(bounded = false)
- ),
- )
- }
-}
-
-@Composable
-private fun ReplyToModeView(
- senderName: String,
- text: String?,
- attachmentThumbnailInfo: AttachmentThumbnailInfo?,
- onResetComposerMode: () -> Unit,
- modifier: Modifier = Modifier,
-) {
- Row(
- modifier
- .clip(RoundedCornerShape(13.dp))
- .background(MaterialTheme.colorScheme.surface)
- .padding(4.dp)
- ) {
- if (attachmentThumbnailInfo != null) {
- AttachmentThumbnail(
- info = attachmentThumbnailInfo,
- backgroundColor = MaterialTheme.colorScheme.surfaceVariant,
- modifier = Modifier
- .size(36.dp)
- .clip(RoundedCornerShape(9.dp))
- )
- }
- Spacer(modifier = Modifier.width(8.dp))
- Column(
- modifier = Modifier
- .weight(1f)
- .align(Alignment.CenterVertically)
- ) {
- Text(
- text = senderName,
- modifier = Modifier
- .fillMaxWidth()
- .clipToBounds(),
- maxLines = 1,
- overflow = TextOverflow.Ellipsis,
- style = ElementTheme.typography.fontBodySmMedium,
- textAlign = TextAlign.Start,
- color = ElementTheme.materialColors.primary,
- )
- Text(
- modifier = Modifier.fillMaxWidth(),
- text = text.orEmpty(),
- style = ElementTheme.typography.fontBodyMdRegular,
- textAlign = TextAlign.Start,
- color = ElementTheme.materialColors.secondary,
- maxLines = if (attachmentThumbnailInfo != null) 1 else 2,
- overflow = TextOverflow.Ellipsis,
- )
- }
- Icon(
- imageVector = CompoundIcons.Close(),
- contentDescription = stringResource(CommonStrings.action_close),
- tint = MaterialTheme.colorScheme.secondary,
- modifier = Modifier
- .padding(end = 4.dp, top = 4.dp, start = 16.dp, bottom = 16.dp)
- .size(16.dp)
- .clickable(
- enabled = true,
- onClick = onResetComposerMode,
- interactionSource = remember { MutableInteractionSource() },
- indication = rememberRipple(bounded = false)
- ),
+ .padding(top = 6.dp, bottom = 6.dp)
+ .fillMaxWidth(),
+ style = ElementRichTextEditorStyle.composerStyle(hasFocus = state.hasFocus),
+ resolveMentionDisplay = resolveMentionDisplay,
+ resolveRoomMentionDisplay = resolveRoomMentionDisplay,
+ onError = onError,
+ onRichContentSelected = onRichContentSelected,
+ onTyping = onTyping,
)
}
}
@@ -606,43 +514,41 @@ internal fun TextComposerSimplePreview() = ElementPreview {
items = persistentListOf(
{
ATextComposer(
- aRichTextEditorState(initialText = "", initialFocus = true),
+ TextEditorState.Markdown(aMarkdownTextEditorState(initialText = "", initialFocus = true)),
voiceMessageState = VoiceMessageState.Idle,
composerMode = MessageComposerMode.Normal,
- enableTextFormatting = true,
enableVoiceMessages = true,
currentUserId = UserId("@alice:localhost"),
)
},
{
ATextComposer(
- aRichTextEditorState(initialText = "A message", initialFocus = true),
+ TextEditorState.Markdown(aMarkdownTextEditorState(initialText = "A message", initialFocus = true)),
voiceMessageState = VoiceMessageState.Idle,
composerMode = MessageComposerMode.Normal,
- enableTextFormatting = true,
enableVoiceMessages = true,
currentUserId = UserId("@alice:localhost")
)
},
{
ATextComposer(
- aRichTextEditorState(
- initialText = "A message\nWith several lines\nTo preview larger textfields and long lines with overflow",
- initialFocus = true
+ TextEditorState.Markdown(
+ aMarkdownTextEditorState(
+ initialText = "A message\nWith several lines\nTo preview larger textfields and long lines with overflow",
+ initialFocus = true
+ )
),
voiceMessageState = VoiceMessageState.Idle,
composerMode = MessageComposerMode.Normal,
- enableTextFormatting = true,
enableVoiceMessages = true,
currentUserId = UserId("@alice:localhost")
)
},
{
ATextComposer(
- aRichTextEditorState(initialText = "A message without focus"),
+ TextEditorState.Markdown(aMarkdownTextEditorState(initialText = "A message without focus", initialFocus = false)),
voiceMessageState = VoiceMessageState.Idle,
composerMode = MessageComposerMode.Normal,
- enableTextFormatting = true,
enableVoiceMessages = true,
currentUserId = UserId("@alice:localhost")
)
@@ -656,33 +562,32 @@ internal fun TextComposerSimplePreview() = ElementPreview {
internal fun TextComposerFormattingPreview() = ElementPreview {
PreviewColumn(items = persistentListOf({
ATextComposer(
- aRichTextEditorState(),
+ TextEditorState.Rich(aRichTextEditorState()),
voiceMessageState = VoiceMessageState.Idle,
showTextFormatting = true,
composerMode = MessageComposerMode.Normal,
- enableTextFormatting = true,
enableVoiceMessages = true,
currentUserId = UserId("@alice:localhost")
)
}, {
ATextComposer(
- aRichTextEditorState(initialText = "A message"),
+ TextEditorState.Rich(aRichTextEditorState(initialText = "A message")),
voiceMessageState = VoiceMessageState.Idle,
showTextFormatting = true,
composerMode = MessageComposerMode.Normal,
- enableTextFormatting = true,
enableVoiceMessages = true,
currentUserId = UserId("@alice:localhost")
)
}, {
ATextComposer(
- aRichTextEditorState(
- initialText = "A message\nWith several lines\nTo preview larger textfields and long lines with overflow",
+ TextEditorState.Rich(
+ aRichTextEditorState(
+ initialText = "A message\nWith several lines\nTo preview larger textfields and long lines with overflow",
+ )
),
voiceMessageState = VoiceMessageState.Idle,
showTextFormatting = true,
composerMode = MessageComposerMode.Normal,
- enableTextFormatting = true,
enableVoiceMessages = true,
currentUserId = UserId("@alice:localhost")
)
@@ -694,10 +599,23 @@ internal fun TextComposerFormattingPreview() = ElementPreview {
internal fun TextComposerEditPreview() = ElementPreview {
PreviewColumn(items = persistentListOf({
ATextComposer(
- aRichTextEditorState(initialText = "A message", initialFocus = true),
+ TextEditorState.Rich(aRichTextEditorState(initialText = "A message", initialFocus = true)),
+ voiceMessageState = VoiceMessageState.Idle,
+ composerMode = MessageComposerMode.Edit(EventId("$1234"), "Some text", TransactionId("1234")),
+ enableVoiceMessages = true,
+ currentUserId = UserId("@alice:localhost")
+ )
+ }))
+}
+
+@PreviewsDayNight
+@Composable
+internal fun MarkdownTextComposerEditPreview() = ElementPreview {
+ PreviewColumn(items = persistentListOf({
+ ATextComposer(
+ TextEditorState.Markdown(aMarkdownTextEditorState(initialText = "A message", initialFocus = true)),
voiceMessageState = VoiceMessageState.Idle,
composerMode = MessageComposerMode.Edit(EventId("$1234"), "Some text", TransactionId("1234")),
- enableTextFormatting = true,
enableVoiceMessages = true,
currentUserId = UserId("@alice:localhost")
)
@@ -711,7 +629,7 @@ internal fun TextComposerReplyPreview() = ElementPreview {
items = persistentListOf(
{
ATextComposer(
- aRichTextEditorState(),
+ TextEditorState.Rich(aRichTextEditorState()),
voiceMessageState = VoiceMessageState.Idle,
composerMode = MessageComposerMode.Reply(
isThreaded = false,
@@ -722,14 +640,13 @@ internal fun TextComposerReplyPreview() = ElementPreview {
"With several lines\n" +
"To preview larger textfields and long lines with overflow"
),
- enableTextFormatting = true,
enableVoiceMessages = true,
currentUserId = UserId("@alice:localhost")
)
},
{
ATextComposer(
- aRichTextEditorState(),
+ TextEditorState.Rich(aRichTextEditorState()),
voiceMessageState = VoiceMessageState.Idle,
composerMode = MessageComposerMode.Reply(
isThreaded = true,
@@ -740,14 +657,13 @@ internal fun TextComposerReplyPreview() = ElementPreview {
"With several lines\n" +
"To preview larger textfields and long lines with overflow"
),
- enableTextFormatting = true,
enableVoiceMessages = true,
currentUserId = UserId("@alice:localhost")
)
},
{
ATextComposer(
- aRichTextEditorState(initialText = "A message"),
+ TextEditorState.Rich(aRichTextEditorState(initialText = "A message")),
voiceMessageState = VoiceMessageState.Idle,
composerMode = MessageComposerMode.Reply(
isThreaded = true,
@@ -761,14 +677,13 @@ internal fun TextComposerReplyPreview() = ElementPreview {
),
defaultContent = "image.jpg"
),
- enableTextFormatting = true,
enableVoiceMessages = true,
currentUserId = UserId("@alice:localhost")
)
},
{
ATextComposer(
- aRichTextEditorState(initialText = "A message"),
+ TextEditorState.Rich(aRichTextEditorState(initialText = "A message")),
voiceMessageState = VoiceMessageState.Idle,
composerMode = MessageComposerMode.Reply(
isThreaded = false,
@@ -782,14 +697,13 @@ internal fun TextComposerReplyPreview() = ElementPreview {
),
defaultContent = "video.mp4"
),
- enableTextFormatting = true,
enableVoiceMessages = true,
currentUserId = UserId("@alice:localhost")
)
},
{
ATextComposer(
- aRichTextEditorState(initialText = "A message"),
+ TextEditorState.Rich(aRichTextEditorState(initialText = "A message")),
voiceMessageState = VoiceMessageState.Idle,
composerMode = MessageComposerMode.Reply(
isThreaded = false,
@@ -803,14 +717,13 @@ internal fun TextComposerReplyPreview() = ElementPreview {
),
defaultContent = "logs.txt"
),
- enableTextFormatting = true,
enableVoiceMessages = true,
currentUserId = UserId("@alice:localhost")
)
},
{
ATextComposer(
- aRichTextEditorState(initialText = "A message", initialFocus = true),
+ TextEditorState.Rich(aRichTextEditorState(initialText = "A message", initialFocus = true)),
voiceMessageState = VoiceMessageState.Idle,
composerMode = MessageComposerMode.Reply(
isThreaded = false,
@@ -824,7 +737,6 @@ internal fun TextComposerReplyPreview() = ElementPreview {
),
defaultContent = "Shared location"
),
- enableTextFormatting = true,
enableVoiceMessages = true,
currentUserId = UserId("@alice:localhost")
)
@@ -840,10 +752,9 @@ internal fun TextComposerVoicePreview() = ElementPreview {
fun VoicePreview(
voiceMessageState: VoiceMessageState
) = ATextComposer(
- aRichTextEditorState(initialFocus = true),
+ TextEditorState.Rich(aRichTextEditorState(initialFocus = true)),
voiceMessageState = voiceMessageState,
composerMode = MessageComposerMode.Normal,
- enableTextFormatting = true,
enableVoiceMessages = true,
currentUserId = UserId("@alice:localhost")
)
@@ -902,23 +813,21 @@ private fun PreviewColumn(
@Composable
private fun ATextComposer(
- richTextEditorState: RichTextEditorState,
+ state: TextEditorState,
voiceMessageState: VoiceMessageState,
composerMode: MessageComposerMode,
- enableTextFormatting: Boolean,
enableVoiceMessages: Boolean,
currentUserId: UserId,
showTextFormatting: Boolean = false,
) {
TextComposer(
- state = richTextEditorState,
+ state = state,
showTextFormatting = showTextFormatting,
voiceMessageState = voiceMessageState,
permalinkParser = object : PermalinkParser {
override fun parse(uriString: String): PermalinkData = TODO("Not yet implemented")
},
composerMode = composerMode,
- enableTextFormatting = enableTextFormatting,
enableVoiceMessages = enableVoiceMessages,
currentUserId = currentUserId,
onRequestFocus = {},
diff --git a/libraries/textcomposer/impl/src/main/kotlin/io/element/android/libraries/textcomposer/components/markdown/MarkdownEditText.kt b/libraries/textcomposer/impl/src/main/kotlin/io/element/android/libraries/textcomposer/components/markdown/MarkdownEditText.kt
new file mode 100644
index 0000000000..98842c35de
--- /dev/null
+++ b/libraries/textcomposer/impl/src/main/kotlin/io/element/android/libraries/textcomposer/components/markdown/MarkdownEditText.kt
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2024 New Vector Ltd
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package io.element.android.libraries.textcomposer.components.markdown
+
+import android.content.Context
+import androidx.appcompat.widget.AppCompatEditText
+
+internal class MarkdownEditText(
+ context: Context,
+) : AppCompatEditText(context) {
+ var onSelectionChangeListener: ((Int, Int) -> Unit)? = null
+
+ private var isModifyingText = false
+
+ fun updateEditableText(charSequence: CharSequence) {
+ isModifyingText = true
+ editableText.clear()
+ editableText.append(charSequence)
+ isModifyingText = false
+ }
+
+ override fun setText(text: CharSequence?, type: BufferType?) {
+ isModifyingText = true
+ super.setText(text, type)
+ isModifyingText = false
+ }
+
+ override fun onSelectionChanged(selStart: Int, selEnd: Int) {
+ super.onSelectionChanged(selStart, selEnd)
+ if (!isModifyingText) {
+ onSelectionChangeListener?.invoke(selStart, selEnd)
+ }
+ }
+}
diff --git a/libraries/textcomposer/impl/src/main/kotlin/io/element/android/libraries/textcomposer/components/markdown/MarkdownTextInput.kt b/libraries/textcomposer/impl/src/main/kotlin/io/element/android/libraries/textcomposer/components/markdown/MarkdownTextInput.kt
new file mode 100644
index 0000000000..451eaca53f
--- /dev/null
+++ b/libraries/textcomposer/impl/src/main/kotlin/io/element/android/libraries/textcomposer/components/markdown/MarkdownTextInput.kt
@@ -0,0 +1,160 @@
+/*
+ * Copyright (c) 2024 New Vector Ltd
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package io.element.android.libraries.textcomposer.components.markdown
+
+import android.graphics.Color
+import android.text.Editable
+import android.text.Selection
+import androidx.compose.foundation.layout.fillMaxWidth
+import androidx.compose.foundation.layout.padding
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.unit.dp
+import androidx.compose.ui.viewinterop.AndroidView
+import androidx.core.text.getSpans
+import androidx.core.view.setPadding
+import androidx.core.widget.addTextChangedListener
+import io.element.android.libraries.designsystem.preview.ElementPreview
+import io.element.android.libraries.designsystem.preview.PreviewsDayNight
+import io.element.android.libraries.testtags.TestTags
+import io.element.android.libraries.textcomposer.ElementRichTextEditorStyle
+import io.element.android.libraries.textcomposer.mentions.MentionSpan
+import io.element.android.libraries.textcomposer.model.MarkdownTextEditorState
+import io.element.android.libraries.textcomposer.model.Suggestion
+import io.element.android.libraries.textcomposer.model.SuggestionType
+import io.element.android.wysiwyg.compose.RichTextEditorStyle
+import io.element.android.wysiwyg.compose.internal.applyStyleInCompose
+
+@Suppress("ModifierMissing")
+@Composable
+fun MarkdownTextInput(
+ state: MarkdownTextEditorState,
+ subcomposing: Boolean,
+ onTyping: (Boolean) -> Unit,
+ onSuggestionReceived: (Suggestion?) -> Unit,
+ richTextEditorStyle: RichTextEditorStyle,
+) {
+ val canUpdateState = !subcomposing
+ AndroidView(
+ modifier = Modifier
+ .padding(top = 6.dp, bottom = 6.dp)
+ .fillMaxWidth(),
+ factory = { context ->
+ MarkdownEditText(context).apply {
+ tag = TestTags.plainTextEditor.value // Needed for UI tests
+ setPadding(0)
+ setBackgroundColor(Color.TRANSPARENT)
+ setText(state.text.value())
+ if (canUpdateState) {
+ setSelection(state.selection.first, state.selection.last)
+ setOnFocusChangeListener { _, hasFocus ->
+ state.hasFocus = hasFocus
+ }
+ addTextChangedListener { editable ->
+ onTyping(!editable.isNullOrEmpty())
+ state.text.update(editable, false)
+ state.lineCount = lineCount
+
+ state.currentMentionSuggestion = editable?.checkSuggestionNeeded()
+ onSuggestionReceived(state.currentMentionSuggestion)
+ }
+ onSelectionChangeListener = { selStart, selEnd ->
+ state.selection = selStart..selEnd
+ state.currentMentionSuggestion = editableText.checkSuggestionNeeded()
+ onSuggestionReceived(state.currentMentionSuggestion)
+ }
+ state.requestFocusAction = { this.requestFocus() }
+ }
+ }
+ },
+ update = { editText ->
+ editText.applyStyleInCompose(richTextEditorStyle)
+
+ if (state.text.needsDisplaying()) {
+ editText.updateEditableText(state.text.value())
+ if (canUpdateState) {
+ state.text.update(editText.editableText, false)
+ }
+ }
+ if (canUpdateState) {
+ val newSelectionStart = state.selection.first
+ val newSelectionEnd = state.selection.last
+ val currentTextRange = 0..editText.editableText.length
+ val didSelectionChange = { editText.selectionStart != newSelectionStart || editText.selectionEnd != newSelectionEnd }
+ val isNewSelectionValid = { newSelectionStart in currentTextRange && newSelectionEnd in currentTextRange }
+ if (didSelectionChange() && isNewSelectionValid()) {
+ editText.setSelection(state.selection.first, state.selection.last)
+ }
+ }
+ }
+ )
+}
+
+private fun Editable.checkSuggestionNeeded(): Suggestion? {
+ if (this.isEmpty()) return null
+ val start = Selection.getSelectionStart(this)
+ val end = Selection.getSelectionEnd(this)
+ var startOfWord = start
+ while ((startOfWord > 0 || startOfWord == length) && !this[startOfWord - 1].isWhitespace()) {
+ startOfWord--
+ }
+ if (startOfWord !in indices) return null
+ val firstChar = this[startOfWord]
+
+ // If a mention span already exists we don't need suggestions
+ if (getSpans(startOfWord, startOfWord + 1).isNotEmpty()) return null
+
+ return if (firstChar in listOf('@', '#', '/')) {
+ var endOfWord = end
+ while (endOfWord < this.length && !this[endOfWord].isWhitespace()) {
+ endOfWord++
+ }
+ val text = this.subSequence(startOfWord + 1, endOfWord).toString()
+ val suggestionType = when (firstChar) {
+ '@' -> SuggestionType.Mention
+ '#' -> SuggestionType.Room
+ '/' -> SuggestionType.Command
+ else -> error("Unknown suggestion type. This should never happen.")
+ }
+ Suggestion(startOfWord, endOfWord, suggestionType, text)
+ } else {
+ null
+ }
+}
+
+@PreviewsDayNight
+@Composable
+internal fun MarkdownTextInputPreview() {
+ ElementPreview {
+ val style = ElementRichTextEditorStyle.composerStyle(hasFocus = true)
+ MarkdownTextInput(
+ state = aMarkdownTextEditorState(),
+ subcomposing = false,
+ onTyping = {},
+ onSuggestionReceived = {},
+ richTextEditorStyle = style,
+ )
+ }
+}
+
+internal fun aMarkdownTextEditorState(
+ initialText: String = "Hello, World!",
+ initialFocus: Boolean = true,
+) = MarkdownTextEditorState(
+ initialText = initialText,
+ initialFocus = initialFocus,
+)
diff --git a/libraries/textcomposer/impl/src/main/kotlin/io/element/android/libraries/textcomposer/components/markdown/StableCharSequence.kt b/libraries/textcomposer/impl/src/main/kotlin/io/element/android/libraries/textcomposer/components/markdown/StableCharSequence.kt
new file mode 100644
index 0000000000..5491f9ccf4
--- /dev/null
+++ b/libraries/textcomposer/impl/src/main/kotlin/io/element/android/libraries/textcomposer/components/markdown/StableCharSequence.kt
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2024 New Vector Ltd
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package io.element.android.libraries.textcomposer.components.markdown
+
+import android.text.SpannableString
+import androidx.compose.runtime.Stable
+import androidx.compose.runtime.getValue
+import androidx.compose.runtime.mutableStateOf
+import androidx.compose.runtime.setValue
+import io.element.android.libraries.core.extensions.orEmpty
+
+@Stable
+class StableCharSequence(initialText: CharSequence = "") {
+ private var value by mutableStateOf(SpannableString(initialText))
+ private var needsDisplaying by mutableStateOf(false)
+
+ fun update(newText: CharSequence?, needsDisplaying: Boolean) {
+ value = SpannableString(newText.orEmpty())
+ this.needsDisplaying = needsDisplaying
+ }
+
+ fun value(): CharSequence = value
+ fun needsDisplaying(): Boolean = needsDisplaying
+
+ override fun toString(): String {
+ return "ImmutableCharSequence(value='$value', needsDisplaying=$needsDisplaying)"
+ }
+}
diff --git a/libraries/textcomposer/impl/src/main/kotlin/io/element/android/libraries/textcomposer/mentions/MentionSpan.kt b/libraries/textcomposer/impl/src/main/kotlin/io/element/android/libraries/textcomposer/mentions/MentionSpan.kt
index 9788f1f6c3..fe1c0c2167 100644
--- a/libraries/textcomposer/impl/src/main/kotlin/io/element/android/libraries/textcomposer/mentions/MentionSpan.kt
+++ b/libraries/textcomposer/impl/src/main/kotlin/io/element/android/libraries/textcomposer/mentions/MentionSpan.kt
@@ -26,6 +26,8 @@ import kotlin.math.min
import kotlin.math.roundToInt
class MentionSpan(
+ val text: String,
+ val rawValue: String,
val type: Type,
val backgroundColor: Int,
val textColor: Int,
@@ -39,29 +41,25 @@ class MentionSpan(
private var actualText: CharSequence? = null
private var textWidth = 0
- private var cachedRect: RectF = RectF()
private val backgroundPaint = Paint().apply {
isAntiAlias = true
color = backgroundColor
}
override fun getSize(paint: Paint, text: CharSequence?, start: Int, end: Int, fm: Paint.FontMetricsInt?): Int {
- val mentionText = getActualText(text, start, end)
+ val mentionText = getActualText(this.text)
paint.typeface = typeface
textWidth = paint.measureText(mentionText, 0, mentionText.length).roundToInt()
return textWidth + startPadding + endPadding
}
override fun draw(canvas: Canvas, text: CharSequence?, start: Int, end: Int, x: Float, top: Int, y: Int, bottom: Int, paint: Paint) {
- val mentionText = getActualText(text, start, end)
+ val mentionText = getActualText(this.text)
// Extra vertical space to add below the baseline (y). This helps us center the span vertically
val extraVerticalSpace = y + paint.ascent() + paint.descent() - top
- if (cachedRect.isEmpty) {
- cachedRect = RectF(x, top.toFloat(), x + textWidth + startPadding + endPadding, y.toFloat() + extraVerticalSpace)
- }
- val rect = cachedRect
+ val rect = RectF(x, top.toFloat(), x + textWidth + startPadding + endPadding, y.toFloat() + extraVerticalSpace)
val radius = rect.height() / 2
canvas.drawRoundRect(rect, radius, radius, backgroundPaint)
paint.color = textColor
@@ -69,24 +67,24 @@ class MentionSpan(
canvas.drawText(mentionText, 0, mentionText.length, x + startPadding, y.toFloat(), paint)
}
- private fun getActualText(text: CharSequence?, start: Int, end: Int): CharSequence {
+ private fun getActualText(text: String): CharSequence {
if (actualText != null) return actualText!!
return buildString {
val mentionText = text.orEmpty()
when (type) {
Type.USER -> {
- if (start in mentionText.indices && mentionText[start] != '@') {
+ if (text.firstOrNull() != '@') {
append("@")
}
}
Type.ROOM -> {
- if (start in mentionText.indices && mentionText[start] != '#') {
+ if (text.firstOrNull() != '#') {
append("#")
}
}
}
- append(mentionText.substring(start, min(end, start + MAX_LENGTH)))
- if (end - start > MAX_LENGTH) {
+ append(mentionText.substring(0, min(mentionText.length, MAX_LENGTH)))
+ if (mentionText.length > MAX_LENGTH) {
append("…")
}
actualText = this
diff --git a/libraries/textcomposer/impl/src/main/kotlin/io/element/android/libraries/textcomposer/mentions/MentionSpanProvider.kt b/libraries/textcomposer/impl/src/main/kotlin/io/element/android/libraries/textcomposer/mentions/MentionSpanProvider.kt
index 7d8bfd34ce..f7da518feb 100644
--- a/libraries/textcomposer/impl/src/main/kotlin/io/element/android/libraries/textcomposer/mentions/MentionSpanProvider.kt
+++ b/libraries/textcomposer/impl/src/main/kotlin/io/element/android/libraries/textcomposer/mentions/MentionSpanProvider.kt
@@ -84,6 +84,8 @@ class MentionSpanProvider(
permalinkData is PermalinkData.UserLink -> {
val isCurrentUser = permalinkData.userId == currentSessionId
MentionSpan(
+ text = text,
+ rawValue = permalinkData.userId.toString(),
type = MentionSpan.Type.USER,
backgroundColor = if (isCurrentUser) currentUserBackgroundColor else otherBackgroundColor,
textColor = if (isCurrentUser) currentUserTextColor else otherTextColor,
@@ -94,6 +96,8 @@ class MentionSpanProvider(
}
text == "@room" && permalinkData is PermalinkData.FallbackLink -> {
MentionSpan(
+ text = text,
+ rawValue = "@room",
type = MentionSpan.Type.USER,
backgroundColor = otherBackgroundColor,
textColor = otherTextColor,
@@ -102,8 +106,22 @@ class MentionSpanProvider(
typeface = typeface.value,
)
}
+ permalinkData is PermalinkData.RoomLink -> {
+ MentionSpan(
+ text = text,
+ rawValue = permalinkData.roomIdOrAlias.toString(),
+ type = MentionSpan.Type.ROOM,
+ backgroundColor = otherBackgroundColor,
+ textColor = otherTextColor,
+ startPadding = startPaddingPx,
+ endPadding = endPaddingPx,
+ typeface = typeface.value,
+ )
+ }
else -> {
MentionSpan(
+ text = text,
+ rawValue = text,
type = MentionSpan.Type.ROOM,
backgroundColor = otherBackgroundColor,
textColor = otherTextColor,
@@ -155,8 +173,8 @@ internal fun MentionSpanPreview() {
provider.setup()
val textColor = ElementTheme.colors.textPrimary.toArgb()
- fun mentionSpanMe() = provider.getMentionSpanFor("me", "https://matrix.to/#/@me:matrix.org")
- fun mentionSpanOther() = provider.getMentionSpanFor("other", "https://matrix.to/#/@other:matrix.org")
+ fun mentionSpanMe() = provider.getMentionSpanFor("mention", "https://matrix.to/#/@me:matrix.org")
+ fun mentionSpanOther() = provider.getMentionSpanFor("mention", "https://matrix.to/#/@other:matrix.org")
fun mentionSpanRoom() = provider.getMentionSpanFor("room", "https://matrix.to/#/#room:matrix.org")
AndroidView(factory = { context ->
TextView(context).apply {
diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/mentions/MentionSuggestion.kt b/libraries/textcomposer/impl/src/main/kotlin/io/element/android/libraries/textcomposer/mentions/ResolvedMentionSuggestion.kt
similarity index 71%
rename from features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/mentions/MentionSuggestion.kt
rename to libraries/textcomposer/impl/src/main/kotlin/io/element/android/libraries/textcomposer/mentions/ResolvedMentionSuggestion.kt
index b2977bd508..03bc48f53d 100644
--- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/mentions/MentionSuggestion.kt
+++ b/libraries/textcomposer/impl/src/main/kotlin/io/element/android/libraries/textcomposer/mentions/ResolvedMentionSuggestion.kt
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2023 New Vector Ltd
+ * Copyright (c) 2024 New Vector Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -14,13 +14,13 @@
* limitations under the License.
*/
-package io.element.android.features.messages.impl.mentions
+package io.element.android.libraries.textcomposer.mentions
import androidx.compose.runtime.Immutable
import io.element.android.libraries.matrix.api.room.RoomMember
@Immutable
-sealed interface MentionSuggestion {
- data object Room : MentionSuggestion
- data class Member(val roomMember: RoomMember) : MentionSuggestion
+sealed interface ResolvedMentionSuggestion {
+ data object AtRoom : ResolvedMentionSuggestion
+ data class Member(val roomMember: RoomMember) : ResolvedMentionSuggestion
}
diff --git a/libraries/textcomposer/impl/src/main/kotlin/io/element/android/libraries/textcomposer/model/MarkdownTextEditorState.kt b/libraries/textcomposer/impl/src/main/kotlin/io/element/android/libraries/textcomposer/model/MarkdownTextEditorState.kt
new file mode 100644
index 0000000000..7cda8f421c
--- /dev/null
+++ b/libraries/textcomposer/impl/src/main/kotlin/io/element/android/libraries/textcomposer/model/MarkdownTextEditorState.kt
@@ -0,0 +1,122 @@
+/*
+ * Copyright (c) 2024 New Vector Ltd
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package io.element.android.libraries.textcomposer.model
+
+import android.text.Spannable
+import android.text.SpannableString
+import android.text.SpannableStringBuilder
+import android.text.Spanned
+import androidx.compose.runtime.Stable
+import androidx.compose.runtime.getValue
+import androidx.compose.runtime.mutableIntStateOf
+import androidx.compose.runtime.mutableStateOf
+import androidx.compose.runtime.setValue
+import androidx.core.text.getSpans
+import io.element.android.libraries.matrix.api.core.UserId
+import io.element.android.libraries.matrix.api.permalink.PermalinkBuilder
+import io.element.android.libraries.matrix.api.room.Mention
+import io.element.android.libraries.textcomposer.components.markdown.StableCharSequence
+import io.element.android.libraries.textcomposer.mentions.MentionSpan
+import io.element.android.libraries.textcomposer.mentions.MentionSpanProvider
+import io.element.android.libraries.textcomposer.mentions.ResolvedMentionSuggestion
+
+@Stable
+class MarkdownTextEditorState(
+ initialText: String?,
+ initialFocus: Boolean,
+) {
+ var text by mutableStateOf(StableCharSequence(initialText ?: ""))
+ var selection by mutableStateOf(0..0)
+ var hasFocus by mutableStateOf(initialFocus)
+ var requestFocusAction by mutableStateOf({})
+ var lineCount by mutableIntStateOf(1)
+ var currentMentionSuggestion by mutableStateOf(null)
+
+ fun insertMention(
+ mention: ResolvedMentionSuggestion,
+ mentionSpanProvider: MentionSpanProvider,
+ permalinkBuilder: PermalinkBuilder,
+ ) {
+ val suggestion = currentMentionSuggestion ?: return
+ when (mention) {
+ is ResolvedMentionSuggestion.AtRoom -> {
+ val currentText = SpannableStringBuilder(text.value())
+ val replaceText = "@room"
+ val roomPill = mentionSpanProvider.getMentionSpanFor(replaceText, "")
+ currentText.replace(suggestion.start, suggestion.end, ". ")
+ val end = suggestion.start + 1
+ currentText.setSpan(roomPill, suggestion.start, end, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE)
+ text.update(currentText, true)
+ selection = IntRange(end + 1, end + 1)
+ }
+ is ResolvedMentionSuggestion.Member -> {
+ val currentText = SpannableStringBuilder(text.value())
+ val text = mention.roomMember.displayName?.prependIndent("@") ?: mention.roomMember.userId.value
+ val link = permalinkBuilder.permalinkForUser(mention.roomMember.userId).getOrNull() ?: return
+ val mentionPill = mentionSpanProvider.getMentionSpanFor(text, link)
+ currentText.replace(suggestion.start, suggestion.end, ". ")
+ val end = suggestion.start + 1
+ currentText.setSpan(mentionPill, suggestion.start, end, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE)
+ this.text.update(currentText, true)
+ this.selection = IntRange(end + 1, end + 1)
+ }
+ }
+ }
+
+ fun getMessageMarkdown(permalinkBuilder: PermalinkBuilder): String {
+ val charSequence = text.value()
+ return if (charSequence is Spanned) {
+ val mentions = charSequence.getSpans(0, charSequence.length, MentionSpan::class.java)
+ buildString {
+ append(charSequence.toString())
+ if (mentions != null && mentions.isNotEmpty()) {
+ for (mention in mentions.reversed()) {
+ val start = charSequence.getSpanStart(mention)
+ val end = charSequence.getSpanEnd(mention)
+ if (mention.type == MentionSpan.Type.USER) {
+ if (mention.rawValue == "@room") {
+ replace(start, end, "@room")
+ } else {
+ val link = permalinkBuilder.permalinkForUser(UserId(mention.rawValue)).getOrNull() ?: continue
+ replace(start, end, "[${mention.text}]($link)")
+ }
+ }
+ }
+ }
+ }
+ } else {
+ charSequence.toString()
+ }
+ }
+
+ fun getMentions(): List {
+ val text = SpannableString(text.value())
+ val mentionSpans = text.getSpans(0, text.length)
+ return mentionSpans.mapNotNull { mentionSpan ->
+ when (mentionSpan.type) {
+ MentionSpan.Type.USER -> {
+ if (mentionSpan.rawValue == "@room") {
+ Mention.AtRoom
+ } else {
+ Mention.User(UserId(mentionSpan.rawValue))
+ }
+ }
+ else -> null
+ }
+ }
+ }
+}
diff --git a/libraries/textcomposer/impl/src/main/kotlin/io/element/android/libraries/textcomposer/model/TextEditorState.kt b/libraries/textcomposer/impl/src/main/kotlin/io/element/android/libraries/textcomposer/model/TextEditorState.kt
new file mode 100644
index 0000000000..ae7a15fb65
--- /dev/null
+++ b/libraries/textcomposer/impl/src/main/kotlin/io/element/android/libraries/textcomposer/model/TextEditorState.kt
@@ -0,0 +1,69 @@
+/*
+ * Copyright (c) 2024 New Vector Ltd
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package io.element.android.libraries.textcomposer.model
+
+import androidx.compose.runtime.Immutable
+import io.element.android.libraries.matrix.api.permalink.PermalinkBuilder
+import io.element.android.wysiwyg.compose.RichTextEditorState
+
+@Immutable
+sealed interface TextEditorState {
+ data class Markdown(
+ val state: MarkdownTextEditorState,
+ ) : TextEditorState
+
+ data class Rich(
+ val richTextEditorState: RichTextEditorState
+ ) : TextEditorState
+
+ fun messageHtml(): String? = when (this) {
+ is Markdown -> null
+ is Rich -> richTextEditorState.messageHtml
+ }
+
+ fun messageMarkdown(permalinkBuilder: PermalinkBuilder): String = when (this) {
+ is Markdown -> state.getMessageMarkdown(permalinkBuilder)
+ is Rich -> richTextEditorState.messageMarkdown
+ }
+
+ fun hasFocus(): Boolean = when (this) {
+ is Markdown -> state.hasFocus
+ is Rich -> richTextEditorState.hasFocus
+ }
+
+ suspend fun reset() {
+ when (this) {
+ is Markdown -> {
+ state.selection = IntRange.EMPTY
+ state.text.update("", true)
+ }
+ is Rich -> richTextEditorState.setHtml("")
+ }
+ }
+
+ suspend fun requestFocus() {
+ when (this) {
+ is Markdown -> state.requestFocusAction()
+ is Rich -> richTextEditorState.requestFocus()
+ }
+ }
+
+ val lineCount: Int get() = when (this) {
+ is Markdown -> state.lineCount
+ is Rich -> richTextEditorState.lineCount
+ }
+}
diff --git a/libraries/textcomposer/impl/src/main/res/values-ka/translations.xml b/libraries/textcomposer/impl/src/main/res/values-ka/translations.xml
new file mode 100644
index 0000000000..f79c0eb518
--- /dev/null
+++ b/libraries/textcomposer/impl/src/main/res/values-ka/translations.xml
@@ -0,0 +1,25 @@
+
+
+ "დაამატეთ დანართი"
+ "პუნქტების სიის ჩართვა"
+ "ფორმატირების პარამეტრები დახურვა"
+ "კოდის ბლოკის ჩართვა"
+ "შეტყობინება…"
+ "ბმულის შექმნა"
+ "ბმულის რედაქტირება"
+ "თამამი შრიფტის გამოყენება"
+ "კურსიული შრიფტის გამოყენება"
+ "გადახაზული ფორმატის გამოყენება"
+ "ხაზგასმული ფორმატის გამოყენება"
+ "სრული ეკრანის რეჟიმის ჩართვა"
+ "აბზაცი"
+ "კოდის შიდა ფორმატის გამოყენება"
+ "ბმულის დაყენება"
+ "დანომრილი სიის ჩართვა"
+ "გახსენით შედგენის ვარიანტები"
+ "ციტატის ჩართვა"
+ "ბმულის წაშლა"
+ "აბზაცის გარეშე"
+ "Ბმული"
+ "ჩასაწერად დააჭირეთ"
+
diff --git a/libraries/textcomposer/impl/src/main/res/values-pt/translations.xml b/libraries/textcomposer/impl/src/main/res/values-pt/translations.xml
new file mode 100644
index 0000000000..6d11e3110c
--- /dev/null
+++ b/libraries/textcomposer/impl/src/main/res/values-pt/translations.xml
@@ -0,0 +1,25 @@
+
+
+ "Adicionar anexo"
+ "Ativar/desativar lista de pontos"
+ "Fechar opções de formatação"
+ "Ativar/desativar bloco de código"
+ "Mensagem…"
+ "Criar uma ligação"
+ "Editar ligação"
+ "Aplicar negrito"
+ "Aplicar itálico"
+ "Aplicar rasura"
+ "Aplicar sublinhado"
+ "Entrar/sair do modo de ecrã inteiro"
+ "Indentar"
+ "Aplicar código em linha"
+ "Definir ligação"
+ "Alternar lista numerada"
+ "Abrir opções de escrita"
+ "Pôr/tirar aspas"
+ "Remover ligação"
+ "Desindentar"
+ "Ligação"
+ "Segurar para gravar"
+
diff --git a/libraries/textcomposer/impl/src/main/res/values-ru/translations.xml b/libraries/textcomposer/impl/src/main/res/values-ru/translations.xml
index 45cb63ded4..4a7fb7b854 100644
--- a/libraries/textcomposer/impl/src/main/res/values-ru/translations.xml
+++ b/libraries/textcomposer/impl/src/main/res/values-ru/translations.xml
@@ -4,7 +4,7 @@
"Переключить список маркеров"
"Закрыть параметры форматирования"
"Переключить блок кода"
- "Сообщение"
+ "Сообщение…"
"Создать ссылку"
"Редактировать ссылку"
"Применить жирный шрифт"
diff --git a/libraries/textcomposer/impl/src/main/res/values-zh/translations.xml b/libraries/textcomposer/impl/src/main/res/values-zh/translations.xml
new file mode 100644
index 0000000000..0a6b2cf6a2
--- /dev/null
+++ b/libraries/textcomposer/impl/src/main/res/values-zh/translations.xml
@@ -0,0 +1,25 @@
+
+
+ "添加附件"
+ "切换符号列表"
+ "关闭格式化选项"
+ "切换代码块"
+ "消息…"
+ "创建链接"
+ "编辑链接"
+ "应用粗体格式"
+ "应用斜体格式"
+ "应用删除线格式"
+ "应用下划线格式"
+ "切换全屏模式"
+ "缩进"
+ "应用行内代码格式"
+ "设置链接"
+ "切换编号列表"
+ "打开撰写选项"
+ "切换引用"
+ "删除链接"
+ "取消缩进"
+ "链接"
+ "按住录制"
+
diff --git a/libraries/textcomposer/impl/src/test/kotlin/io/element/android/libraries/textcomposer/impl/components/markdown/MarkdownTextInputTest.kt b/libraries/textcomposer/impl/src/test/kotlin/io/element/android/libraries/textcomposer/impl/components/markdown/MarkdownTextInputTest.kt
new file mode 100644
index 0000000000..8967d4cf6a
--- /dev/null
+++ b/libraries/textcomposer/impl/src/test/kotlin/io/element/android/libraries/textcomposer/impl/components/markdown/MarkdownTextInputTest.kt
@@ -0,0 +1,201 @@
+/*
+ * Copyright (c) 2024 New Vector Ltd
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package io.element.android.libraries.textcomposer.impl.components.markdown
+
+import android.widget.EditText
+import androidx.activity.ComponentActivity
+import androidx.compose.ui.test.junit4.AndroidComposeTestRule
+import androidx.compose.ui.test.junit4.createAndroidComposeRule
+import androidx.core.text.getSpans
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import com.google.common.truth.Truth.assertThat
+import io.element.android.libraries.matrix.api.permalink.PermalinkData
+import io.element.android.libraries.matrix.test.A_SESSION_ID
+import io.element.android.libraries.matrix.test.permalink.FakePermalinkBuilder
+import io.element.android.libraries.matrix.test.permalink.FakePermalinkParser
+import io.element.android.libraries.matrix.test.room.aRoomMember
+import io.element.android.libraries.testtags.TestTags
+import io.element.android.libraries.textcomposer.ElementRichTextEditorStyle
+import io.element.android.libraries.textcomposer.components.markdown.MarkdownTextInput
+import io.element.android.libraries.textcomposer.components.markdown.aMarkdownTextEditorState
+import io.element.android.libraries.textcomposer.mentions.MentionSpan
+import io.element.android.libraries.textcomposer.mentions.MentionSpanProvider
+import io.element.android.libraries.textcomposer.mentions.ResolvedMentionSuggestion
+import io.element.android.libraries.textcomposer.model.MarkdownTextEditorState
+import io.element.android.libraries.textcomposer.model.Suggestion
+import io.element.android.libraries.textcomposer.model.SuggestionType
+import io.element.android.tests.testutils.EnsureCalledOnceWithParam
+import io.element.android.tests.testutils.EventsRecorder
+import kotlinx.coroutines.test.runTest
+import org.junit.Rule
+import org.junit.Test
+import org.junit.rules.TestRule
+import org.junit.runner.RunWith
+
+@RunWith(AndroidJUnit4::class)
+class MarkdownTextInputTest {
+ @get:Rule val rule = createAndroidComposeRule()
+
+ @Test
+ fun `when user types onTyping is triggered with value 'true'`() = runTest {
+ val state = aMarkdownTextEditorState(initialFocus = true)
+ val onTyping = EnsureCalledOnceWithParam(expectedParam = true, result = Unit)
+ rule.setMarkdownTextInput(state = state, onTyping = onTyping)
+ rule.activityRule.scenario.onActivity {
+ it.findEditor().setText("Test")
+ }
+ rule.awaitIdle()
+ onTyping.assertSuccess()
+ }
+
+ @Test
+ fun `when user removes text onTyping is triggered with value 'false'`() = runTest {
+ val state = aMarkdownTextEditorState(initialFocus = true)
+ val onTyping = EventsRecorder()
+ rule.setMarkdownTextInput(state = state, onTyping = onTyping)
+ rule.activityRule.scenario.onActivity {
+ val editText = it.findEditor()
+ editText.setText("Test")
+ editText.setText("")
+ editText.setText(null)
+ }
+ rule.awaitIdle()
+ onTyping.assertList(listOf(true, false, false))
+ }
+
+ @Test
+ fun `when user types something that's not a mention onSuggestionReceived is triggered with 'null'`() = runTest {
+ val state = aMarkdownTextEditorState(initialFocus = true)
+ val onSuggestionReceived = EventsRecorder()
+ rule.setMarkdownTextInput(state = state, onSuggestionReceived = onSuggestionReceived)
+ rule.activityRule.scenario.onActivity {
+ it.findEditor().setText("Test")
+ }
+ rule.awaitIdle()
+ onSuggestionReceived.assertSingle(null)
+ }
+
+ @Test
+ fun `when user types something that's a mention onSuggestionReceived is triggered a real value`() = runTest {
+ val state = aMarkdownTextEditorState(initialFocus = true)
+ val onSuggestionReceived = EventsRecorder()
+ rule.setMarkdownTextInput(state = state, onSuggestionReceived = onSuggestionReceived)
+ rule.activityRule.scenario.onActivity {
+ it.findEditor().setText("@")
+ it.findEditor().setText("#")
+ it.findEditor().setText("/")
+ }
+ rule.awaitIdle()
+ onSuggestionReceived.assertList(
+ listOf(
+ // User mention suggestion
+ Suggestion(0, 1, SuggestionType.Mention, ""),
+ // Room suggestion
+ Suggestion(0, 1, SuggestionType.Room, ""),
+ // Slash command suggestion
+ Suggestion(0, 1, SuggestionType.Command, ""),
+ )
+ )
+ }
+
+ @Test
+ fun `when the selection changes in the UI the state is updated`() = runTest {
+ val state = aMarkdownTextEditorState(initialText = "Test", initialFocus = true)
+ rule.setMarkdownTextInput(state = state)
+ rule.activityRule.scenario.onActivity {
+ val editor = it.findEditor()
+ editor.setSelection(2)
+ }
+ rule.awaitIdle()
+ // Selection is updated
+ assertThat(state.selection).isEqualTo(2..2)
+ }
+
+ @Test
+ fun `when the selection state changes in the view is updated`() = runTest {
+ val state = aMarkdownTextEditorState(initialText = "Test", initialFocus = true)
+ rule.setMarkdownTextInput(state = state)
+ var editor: EditText? = null
+ rule.activityRule.scenario.onActivity {
+ editor = it.findEditor()
+ state.selection = 2..2
+ }
+ rule.awaitIdle()
+ // Selection state is updated
+ assertThat(editor?.selectionStart).isEqualTo(2)
+ assertThat(editor?.selectionEnd).isEqualTo(2)
+ }
+
+ @Test
+ fun `when the view focus changes the state is updated`() = runTest {
+ val state = aMarkdownTextEditorState(initialText = "Test", initialFocus = false)
+ rule.setMarkdownTextInput(state = state)
+ rule.activityRule.scenario.onActivity {
+ val editor = it.findEditor()
+ editor.requestFocus()
+ }
+ // Focus state is updated
+ assertThat(state.hasFocus).isTrue()
+ }
+
+ @Test
+ fun `inserting a mention replaces the existing text with a span`() = runTest {
+ val permalinkParser = FakePermalinkParser(result = { PermalinkData.UserLink(A_SESSION_ID) })
+ val permalinkBuilder = FakePermalinkBuilder(result = { Result.success("https://matrix.to/#/$A_SESSION_ID") })
+ val state = aMarkdownTextEditorState(initialText = "@", initialFocus = true)
+ state.currentMentionSuggestion = Suggestion(0, 1, SuggestionType.Mention, "")
+ rule.setMarkdownTextInput(state = state)
+ var editor: EditText? = null
+ rule.activityRule.scenario.onActivity {
+ editor = it.findEditor()
+ state.insertMention(
+ ResolvedMentionSuggestion.Member(roomMember = aRoomMember()),
+ MentionSpanProvider(currentSessionId = A_SESSION_ID, permalinkParser = permalinkParser),
+ permalinkBuilder,
+ )
+ }
+ rule.awaitIdle()
+
+ // Text is replaced with a placeholder
+ assertThat(editor?.editableText.toString()).isEqualTo(". ")
+ // The placeholder contains a MentionSpan
+ val mentionSpans = editor?.editableText?.getSpans(0, 2).orEmpty()
+ assertThat(mentionSpans).isNotEmpty()
+ }
+
+ private fun AndroidComposeTestRule.setMarkdownTextInput(
+ state: MarkdownTextEditorState = aMarkdownTextEditorState(),
+ subcomposing: Boolean = false,
+ onTyping: (Boolean) -> Unit = {},
+ onSuggestionReceived: (Suggestion?) -> Unit = {},
+ ) {
+ rule.setContent {
+ val style = ElementRichTextEditorStyle.composerStyle(hasFocus = state.hasFocus)
+ MarkdownTextInput(
+ state = state,
+ subcomposing = subcomposing,
+ onTyping = onTyping,
+ onSuggestionReceived = onSuggestionReceived,
+ richTextEditorStyle = style,
+ )
+ }
+ }
+
+ private fun ComponentActivity.findEditor(): EditText {
+ return window.decorView.findViewWithTag(TestTags.plainTextEditor.value)
+ }
+}
diff --git a/libraries/textcomposer/impl/src/test/kotlin/io/element/android/libraries/textcomposer/impl/mentions/MentionSpanProviderTest.kt b/libraries/textcomposer/impl/src/test/kotlin/io/element/android/libraries/textcomposer/impl/mentions/MentionSpanProviderTest.kt
index 2b346ceeab..7245da04c6 100644
--- a/libraries/textcomposer/impl/src/test/kotlin/io/element/android/libraries/textcomposer/impl/mentions/MentionSpanProviderTest.kt
+++ b/libraries/textcomposer/impl/src/test/kotlin/io/element/android/libraries/textcomposer/impl/mentions/MentionSpanProviderTest.kt
@@ -17,6 +17,7 @@
package io.element.android.libraries.textcomposer.impl.mentions
import android.graphics.Color
+import android.net.Uri
import com.google.common.truth.Truth.assertThat
import io.element.android.libraries.matrix.api.core.RoomAlias
import io.element.android.libraries.matrix.api.core.UserId
@@ -66,6 +67,14 @@ class MentionSpanProviderTest {
assertThat(mentionSpan.textColor).isEqualTo(otherColor)
}
+ @Test
+ fun `getting mention span for everyone in the room`() {
+ permalinkParser.givenResult(PermalinkData.FallbackLink(uri = Uri.EMPTY))
+ val mentionSpan = mentionSpanProvider.getMentionSpanFor("@room", "#")
+ assertThat(mentionSpan.backgroundColor).isEqualTo(otherColor)
+ assertThat(mentionSpan.textColor).isEqualTo(otherColor)
+ }
+
@Test
fun `getting mention span for a room should return a MentionSpan with normal colors`() {
permalinkParser.givenResult(
diff --git a/libraries/textcomposer/impl/src/test/kotlin/io/element/android/libraries/textcomposer/impl/model/MarkdownTextEditorStateTest.kt b/libraries/textcomposer/impl/src/test/kotlin/io/element/android/libraries/textcomposer/impl/model/MarkdownTextEditorStateTest.kt
new file mode 100644
index 0000000000..bd2b6785ed
--- /dev/null
+++ b/libraries/textcomposer/impl/src/test/kotlin/io/element/android/libraries/textcomposer/impl/model/MarkdownTextEditorStateTest.kt
@@ -0,0 +1,171 @@
+/*
+ * Copyright (c) 2024 New Vector Ltd
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package io.element.android.libraries.textcomposer.impl.model
+
+import android.net.Uri
+import androidx.core.text.buildSpannedString
+import androidx.core.text.inSpans
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import com.google.common.truth.Truth.assertThat
+import io.element.android.libraries.matrix.api.core.SessionId
+import io.element.android.libraries.matrix.api.permalink.PermalinkData
+import io.element.android.libraries.matrix.api.room.Mention
+import io.element.android.libraries.matrix.test.A_SESSION_ID
+import io.element.android.libraries.matrix.test.permalink.FakePermalinkBuilder
+import io.element.android.libraries.matrix.test.permalink.FakePermalinkParser
+import io.element.android.libraries.matrix.test.room.aRoomMember
+import io.element.android.libraries.textcomposer.mentions.MentionSpan
+import io.element.android.libraries.textcomposer.mentions.MentionSpanProvider
+import io.element.android.libraries.textcomposer.mentions.ResolvedMentionSuggestion
+import io.element.android.libraries.textcomposer.model.MarkdownTextEditorState
+import io.element.android.libraries.textcomposer.model.Suggestion
+import io.element.android.libraries.textcomposer.model.SuggestionType
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@RunWith(AndroidJUnit4::class)
+class MarkdownTextEditorStateTest {
+ @Test
+ fun `insertMention - with no currentMentionSuggestion does nothing`() {
+ val state = MarkdownTextEditorState(initialText = "Hello @", initialFocus = true)
+ val member = aRoomMember()
+ val mention = ResolvedMentionSuggestion.Member(member)
+ val permalinkBuilder = FakePermalinkBuilder()
+ val mentionSpanProvider = aMentionSpanProvider()
+
+ state.insertMention(mention, mentionSpanProvider, permalinkBuilder)
+
+ assertThat(state.getMentions()).isEmpty()
+ }
+
+ @Test
+ fun `insertMention - with member but failed PermalinkBuilder result`() {
+ val state = MarkdownTextEditorState(initialText = "Hello @", initialFocus = true).apply {
+ currentMentionSuggestion = Suggestion(start = 6, end = 7, type = SuggestionType.Mention, text = "")
+ }
+ val member = aRoomMember()
+ val mention = ResolvedMentionSuggestion.Member(member)
+ val permalinkParser = FakePermalinkParser(result = { PermalinkData.UserLink(member.userId) })
+ val permalinkBuilder = FakePermalinkBuilder(result = { Result.failure(IllegalStateException("Failed")) })
+ val mentionSpanProvider = aMentionSpanProvider(permalinkParser = permalinkParser)
+
+ state.insertMention(mention, mentionSpanProvider, permalinkBuilder)
+
+ val mentions = state.getMentions()
+ assertThat(mentions).isEmpty()
+ }
+
+ @Test
+ fun `insertMention - with member`() {
+ val state = MarkdownTextEditorState(initialText = "Hello @", initialFocus = true).apply {
+ currentMentionSuggestion = Suggestion(start = 6, end = 7, type = SuggestionType.Mention, text = "")
+ }
+ val member = aRoomMember()
+ val mention = ResolvedMentionSuggestion.Member(member)
+ val permalinkParser = FakePermalinkParser(result = { PermalinkData.UserLink(member.userId) })
+ val permalinkBuilder = FakePermalinkBuilder(result = { Result.success("https://matrix.to/#/${member.userId}") })
+ val mentionSpanProvider = aMentionSpanProvider(permalinkParser = permalinkParser)
+
+ state.insertMention(mention, mentionSpanProvider, permalinkBuilder)
+
+ val mentions = state.getMentions()
+ assertThat(mentions).isNotEmpty()
+ assertThat((mentions.firstOrNull() as? Mention.User)?.userId).isEqualTo(member.userId)
+ }
+
+ @Test
+ fun `insertMention - with @room`() {
+ val state = MarkdownTextEditorState(initialText = "Hello @", initialFocus = true).apply {
+ currentMentionSuggestion = Suggestion(start = 6, end = 7, type = SuggestionType.Mention, text = "")
+ }
+ val mention = ResolvedMentionSuggestion.AtRoom
+ val permalinkBuilder = FakePermalinkBuilder()
+ val permalinkParser = FakePermalinkParser(result = { PermalinkData.FallbackLink(Uri.EMPTY, false) })
+ val mentionSpanProvider = aMentionSpanProvider(permalinkParser = permalinkParser)
+
+ state.insertMention(mention, mentionSpanProvider, permalinkBuilder)
+
+ val mentions = state.getMentions()
+ assertThat(mentions).isNotEmpty()
+ assertThat(mentions.firstOrNull()).isInstanceOf(Mention.AtRoom::class.java)
+ }
+
+ @Test
+ fun `getMessageMarkdown - when there are no MentionSpans returns the same text`() {
+ val text = "No mentions here"
+ val state = MarkdownTextEditorState(initialText = text, initialFocus = true)
+
+ val markdown = state.getMessageMarkdown(FakePermalinkBuilder())
+
+ assertThat(markdown).isEqualTo(text)
+ }
+
+ @Test
+ fun `getMessageMarkdown - when there are MentionSpans returns the same text with links to the mentions`() {
+ val text = "No mentions here"
+ val permalinkBuilder = FakePermalinkBuilder(result = { Result.success("https://matrix.to/#/$it") })
+ val state = MarkdownTextEditorState(initialText = text, initialFocus = true)
+ state.text.update(aMarkdownTextWithMentions(), needsDisplaying = false)
+
+ val markdown = state.getMessageMarkdown(permalinkBuilder = permalinkBuilder)
+
+ assertThat(markdown).isEqualTo(
+ "Hello [@Alice](https://matrix.to/#/@alice:matrix.org) and everyone in @room"
+ )
+ }
+
+ @Test
+ fun `getMentions - when there are no MentionSpans returns empty list of mentions`() {
+ val state = MarkdownTextEditorState(initialText = "Hello @", initialFocus = true)
+
+ assertThat(state.getMentions()).isEmpty()
+ }
+
+ @Test
+ fun `getMentions - when there are MentionSpans returns a list of mentions`() {
+ val state = MarkdownTextEditorState(initialText = "Hello @", initialFocus = true)
+ state.text.update(aMarkdownTextWithMentions(), needsDisplaying = false)
+
+ val mentions = state.getMentions()
+
+ assertThat(mentions).isNotEmpty()
+ assertThat((mentions.firstOrNull() as? Mention.User)?.userId?.value).isEqualTo("@alice:matrix.org")
+ assertThat(mentions.lastOrNull()).isInstanceOf(Mention.AtRoom::class.java)
+ }
+
+ private fun aMentionSpanProvider(
+ currentSessionId: SessionId = A_SESSION_ID,
+ permalinkParser: FakePermalinkParser = FakePermalinkParser(),
+ ): MentionSpanProvider {
+ return MentionSpanProvider(currentSessionId, permalinkParser)
+ }
+
+ private fun aMarkdownTextWithMentions(): CharSequence {
+ val userMentionSpan = MentionSpan("@Alice", "@alice:matrix.org", MentionSpan.Type.USER, 0, 0, 0, 0)
+ val atRoomMentionSpan = MentionSpan("@room", "@room", MentionSpan.Type.USER, 0, 0, 0, 0)
+ return buildSpannedString {
+ append("Hello ")
+ inSpans(userMentionSpan) {
+ append("@")
+ }
+ append(" and everyone in ")
+ inSpans(atRoomMentionSpan) {
+ append("@")
+ }
+ }
+ }
+}
diff --git a/libraries/troubleshoot/impl/src/main/res/values-it/translations.xml b/libraries/troubleshoot/impl/src/main/res/values-it/translations.xml
index 15328545ec..4c359a8140 100644
--- a/libraries/troubleshoot/impl/src/main/res/values-it/translations.xml
+++ b/libraries/troubleshoot/impl/src/main/res/values-it/translations.xml
@@ -1,6 +1,11 @@
"Esegui i test"
+ "Esegui nuovamente i test"
+ "Alcuni test sono falliti. Si prega di controllare i dettagli."
"Esegui i test per individuare eventuali problemi nella tua configurazione che potrebbero far sì che le notifiche non si comportino come previsto."
+ "Prova a risolvere"
+ "Tutti i test sono stati superati con successo."
"Risoluzione di problemi delle notifiche"
+ "Alcuni test richiedono la tua attenzione. Si prega di controllare i dettagli."
diff --git a/libraries/troubleshoot/impl/src/main/res/values-pt/translations.xml b/libraries/troubleshoot/impl/src/main/res/values-pt/translations.xml
new file mode 100644
index 0000000000..33f54d0712
--- /dev/null
+++ b/libraries/troubleshoot/impl/src/main/res/values-pt/translations.xml
@@ -0,0 +1,11 @@
+
+
+ "Correr testes"
+ "Correr testes novamente"
+ "Alguns testes falharam. Por favor, verifica os detalhes."
+ "Corre os testes para detetar problemas com a tua configuração que possam levar a comportamentos inesperados das notificações."
+ "Tentar corrigir"
+ "Todos os testes realizados sem problemas."
+ "Resolver problemas com as notificações"
+ "Alguns testes necessitam a tua atenção. Por favor, verifica os detalhes."
+
diff --git a/libraries/troubleshoot/impl/src/main/res/values-ro/translations.xml b/libraries/troubleshoot/impl/src/main/res/values-ro/translations.xml
new file mode 100644
index 0000000000..a10361672e
--- /dev/null
+++ b/libraries/troubleshoot/impl/src/main/res/values-ro/translations.xml
@@ -0,0 +1,11 @@
+
+
+ "Rulați testele"
+ "Rulați din nou testele"
+ "Unele teste au eșuat. Vă rugăm să verificați detaliile."
+ "Rulați testele pentru a detecta probleme în configurația dumneavoastră care poat face ca notificările să nu se funcționeze corect."
+ "Încercați să remediați"
+ "Toate testele au trecut cu succes."
+ "Depanați notificările"
+ "Unele teste necesită atenția dumneavoastră. Vă rugăm să verificați detaliile."
+
diff --git a/libraries/troubleshoot/impl/src/main/res/values-zh/translations.xml b/libraries/troubleshoot/impl/src/main/res/values-zh/translations.xml
new file mode 100644
index 0000000000..22354b62b7
--- /dev/null
+++ b/libraries/troubleshoot/impl/src/main/res/values-zh/translations.xml
@@ -0,0 +1,11 @@
+
+
+ "运行测试"
+ "再次运行测试"
+ "一些测试失败了。请查看详情。"
+ "运行测试以检测您的配置中可能导致通知无法按预期运行的问题。"
+ "尝试修复"
+ "所有测试均成功通过。"
+ "排查通知问题"
+ "有些测试需要你注意。请查看详情。"
+
diff --git a/libraries/ui-strings/src/main/res/values-be/translations.xml b/libraries/ui-strings/src/main/res/values-be/translations.xml
index c155ad7ca3..f5680c2b7f 100644
--- a/libraries/ui-strings/src/main/res/values-be/translations.xml
+++ b/libraries/ui-strings/src/main/res/values-be/translations.xml
@@ -36,6 +36,7 @@
"Прыняць"
"Дадаць у хроніку"
"Назад"
+ "Выклік"
"Скасаваць"
"Выбраць фота"
"Ачысціць"
@@ -74,6 +75,7 @@
"Загрузіць больш"
"Кіраванне ўліковым запісам"
"Кіраванне прыладамі"
+ "Паведамленне"
"Далей"
"Не"
"Не зараз"
@@ -119,6 +121,7 @@
"Заблакіраваныя карыстальнікі"
"Бурбалкі"
"Ідзе выклік (не падтрымліваецца)"
+ "Выклік пачаўся"
"Рэзервовае капіраванне чатаў"
"Аўтарскае права"
"Стварэнне пакоя…"
@@ -266,6 +269,7 @@
"Разблакіраваць"
"Вы зноў зможаце ўбачыць усе паведамленні."
"Разблакіраваць карыстальніка"
+ "Чат"
"Падзяліцца месцазнаходжаннем"
"Падзяліцца маім месцазнаходжаннем"
"Адкрыць у Apple Maps"
diff --git a/libraries/ui-strings/src/main/res/values-cs/translations.xml b/libraries/ui-strings/src/main/res/values-cs/translations.xml
index 66c33b70d9..52b673e535 100644
--- a/libraries/ui-strings/src/main/res/values-cs/translations.xml
+++ b/libraries/ui-strings/src/main/res/values-cs/translations.xml
@@ -36,6 +36,7 @@
"Přijmout"
"Přidat na časovou osu"
"Zpět"
+ "Hovor"
"Zrušit"
"Vybrat fotku"
"Vymazat"
@@ -74,6 +75,7 @@
"Načíst více"
"Spravovat účet"
"Spravovat zařízení"
+ "Zpráva"
"Další"
"Ne"
"Teď ne"
@@ -266,6 +268,7 @@
"Odblokovat"
"Znovu uvidíte všechny zprávy od nich."
"Odblokovat uživatele"
+ "Chat"
"Sdílet polohu"
"Sdílet moji polohu"
"Otevřít v Mapách Apple"
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 af217016a2..2779bead6f 100644
--- a/libraries/ui-strings/src/main/res/values-de/translations.xml
+++ b/libraries/ui-strings/src/main/res/values-de/translations.xml
@@ -34,6 +34,7 @@
"Akzeptieren"
"Zum Nachrichtenverlauf hinzufügen"
"Zurück"
+ "Anruf"
"Abbrechen"
"Foto auswählen"
"Löschen"
@@ -72,6 +73,7 @@
"Mehr laden …"
"Konto verwalten"
"Geräte verwalten"
+ "Nachricht"
"Weiter"
"Nein"
"Später"
@@ -262,6 +264,7 @@
"Blockierung aufheben"
"Der Nutzer kann dir wieder Nachrichten senden & alle Nachrichten des Nutzers werden wieder angezeigt."
"Blockierung aufheben"
+ "Chat"
"Standort teilen"
"Meinen Standort teilen"
"In Apple Maps öffnen"
diff --git a/libraries/ui-strings/src/main/res/values-es/translations.xml b/libraries/ui-strings/src/main/res/values-es/translations.xml
index 43e6919c34..4a09b3d52d 100644
--- a/libraries/ui-strings/src/main/res/values-es/translations.xml
+++ b/libraries/ui-strings/src/main/res/values-es/translations.xml
@@ -49,6 +49,7 @@
"Rechazar"
"Eliminar encuesta"
"Desactivar"
+ "Descartar"
"Hecho"
"Editar"
"Editar encuesta"
@@ -57,6 +58,7 @@
"Introducir PIN"
"¿Olvidaste tu contraseña?"
"Reenviar"
+ "Volver atrás"
"Invitar"
"Invitar personas"
"Invita a alguien a %1$s"
@@ -65,6 +67,7 @@
"Unirse"
"Más información"
"Salir"
+ "Salir de la conversación"
"Salir de la sala"
"Cargar más"
"Gestionar cuenta"
@@ -83,6 +86,7 @@
"Responder en el hilo"
"Informar de un error"
"Reportar Contenido"
+ "Restablecer"
"Reintentar"
"Reintentar descifrado"
"Guardar"
@@ -110,7 +114,9 @@
"Estadísticas"
"Apariencia"
"Sonido"
+ "Usuarios bloqueados"
"Burbujas"
+ "Llamada en curso (no admitida)"
"Copia de seguridad del chat"
"Derechos de autor"
"Creando sala…"
@@ -126,6 +132,9 @@
"Introduce tu PIN"
"Error"
"Todos"
+ "Falló"
+ "Favorito"
+ "Marcado como favorito"
"Archivo"
"Archivo guardado en Descargas"
"Reenviar mensaje"
@@ -150,6 +159,7 @@
"Silenciar"
"No hay resultados"
"Sin conexión"
+ "o"
"Contraseña"
"Personas"
"Enlace permanente"
@@ -175,6 +185,8 @@
"Sala"
"Nombre de la sala"
"p. ej., el nombre de tu proyecto"
+ "Cambios guardados"
+ "Guardando"
"Bloqueo de pantalla"
"Buscar a alguien"
"Buscar resultados"
@@ -217,6 +229,8 @@
"Error"
"Terminado"
"Atención"
+ "Tus cambios no se han guardado. ¿Estás seguro de que quieres volver atrás?"
+ "¿Guardar cambios?"
"No se pudo crear el enlace permanente"
"%1$s no pudo cargar el mapa. Por favor vuelve a intentarlo más tarde."
"Error al cargar mensajes"
diff --git a/libraries/ui-strings/src/main/res/values-hu/translations.xml b/libraries/ui-strings/src/main/res/values-hu/translations.xml
index 5e669f61f4..216829fd3e 100644
--- a/libraries/ui-strings/src/main/res/values-hu/translations.xml
+++ b/libraries/ui-strings/src/main/res/values-hu/translations.xml
@@ -34,6 +34,7 @@
"Elfogadás"
"Hozzáadás az idővonalhoz"
"Vissza"
+ "Hívás"
"Mégse"
"Fénykép kiválasztása"
"Törlés"
@@ -72,6 +73,7 @@
"Továbbiak betöltése"
"Fiók kezelése"
"Eszközök kezelése"
+ "Üzenet"
"Következő"
"Nem"
"Most nem"
@@ -262,6 +264,7 @@
"Letiltás feloldása"
"Újra láthatja az összes üzenetét."
"Felhasználó kitiltásának feloldása"
+ "Csevegés"
"Hely megosztása"
"Saját hely megosztása"
"Megnyitás az Apple Mapsben"
diff --git a/libraries/ui-strings/src/main/res/values-it/translations.xml b/libraries/ui-strings/src/main/res/values-it/translations.xml
index 3483fadb43..fd216e1e0b 100644
--- a/libraries/ui-strings/src/main/res/values-it/translations.xml
+++ b/libraries/ui-strings/src/main/res/values-it/translations.xml
@@ -158,12 +158,14 @@
"Moderno"
"Silenzia"
"Nessun risultato"
+ "Nessun nome della stanza"
"Non in linea"
"o"
"Password"
"Persone"
"Collegamento permanente"
"Autorizzazione"
+ "Attendere prego…"
"Vuoi davvero terminare questo sondaggio?"
"Sondaggio: %1$s"
"Voti totali: %1$s"
@@ -200,6 +202,7 @@
"Impostazioni"
"Posizione condivisa"
"Disconnessione"
+ "Qualcosa è andato storto"
"Avvio della conversazione…"
"Adesivo"
"Operazione riuscita"
@@ -212,6 +215,7 @@
"Argomento"
"Di cosa parla questa stanza?"
"Impossibile decrittografare"
+ "Non hai accesso a questo messaggio"
"Non è stato possibile spedire inviti a uno o più utenti."
"Impossibile inviare inviti"
"Sblocca"
@@ -236,6 +240,7 @@
"Caricamento dei messaggi non riuscito"
"%1$s non è riuscito ad accedere alla tua posizione. Riprova più tardi."
"Invio del messaggio vocale fallito."
+ "Messaggio non trovato"
"%1$s non ha l\'autorizzazione di accedere alla tua posizione. Puoi attivare l\'accesso nelle impostazioni."
"%1$s non ha l\'autorizzazione per accedere alla tua posizione. Attiva l\'accesso di seguito."
"%1$s non ha l\'autorizzazione di accedere al microfono. Attiva l\'accesso per registrare un messaggio vocale."
@@ -253,6 +258,7 @@
"Blocca"
"Gli utenti bloccati non saranno in grado di inviarti messaggi e tutti quelli già ricevuti saranno nascosti. Puoi sbloccarli in qualsiasi momento."
"Blocca utente"
+ "Profilo"
"Sblocca"
"Potrai vedere di nuovo tutti i suoi messaggi."
"Sblocca utente"
diff --git a/libraries/ui-strings/src/main/res/values-ka/translations.xml b/libraries/ui-strings/src/main/res/values-ka/translations.xml
new file mode 100644
index 0000000000..fd0bc2c832
--- /dev/null
+++ b/libraries/ui-strings/src/main/res/values-ka/translations.xml
@@ -0,0 +1,221 @@
+
+
+ "წაშლა"
+
+ - "%1$d ციფრი ჩაიწერა"
+ - "%1$d ციფრი ჩაიწერა"
+
+ "პაროლის დამალვა"
+ "მხოლოდ მოხსენიებები"
+ "დადუმებულია"
+ "პაუზა"
+ "PIN ველი"
+ "დაკვრა"
+ "გამოკითხვა"
+ "დასრულდა გამოკითხვა"
+ "ფაილების გაგზავნა"
+ "პაროლის ჩვენება"
+ "მომხმარებლის მენიუ"
+ "ხმოვანი შეტყობინების ჩაწერა."
+ "მიღება"
+ "დამატება ქრონოლოგიაში"
+ "უკან"
+ "გაუქმება"
+ "აირჩიეთ ფოტო"
+ "გასუფთავება"
+ "დახურვა"
+ "დადასტურების დასრულება"
+ "დადასტურება"
+ "გაგრძელება"
+ "კოპირება"
+ "ბმულის კოპირება"
+ "დააკოპირეთ შეტყობინების ბმული"
+ "შექმნა"
+ "ოთახის შექმნა"
+ "უარყოფა"
+ "გამორთვა"
+ "მზადაა"
+ "რედაქტირება"
+ "გამოკითხვის რედაქტირება"
+ "გამოკითხვის დასრულება"
+ "დაგავიწყდათ პაროლი?"
+ "გადაგზავნა"
+ "მოწვევა"
+ "ხალხის მოწვევა"
+ "ადამიანების დამატება %1$s"
+ "%1$s-ში ხალხის მოწვევა"
+ "მოწვევები"
+ "გაწევრიანება"
+ "შეიტყვეთ მეტი"
+ "დატოვება"
+ "ოთახის დატოვება"
+ "ანგარიშის მართვა"
+ "მოწყობილობების მართვა"
+ "შემდეგი"
+ "არა"
+ "ახლა არა"
+ "OK"
+ "პარამეტრები"
+ "გახსნა პროგრამით:"
+ "Სწრაფი პასუხი"
+ "ციტირება"
+ "რეაგირება"
+ "წაშლა"
+ "პასუხი"
+ "პასუხი თემაში"
+ "ხარვეზის შეტყობინება"
+ "კონტენტის რეპორტი"
+ "ხელახლა ცდა"
+ "გაშიფვრის ხელახლა ცდა"
+ "შენახვა"
+ "ძიება"
+ "გაგზავნა"
+ "შეტყობინების გაგზავნა"
+ "გაზიარება"
+ "ბმულის გაზიარება"
+ "ხელახლა შედით"
+ "გამოსვლა"
+ "მაინც გასვლა"
+ "გამოტოვება"
+ "დაწყება"
+ "ჩატის დაწყება"
+ "დადასტურების დაწყება"
+ "დააწკაპუნეთ რუკის ჩასატვირთად"
+ "ფოტოს გადაღება"
+ "წყაროს ნახვა"
+ "დიახ"
+ "შესახებ"
+ "მისაღები გამოყენების პოლიტიკა"
+ "გაფართოებული პარამეტრები"
+ "ანალიტიკა"
+ "აუდიო"
+ "ბუშტები"
+ "ჩატის სარეზერვო ასლი"
+ "საავტორო უფლება"
+ "ოთახის შექმნა…"
+ "დატოვა ოთახი"
+ "გაშიფვრის შეცდომა"
+ "დეველოპერის პარამეტრები"
+ "(რედაქტირებულია)"
+ "რედაქტირება"
+ "* %1$s %2$s"
+ "დაშიფვრა ჩართულია"
+ "შეიყვანეთ თქვენი PIN"
+ "შეცდომა"
+ "ყველა"
+ "ფაილი"
+ "ფაილი შენახულია ჩამოტვირთვებში"
+ "შეტყობინების გადაგზავნა"
+ "GIF"
+ "სურათი"
+ "%1$s-ს პასუხად"
+ "დააინსტალირეთ APK"
+ "ეს Matrix ID ვერ მოიძებნა, ამიტომ მოწვევა შეიძლება არ იყოს მიღებული."
+ "ოთახის დატოვება"
+ "ბმული კოპირებულია გაცვლის ბუფერში"
+ "იტვირთება…"
+
+ - "%1$d წევრი"
+ - "%1$d წევრები"
+
+ "შეტყობინება"
+ "შეტყობინებების ფორმა"
+ "მესიჯი წაშლილია"
+ "თანამედროვე"
+ "დადუმება"
+ "შედეგი არ არის"
+ "ხაზგარეშე"
+ "პაროლი"
+ "ხალხი"
+ "მუდმივი ბმული"
+ "ნებართვა"
+ "დარწმუნებული ხართ, რომ გსურთ ამ გამოკითხვის დასრულება?"
+ "გამოკითხვა: %1$s"
+ "სულ ხმები: %1$s"
+ "შედეგები გამოკითხვის დასრულების შემდეგ გამოჩნდება"
+
+ - "%d ხმა"
+ - "%d ხმა"
+
+ "კონფიდენციალურობის პოლიტიკა"
+ "რეაქცია"
+ "რეაქციები"
+
+ "აღდგენის გასაღები"
+
+ "განახლება…"
+ "პასუხი %1$s-ს"
+ "ხარვეზის შეტყობინება"
+ "რეპორტი გაგზავნილია"
+ "მდიდარი ტექსტის რედაქტორი"
+ "ოთახის სახელი"
+ "მაგ. თქვენი პროექტის სახელი"
+ "ეკრანის დაბლოკვა"
+ "ვიღაცის ძებნა"
+ "ძიების შედეგები"
+ "უსაფრთხოება"
+ "იგზავნება…"
+ "სერვერი არ არის მხარდაჭერილი"
+ "სერვერის ვებ-მისამართი"
+ "პარამეტრები"
+ "გაზიარებული მდებარეობა"
+ "ჩატის დაწყება…"
+ "სტიკერი"
+ "წარმატება"
+ "შეთავაზებები"
+ "სინქრონიზაცია"
+ "ტექსტი"
+ "მესამე პირის შენიშვნები"
+ "თემა"
+ "თემა"
+ "რა თემებს ეხება ეს ოთახი?"
+ "გაშიფვრა ვერ მოხერხდა"
+ "მოსაწვევები ვერ გაეგზავნა ერთ ან მეტ მომხმარებელს."
+ "მოწვევის (ების) გაგზავნა შეუძლებელია"
+ "განბლოკვა"
+ "დადუმების გაუქმება"
+ "მხარდაუჭერელი მოვლენა"
+ "მომხმარებლის სახელი"
+ "დადასტურება გაუქმდა"
+ "დადასტურება დასრულებულია"
+ "ვიდეო"
+ "ხმოვანი შეტყობინება"
+ "მოცდა…"
+ "დადასტურება"
+ "შეცდომა"
+ "წარმატება"
+ "გაფრთხილება"
+ "მუდმივი ბმულის შექმნა ვერ მოხერხდა"
+ "ვერ გამოვიდა რუკის %1$s ჩატვირთვა. გთხოვთ, მოგვიანებით სცადოთ."
+ "შეტყობინებების ჩატვირთვა ვერ მოხერხდა"
+ "%1$s ვერ მოახერხა თქვენი ადგილმდებარეობაზე წვდომა. გთხოვთ, მოგვიანებით სცადოთ."
+ "%1$s არ აქვს თქვენს ადგილმდებარეობაზე წვდომის ნებართვა. შეგიძლიათ ჩართოთ წვდომა პარამეტრებში."
+ "%1$s არ აქვს თქვენს ადგილმდებარეობაზე წვდომის ნებართვა. ჩართეთ წვდომა ქვემოთ"
+ "%1$s არ აქვს თქვენს მიკროფონზე წვდომის ნებართვა. ჩართეთ წვდომა ხმოვანი შეტყობინების ჩასაწერად."
+ "ზოგიერთი შეტყობინება არ გაიგზავნა"
+ "ბოდიშით, შეცდომა მოხდა"
+ "🔐️ შემომიერთდით %1$s"
+ "გაგიმარჯოს! მესაუბრე %1$s-ზე: %2$s"
+ "%1$s Android"
+ "შეცდომის შესატყობინებლად ტელეფონის შენჯღრევა"
+ "მედიის შერჩევა ვერ მოხერხდა, გთხოვთ, სცადოთ ხელახლა."
+ "მედიის ატვირთვა ვერ მოხერხდა. გთხოვთ, სცადოთ ხელახლა."
+ "მედიის ატვირთვა ვერ მოხერხდა, გთხოვთ, სცადოთ ხელახლა."
+ "მედიის ატვირთვა ვერ მოხერხდა. გთხოვთ, სცადოთ ხელახლა."
+ "მომხმარებლის მონაცემების მოძიება ვერ მოხერხდა"
+ "დაბლოკვა"
+ "დაბლოკილი მომხმარებლები ვერ შეძლებენ თქვენთვის შეტყობინების გაგზავნას და ყველა მათი შეტყობინება თქვენთვის დამალული იქნება. თქვენ მათი განბლოკვა ნებისმეირ დროს შეგიძლიათ."
+ "მომხმარებლის დაბლოკვა"
+ "განბლოკვა"
+ "თქვენ კვლავ შეძლებთ მათგან ყველა შეტყობინების ნახვას."
+ "Მომხმარებლის განბლოკვა"
+ "მდებარეობის გაზიარება"
+ "ჩემი მდებარეობის გაზიარება"
+ "Apple Maps-ში გახსნა"
+ "Google Maps-ში გახსნა"
+ "OpenStreetMap-ში გახსნა"
+ "ამ ადგილის გაზიარება"
+ "ადგილმდებარეობა"
+ "ვერსია: %1$s (%2$s)"
+ "ka"
+
diff --git a/libraries/ui-strings/src/main/res/values-pt/translations.xml b/libraries/ui-strings/src/main/res/values-pt/translations.xml
new file mode 100644
index 0000000000..072602a5da
--- /dev/null
+++ b/libraries/ui-strings/src/main/res/values-pt/translations.xml
@@ -0,0 +1,277 @@
+
+
+ "Eliminar"
+
+ - "%1$d dígito inserido"
+ - "%1$d dígitos inseridos"
+
+ "Ocultar senha"
+ "Saltar para o fundo"
+ "Apenas menções"
+ "Silenciado"
+ "Página %1$d"
+ "Pausar"
+ "Campo para PIN"
+ "Reproduzir"
+ "Sondagem"
+ "Sondagem concluída"
+ "Reagir com %1$s"
+ "Reagir com outros emojis"
+ "Lida por %1$s e %2$s"
+
+ - "Lida por %1$s e %2$d outro"
+ - "Lida por %1$s e %2$d outros"
+
+ "Lida por %1$s"
+ "Toque para mostrar tudo"
+ "Remover reação com %1$s"
+ "Enviar ficheiros"
+ "Mostrar senha"
+ "Iniciar chamada"
+ "Menu de utilizador"
+ "Gravar mensagem de voz."
+ "Parar gravação"
+ "Aceitar"
+ "Adicionar à cronologia"
+ "Voltar"
+ "Chamar"
+ "Cancelar"
+ "Escolher foto"
+ "Limpar"
+ "Fechar"
+ "Concluir verificação"
+ "Confirmar"
+ "Continuar"
+ "Copiar"
+ "Copiar ligação"
+ "Copiar ligação da mensagem"
+ "Criar"
+ "Criar uma sala"
+ "Rejeitar"
+ "Eliminar sondagem"
+ "Desativar"
+ "Descartar"
+ "Feito"
+ "Editar"
+ "Editar sondagem"
+ "Ativar"
+ "Fim da sondagem"
+ "Inserir PIN"
+ "Esqueceu-se da senha?"
+ "Reencaminhar"
+ "Voltar"
+ "Convidar"
+ "Convidar pessoas"
+ "Convidar amigos para %1$s"
+ "Convida pessoas para a %1$s"
+ "Convites"
+ "Entrar"
+ "Saber mais"
+ "Sair"
+ "Sair da conversa"
+ "Sair da sala"
+ "Carrega mais"
+ "Gerir conta"
+ "Gerir dispositivos"
+ "Enviar mensagem"
+ "Próximo"
+ "Não"
+ "Agora não"
+ "OK"
+ "Configurações"
+ "Abrir com"
+ "Resposta rápida"
+ "Citação"
+ "Reagir"
+ "Remover"
+ "Responder"
+ "Responder ao tópico"
+ "Comunicar problema"
+ "Denunciar conteúdo"
+ "Repor"
+ "Tentar novamente"
+ "Tentar decifragem novamente"
+ "Guardar"
+ "Pesquisar"
+ "Enviar"
+ "Enviar mensagem"
+ "Partilhar"
+ "Partilhar ligação"
+ "Inicia sessão novamente"
+ "Terminar sessão"
+ "Terminar mesmo assim"
+ "Saltar"
+ "Iniciar"
+ "Iniciar conversa"
+ "Iniciar verificação"
+ "Toque para carregar o mapa"
+ "Tirar foto"
+ "Toca para ver as opções"
+ "Tentar novamente"
+ "Ver fonte"
+ "Sim"
+ "Sobre"
+ "Política de utilização aceitável"
+ "Configurações avançadas"
+ "Recolha e análise de dados"
+ "Aparência"
+ "Áudio"
+ "Utilizadores bloqueados"
+ "Bolhas"
+ "Chamada em curso (não suportada)"
+ "Cópia de segurança das conversas"
+ "Direitos de autor"
+ "A criar sala…"
+ "Saíste da sala"
+ "Escuro"
+ "Erro de decifragem"
+ "Opções de programador"
+ "Conversa direta"
+ "(editada)"
+ "A editar"
+ "* %1$s %2$s"
+ "Cifragem ativada"
+ "Introduz o teu PIN"
+ "Erro"
+ "Toda a gente"
+ "Falha"
+ "Marcar como favorita"
+ "Favoritas"
+ "Ficheiro"
+ "Ficheiro guardado nas Transferências"
+ "Reencaminhar mensagem"
+ "GIF"
+ "Imagem"
+ "Em resposta a %1$s"
+ "Instalar APK"
+ "Não foi possível encontrar este ID Matrix, portanto o convite pode não ser recebido."
+ "A sair da sala"
+ "Claro"
+ "Ligação copiada para a área de transferência"
+ "A carregar…"
+
+ - "%1$d membro"
+ - "%1$d membros"
+
+ "Mensagem"
+ "Ações de mensagem"
+ "Disposição das mensagens"
+ "Mensagem removida"
+ "Moderno"
+ "Silenciar"
+ "Sem resultados"
+ "Sala sem nome"
+ "Desligado"
+ "ou"
+ "Senha"
+ "Pessoas"
+ "Ligação permanente"
+ "Permissão"
+ "Por favor, aguarda…"
+ "Tens a certeza que queres concluir esta sondagem?"
+ "Sondagem: %1$s"
+ "Total de votos: %1$s"
+ "Os resultados serão apresentados após o fim da sondagem"
+
+ - "%d voto"
+ - "%d votos"
+
+ "Política de privacidade"
+ "Reação"
+ "Reações"
+ "Chave de recuperação"
+ "A atualizar…"
+ "Em resposta a %1$s"
+ "Comunicar falha"
+ "Comunicar um problema"
+ "Denúncia submetida"
+ "Editor de texto rico"
+ "Sala"
+ "Nome da sala"
+ "p.ex. o nome do teu projeto"
+ "Alterações guardadas"
+ "A guardar"
+ "Bloqueio do ecrã"
+ "Pesquisar por alguém"
+ "Resultados da pesquisa"
+ "Segurança"
+ "Vista por"
+ "A enviar…"
+ "Falha no envio"
+ "Enviada"
+ "Servidor não suportado"
+ "URL do servidor"
+ "Configurações"
+ "Localização partilhada"
+ "A terminar sessão"
+ "Algo correu mal"
+ "A iniciar conversa…"
+ "Autocolante"
+ "Sucesso"
+ "Sugestões"
+ "A sincronizar…"
+ "Sistema"
+ "Texto"
+ "Avisos de terceiros"
+ "Tópico"
+ "Descrição"
+ "Sobre o que é esta sala?"
+ "Incapaz de decifrar"
+ "Não tens acesso a esta mensagem"
+ "Não foi possível enviar convites a um ou mais utilizadores."
+ "Não foi possível enviar convite(s)"
+ "Desbloquear"
+ "Dessilenciar"
+ "Evento não suportado"
+ "Nome de utilizador"
+ "Verificação cancelada"
+ "Verificação concluída"
+ "Verificar o dispositivo"
+ "Vídeo"
+ "Mensagem de voz"
+ "A aguardar…"
+ "À espera desta mensagem"
+ "Confirmação"
+ "Erro"
+ "Sucesso"
+ "Aviso"
+ "As tuas alterações não foram guardadas. Tens a certeza que queres voltar atrás?"
+ "Guardar alterações?"
+ "Falha ao criar ligação permanente"
+ "%1$s não foi possível carregar o mapa. Por favor, tente novamente mais tarde."
+ "Falha ao carregar mensagens"
+ "A %1$s não conseguiu aceder à tua localização. Por favor, tenta novamente mais tarde."
+ "Falha ao carregar mensagem de voz."
+ "Mensagem não encontrada"
+ "A %1$s não tem permissão para aceder à tua localização. Podes ativar o acesso nas Definições."
+ "A %1$s não tem permissão para aceder à tua localização. Ativa o acesso abaixo."
+ "A %1$s não tem permissão para aceder ao teu microfone. Permite o acesso para gravar uma mensagem de voz."
+ "Algumas mensagens não foram enviadas"
+ "Ocorreu um erro, desculpa"
+ "🔐️ Junta-te a mim na %1$s"
+ "Alô! Fala comigo na %1$s: %2$s"
+ "%1$s Android"
+ "Agita o dispositivo em fúria para comunicar um problema"
+ "Falha ao selecionar multimédia, por favor tente novamente."
+ "Falha ao processar multimédia para carregamento, por favor tente novamente."
+ "Falhar ao carregar multimédia, por favor tente novamente."
+ "Falha ao processar multimédia para carregamento, por favor tente novamente."
+ "Não foi possível obter os detalhes de utilizador."
+ "Bloquear"
+ "Os utilizadores bloqueados não poderão enviar-te mensagens e todas as suas mensagens ficarão ocultas. Podes desbloqueá-los em qualquer altura."
+ "Bloquear utilizador"
+ "Perfil"
+ "Desbloquear"
+ "Poderás voltar a ver todas as suas mensagens."
+ "Desbloquear utilizador"
+ "Conversa"
+ "Partilhar localização"
+ "Partilhar a minha localização"
+ "Abrir no Apple Maps"
+ "Abrir no Google Maps"
+ "Abrir no OpenStreetMap"
+ "Partilhar este local"
+ "Localização"
+ "Versão: %1$s (%2$s)"
+ "pt"
+
diff --git a/libraries/ui-strings/src/main/res/values-ro/translations.xml b/libraries/ui-strings/src/main/res/values-ro/translations.xml
index 073dd20f4b..a4c0eb8bfe 100644
--- a/libraries/ui-strings/src/main/res/values-ro/translations.xml
+++ b/libraries/ui-strings/src/main/res/values-ro/translations.xml
@@ -36,6 +36,7 @@
"Acceptați"
"Adăugați conversației"
"Înapoi"
+ "Apel"
"Anulați"
"Alegeți o fotografie"
"Ștergeți"
@@ -51,6 +52,7 @@
"Refuzați"
"Ștergeți sondajul"
"Dezactivați"
+ "Renunţare"
"Efectuat"
"Editați"
"Editați sondajul"
@@ -59,6 +61,7 @@
"Introduceți PIN-ul"
"Ați uitat parola?"
"Redirecționați"
+ "Înapoi"
"Invitați"
"Invitați prieteni"
"Invitați prieteni în %1$s"
@@ -72,6 +75,7 @@
"Încărcați mai mult"
"Administrare cont"
"Gestionare dispozitive"
+ "Mesaj"
"Următorul"
"Nu"
"Nu acum"
@@ -86,6 +90,7 @@
"Răspundeți în fir"
"Raportați o eroare"
"Raportați conținutul"
+ "Resetare"
"Reîncercați"
"Reîncercați decriptarea"
"Salvați"
@@ -113,7 +118,9 @@
"Analitice"
"Aspect"
"Audio"
+ "Utilizatori blocați"
"Baloane"
+ "Apel în curs (nesuportat)"
"Backup conversații"
"Drepturi de autor"
"Se creează camera…"
@@ -129,6 +136,7 @@
"Introduceți codul PIN"
"Eroare"
"Toți"
+ "Eșuat"
"Favorite"
"Favorită"
"Fişier"
@@ -155,11 +163,14 @@
"Modern"
"Dezactivați sunetul"
"Niciun rezultat"
+ "Fără nume de cameră"
"Deconectat"
+ "sau"
"Parola"
"Persoane"
"Permalink"
"Permisiune"
+ "Va rugam asteptati…"
"Sunteți sigur că doriți să încheiați acest sondaj?"
"Sondajul %1$s"
"Total voturi: %1$s"
@@ -182,6 +193,8 @@
"Cameră"
"Numele camerei"
"de exemplu, numele proiectului dvs."
+ "Modificări salvate"
+ "Se salvează…"
"Blocare ecran"
"Căutați pe cineva"
"Rezultatele căutării"
@@ -195,6 +208,7 @@
"Setări"
"Locație partajată"
"Deconectare în curs"
+ "Ceva nu a mers bine"
"Se începe conversația…"
"Autocolant"
"Succes"
@@ -207,6 +221,7 @@
"Subiect"
"Despre ce este vorba în această cameră?"
"Nu s-a putut decripta"
+ "Nu aveți acces la acest mesaj"
"Nu am putut trimite invitații unuia sau mai multor utilizatori."
"Nu s-a putut trimite invitația (invitațiile)"
"Deblocare"
@@ -224,11 +239,14 @@
"Eroare"
"Succes"
"Avertisment"
+ "Modificările dumneavoastră nu au fost salvate. Sunteți sigur că doriți să vă întoarceți?"
+ "Salvați modificările?"
"Crearea permalink-ului a eșuat"
"%1$s nu a putut încărca harta. Vă rugăm să încercați din nou mai târziu."
"Încărcarea mesajelor a eșuat"
"%1$s nu a putut accesa locația dumneavoastră. Vă rugăm să încercați din nou mai târziu."
"Trimiterea mesajului vocal nu a reușit."
+ "Mesajul nu a fost găsit"
"%1$s nu are permisiuni pentru a accesa locația dumneavoastră. Puteți permite accesul în Setări."
"%1$s nu are permisiuni pentru a accesa locația dumneavoastră. Permiteți accesul mai jos."
"%1$s nu are permisiunea de a vă accesa microfonul. Permiteți accesul pentru a înregistra un mesaj vocal."
@@ -246,9 +264,11 @@
"Blocați"
"Utilizatorii blocați nu vă vor putea trimite mesaje și toate mesajele lor vor fi ascunse. Puteți anula această acțiune oricând."
"Blocați utilizatorul"
+ "Profil"
"Deblocați"
"La deblocarea utilizatorului, veți putea vedea din nou toate mesajele de la acesta."
"Deblocați utilizatorul"
+ "Chat"
"Partajați locația"
"Distribuiți locația mea"
"Deschideți în Apple Maps"
diff --git a/libraries/ui-strings/src/main/res/values-ru/translations.xml b/libraries/ui-strings/src/main/res/values-ru/translations.xml
index 0634590b92..1932b987ae 100644
--- a/libraries/ui-strings/src/main/res/values-ru/translations.xml
+++ b/libraries/ui-strings/src/main/res/values-ru/translations.xml
@@ -36,6 +36,7 @@
"Разрешить"
"Добавить в хронологию"
"Назад"
+ "Позвонить"
"Отмена"
"Выбрать фото"
"Очистить"
@@ -161,12 +162,14 @@
"Современный"
"Без звука"
"Ничего не найдено"
+ "Нету названия комнаты"
"Не в сети"
"или"
"Пароль"
"Люди"
"Постоянная ссылка"
"Разрешение"
+ "Подождите…"
"Вы действительно хотите завершить данный опрос?"
"Опрос: %1$s"
"Всего голосов: %1$s"
@@ -219,6 +222,7 @@
"Тема"
"О чем эта комната?"
"Невозможно расшифровать"
+ "Вы не имеете доступа к этому сообщению"
"Не удалось отправить приглашения одному или нескольким пользователям."
"Не удалось отправить приглашение(я)"
"Разблокировать"
@@ -243,6 +247,7 @@
"Не удалось загрузить сообщения"
"%1$s не удалось получить доступ к вашему местоположению. Пожалуйста, повторите попытку позже."
"Не удалось загрузить голосовое сообщение."
+ "Сообщение не найдено"
"У %1$s нет разрешения на доступ к вашему местоположению. Вы можете разрешить доступ в Настройках."
"У %1$s нет разрешения на доступ к вашему местоположению. Разрешите доступ ниже."
"%1$s не имеет разрешения на доступ к вашему микрофону. Разрешите доступ к записи голосового сообщения."
@@ -264,6 +269,7 @@
"Разблокировать"
"Вы снова сможете увидеть все сообщения."
"Разблокировать пользователя"
+ "Чат"
"Поделиться местоположением"
"Поделиться моим местоположением"
"Открыть в Apple Maps"
diff --git a/libraries/ui-strings/src/main/res/values-sk/translations.xml b/libraries/ui-strings/src/main/res/values-sk/translations.xml
index dbe16b1868..d9afe4ba65 100644
--- a/libraries/ui-strings/src/main/res/values-sk/translations.xml
+++ b/libraries/ui-strings/src/main/res/values-sk/translations.xml
@@ -36,6 +36,7 @@
"Prijať"
"Pridať na časovú os"
"Späť"
+ "Zavolať"
"Zrušiť"
"Vybrať fotku"
"Vyčistiť"
@@ -74,6 +75,7 @@
"Načítať viac"
"Spravovať účet"
"Spravovať zariadenia"
+ "Poslať správu"
"Ďalej"
"Nie"
"Teraz nie"
@@ -119,6 +121,7 @@
"Blokovaní používatelia"
"Bubliny"
"Prebieha hovor (nepodporované)"
+ "Hovor sa začal"
"Záloha konverzácie"
"Autorské práva"
"Vytváranie miestnosti…"
@@ -136,6 +139,7 @@
"Všetci"
"Zlyhalo"
"Obľúbené"
+ "Obľúbené"
"Súbor"
"Súbor bol uložený do priečinka Stiahnuté súbory"
"Preposlať správu"
diff --git a/libraries/ui-strings/src/main/res/values-zh/translations.xml b/libraries/ui-strings/src/main/res/values-zh/translations.xml
new file mode 100644
index 0000000000..ded718fcec
--- /dev/null
+++ b/libraries/ui-strings/src/main/res/values-zh/translations.xml
@@ -0,0 +1,271 @@
+
+
+ "删除"
+
+ - "已输入 %1$d 个数字"
+
+ "隐藏密码"
+ "跳转到底部"
+ "仅提及"
+ "关闭通知"
+ "第 %1$d 页"
+ "暂停"
+ "PIN 栏位"
+ "播放"
+ "投票"
+ "投票已结束"
+ "使用 %1$s 回应"
+ "使用其他表情符号回应"
+ "%1$s 和 %2$s 已读"
+
+ - "%1$s 及其他 %2$d 人已读"
+
+ "%1$s 已读"
+ "点击以显示全部"
+ "撤回反应 %1$s"
+ "发送文件"
+ "显示密码"
+ "开始通话"
+ "用户菜单"
+ "录制语音消息。"
+ "停止录制"
+ "接受"
+ "添加到时间线"
+ "返回"
+ "取消"
+ "选择照片"
+ "清除"
+ "关闭"
+ "完成验证"
+ "确认"
+ "继续"
+ "复制"
+ "复制链接"
+ "复制消息链接"
+ "创建"
+ "创建房间"
+ "拒绝"
+ "删除投票"
+ "停用"
+ "丢弃"
+ "完成"
+ "编辑"
+ "编辑投票"
+ "启用"
+ "结束投票"
+ "输入 PIN"
+ "忘记密码?"
+ "转发"
+ "返回"
+ "邀请"
+ "邀请朋友"
+ "邀请朋友加入 %1$s"
+ "邀请人们加入 %1$s"
+ "邀请"
+ "加入"
+ "了解更多"
+ "离开"
+ "离开聊天"
+ "离开房间"
+ "载入更多"
+ "管理账户"
+ "管理设备"
+ "下一步"
+ "否"
+ "以后再说"
+ "好"
+ "打开设置"
+ "用其他方式打开"
+ "快速回复"
+ "引用"
+ "回应"
+ "移除"
+ "回复"
+ "在消息列中回复"
+ "报告错误"
+ "举报内容"
+ "重置"
+ "重试"
+ "重试解密"
+ "保存"
+ "搜索"
+ "发送"
+ "发送消息"
+ "分享"
+ "分享链接"
+ "再次登录"
+ "登出"
+ "仍然登出"
+ "跳过"
+ "开始"
+ "开始聊天"
+ "开始验证"
+ "点击以加载地图"
+ "拍摄照片"
+ "点按查看选项"
+ "再试一次"
+ "查看来源"
+ "是"
+ "关于"
+ "可接受的使用政策"
+ "高级设置"
+ "分析"
+ "外观"
+ "音频"
+ "已屏蔽用户"
+ "气泡"
+ "通话进行中(不支持)"
+ "聊天记录备份"
+ "版权"
+ "正在创建房间…"
+ "离开房间"
+ "暗色"
+ "解密错误"
+ "开发者选项"
+ "私聊"
+ "(已编辑)"
+ "编辑中"
+ "* %1$s %2$s"
+ "已启用加密"
+ "输入 PIN 码"
+ "错误"
+ "所有人"
+ "失败"
+ "收藏"
+ "已收藏"
+ "文件"
+ "文件已保存到“下载”"
+ "转发消息"
+ "GIF"
+ "图片"
+ "回复 %1$s"
+ "安装 APK"
+ "找不到此 Matrix ID,因此可能无法收到邀请。"
+ "正在离开房间"
+ "浅色"
+ "链接已复制到剪贴板"
+ "正在加载…"
+
+ - "%1$d个成员"
+
+ "消息"
+ "消息操作"
+ "消息布局"
+ "消息已移除"
+ "现代"
+ "静音"
+ "没有结果"
+ "无房间名"
+ "离线"
+ "或"
+ "密码"
+ "人"
+ "固定链接"
+ "权限"
+ "请稍候……"
+ "你确定要结束这个投票吗?"
+ "投票:%1$s"
+ "总票数: %1$s"
+ "结果将在投票结束后显示"
+
+ - "%d 票"
+
+ "隐私政策"
+ "回应"
+ "回应"
+ "恢复密钥"
+ "正在刷新…"
+ "正在回复 %1$s"
+ "报告错误"
+ "报告问题"
+ "报告已提交"
+ "富文本编辑器"
+ "房间"
+ "房间名称"
+ "例如:你的项目名称"
+ "保存的更改"
+ "正在保存"
+ "屏幕锁定"
+ "搜索某人"
+ "搜索结果"
+ "安全"
+ "已读"
+ "正在发送…"
+ "发送失败"
+ "已发送"
+ "服务器不支持"
+ "服务器 URL"
+ "设置"
+ "共享位置"
+ "正在登出"
+ "发生了一些错误"
+ "开始聊天…"
+ "贴纸"
+ "成功"
+ "建议"
+ "正在同步"
+ "系统"
+ "文本"
+ "第三方通知"
+ "消息列"
+ "话题"
+ "这个房间是关于什么的?"
+ "无法解密"
+ "你无权访问此消息"
+ "无法向一个或多个用户发送邀请。"
+ "无法发送邀请"
+ "解锁"
+ "解除静音"
+ "不支持的事件"
+ "用户名"
+ "验证已取消"
+ "验证完成"
+ "验证设备"
+ "视频"
+ "语音留言"
+ "等待…"
+ "正在等待解密密钥"
+ "确认"
+ "错误"
+ "成功"
+ "警告"
+ "您的更改尚未保存。确定要返回吗?"
+ "保存更改?"
+ "创建固定链接失败"
+ "%1$s 无法加载地图,请稍后再试。"
+ "加载消息失败"
+ "%1$s 无法访问您的位置,请稍后再试。"
+ "无法上传你的语音留言。"
+ "找不到消息"
+ "%1$s 没有权限访问您的位置。您可以在设置中启用位置权限。"
+ "%1$s 没有权限访问您的位置。在下方启用位置权限。"
+ "%1$s 没有权限访问您的麦克风。启用录制语音消息的权限。"
+ "某些信息尚未发送"
+ "抱歉,发生了错误"
+ "🔐️ 加入我 %1$s"
+ "嗨!请通过 %1$s 与我联系:%2$s"
+ "%1$s Android"
+ "摇一摇以报错"
+ "选择媒体失败,请重试。"
+ "处理要上传的媒体失败,请重试。"
+ "上传媒体失败,请重试。"
+ "处理要上传的媒体失败,请重试。"
+ "无法获取用户信息"
+ "封禁"
+ "被封禁的用户无法给你发消息,并且他们的消息会被隐藏。你可以随时解封。"
+ "封禁用户"
+ "个人资料"
+ "解封"
+ "你可以重新接收他们的消息。"
+ "解封用户"
+ "聊天"
+ "分享位置"
+ "分享我的位置"
+ "在 Apple Maps 中打开"
+ "在 Google Maps 中打开"
+ "在 OpenStreetMap 中打开"
+ "分享这个位置"
+ "位置"
+ "版本:%1$s (%2$s)"
+ "zh-Hans"
+
diff --git a/libraries/ui-strings/src/main/res/values/localazy.xml b/libraries/ui-strings/src/main/res/values/localazy.xml
index e667873318..8d46b6e5b1 100644
--- a/libraries/ui-strings/src/main/res/values/localazy.xml
+++ b/libraries/ui-strings/src/main/res/values/localazy.xml
@@ -119,6 +119,7 @@
"Blocked users"
"Bubbles"
"Call in progress (unsupported)"
+ "Call started"
"Chat backup"
"Copyright"
"Creating room…"
diff --git a/plugins/src/main/kotlin/Versions.kt b/plugins/src/main/kotlin/Versions.kt
index a44140f9b2..75461d217f 100644
--- a/plugins/src/main/kotlin/Versions.kt
+++ b/plugins/src/main/kotlin/Versions.kt
@@ -56,7 +56,7 @@ private const val versionMinor = 4
// Note: even values are reserved for regular release, odd values for hotfix release.
// When creating a hotfix, you should decrease the value, since the current value
// is the value for the next regular release.
-private const val versionPatch = 12
+private const val versionPatch = 13
object Versions {
val versionCode = 4_000_000 + versionMajor * 1_00_00 + versionMinor * 1_00 + versionPatch
diff --git a/plugins/src/main/kotlin/extension/KoverExtension.kt b/plugins/src/main/kotlin/extension/KoverExtension.kt
index e107291918..ff66d1d6c6 100644
--- a/plugins/src/main/kotlin/extension/KoverExtension.kt
+++ b/plugins/src/main/kotlin/extension/KoverExtension.kt
@@ -16,10 +16,24 @@
package extension
-import kotlinx.kover.gradle.plugin.dsl.KoverReportExtension
+import kotlinx.kover.gradle.plugin.dsl.AggregationType
+import kotlinx.kover.gradle.plugin.dsl.CoverageUnit
+import kotlinx.kover.gradle.plugin.dsl.GroupingEntityType
+import kotlinx.kover.gradle.plugin.dsl.KoverProjectExtension
+import kotlinx.kover.gradle.plugin.dsl.KoverVariantCreateConfig
import org.gradle.api.Action
import org.gradle.api.Project
+import org.gradle.configurationcache.extensions.capitalized
import org.gradle.kotlin.dsl.apply
+import org.gradle.kotlin.dsl.assign
+
+enum class KoverVariant(val variantName: String) {
+ Presenters("presenters"),
+ States("states"),
+ Views("views"),
+}
+
+val koverVariants = KoverVariant.values().map { it.variantName }
val localAarProjects = listOf(
":libraries:rustsdk",
@@ -44,160 +58,175 @@ val excludedKoverSubProjects = listOf(
":libraries:di",
) + localAarProjects
-private fun Project.koverReport(action: Action) {
- (this as org.gradle.api.plugins.ExtensionAware).extensions.configure("koverReport", action)
+private fun Project.kover(action: Action) {
+ (this as org.gradle.api.plugins.ExtensionAware).extensions.configure("kover", action)
}
fun Project.setupKover() {
+ // Create verify all task joining all existing verification tasks
+ task("koverVerifyAll") {
+ group = "verification"
+ description = "Verifies the code coverage of all subprojects."
+ val dependencies = listOf(":app:koverVerifyGplayDebug") + koverVariants.map { ":app:koverVerify${it.capitalized()}" }
+ dependsOn(dependencies)
+
+ }
// https://kotlin.github.io/kotlinx-kover/
// Run `./gradlew :app:koverHtmlReport` to get report at ./app/build/reports/kover
// Run `./gradlew :app:koverXmlReport` to get XML report
- koverReport {
- filters {
- excludes {
- classes(
- // Exclude generated classes.
- "*_ModuleKt",
- "anvil.hint.binding.io.element.*",
- "anvil.hint.merge.*",
- "anvil.hint.multibinding.io.element.*",
- "anvil.module.*",
- "com.airbnb.android.showkase*",
- "io.element.android.libraries.designsystem.showkase.*",
- "io.element.android.x.di.DaggerAppComponent*",
- "*_Factory",
- "*_Factory_Impl",
- "*_Factory$*",
- "*_Module",
- "*_Module$*",
- "*Module_Provides*",
- "Dagger*Component*",
- "*ComposableSingletons$*",
- "*_AssistedFactory_Impl*",
- "*BuildConfig",
- // Generated by Showkase
- "*Ioelementandroid*PreviewKt$*",
- "*Ioelementandroid*PreviewKt",
- // Other
- // We do not cover Nodes (normally covered by maestro, but code coverage is not computed with maestro)
- "*Node",
- "*Node$*",
- "*Presenter\$present\$*",
- // Forked from compose
- "io.element.android.libraries.designsystem.theme.components.bottomsheet.*",
- // Test presenter
- "io.element.android.features.leaveroom.fake.FakeLeaveRoomPresenter",
- )
- annotatedBy(
- "androidx.compose.ui.tooling.preview.Preview",
- "io.element.android.libraries.architecture.coverage.ExcludeFromCoverage",
- "io.element.android.libraries.designsystem.preview.PreviewsDayNight",
- "io.element.android.libraries.designsystem.preview.PreviewWithLargeHeight",
- )
+ kover {
+ reports {
+ filters {
+ excludes {
+ classes(
+ // Exclude generated classes.
+ "*_ModuleKt",
+ "anvil.hint.binding.io.element.*",
+ "anvil.hint.merge.*",
+ "anvil.hint.multibinding.io.element.*",
+ "anvil.module.*",
+ "com.airbnb.android.showkase*",
+ "io.element.android.libraries.designsystem.showkase.*",
+ "io.element.android.x.di.DaggerAppComponent*",
+ "*_Factory",
+ "*_Factory_Impl",
+ "*_Factory$*",
+ "*_Module",
+ "*_Module$*",
+ "*Module_Provides*",
+ "Dagger*Component*",
+ "*ComposableSingletons$*",
+ "*_AssistedFactory_Impl*",
+ "*BuildConfig",
+ // Generated by Showkase
+ "*Ioelementandroid*PreviewKt$*",
+ "*Ioelementandroid*PreviewKt",
+ // Other
+ // We do not cover Nodes (normally covered by maestro, but code coverage is not computed with maestro)
+ "*Node",
+ "*Node$*",
+ "*Presenter\$present\$*",
+ // Forked from compose
+ "io.element.android.libraries.designsystem.theme.components.bottomsheet.*",
+ // Test presenter
+ "io.element.android.features.leaveroom.fake.FakeLeaveRoomPresenter",
+ )
+ annotatedBy(
+ "androidx.compose.ui.tooling.preview.Preview",
+ "io.element.android.libraries.architecture.coverage.ExcludeFromCoverage",
+ "io.element.android.libraries.designsystem.preview.PreviewsDayNight",
+ "io.element.android.libraries.designsystem.preview.PreviewWithLargeHeight",
+ )
+ }
}
- }
- defaults {
- // add reports of both 'debug' and 'release' Android build variants to default reports
- mergeWith("gplayDebug")
+ total {
+ verify {
+ // General rule: minimum code coverage.
+ rule("Global minimum code coverage.") {
+ groupBy = GroupingEntityType.APPLICATION
+ bound {
+ minValue = 70
+ // Setting a max value, so that if coverage is bigger, it means that we have to change minValue.
+ // For instance if we have minValue = 20 and maxValue = 30, and current code coverage is now 31.32%, update
+ // minValue to 25 and maxValue to 35.
+ maxValue = 80
+ coverageUnits = CoverageUnit.INSTRUCTION
+ aggregationForGroup = AggregationType.COVERED_PERCENTAGE
+ }
+ }
+ }
+ }
+ variant(KoverVariant.Presenters.variantName) {
+ verify {
+ // Rule to ensure that coverage of Presenters is sufficient.
+ rule("Check code coverage of presenters") {
+ groupBy = GroupingEntityType.CLASS
- verify {
- onCheck = true
- // General rule: minimum code coverage.
- rule("Global minimum code coverage.") {
- isEnabled = true
- entity = kotlinx.kover.gradle.plugin.dsl.GroupingEntityType.APPLICATION
- bound {
- minValue = 70
- // Setting a max value, so that if coverage is bigger, it means that we have to change minValue.
- // For instance if we have minValue = 20 and maxValue = 30, and current code coverage is now 31.32%, update
- // minValue to 25 and maxValue to 35.
- maxValue = 80
- metric = kotlinx.kover.gradle.plugin.dsl.MetricType.INSTRUCTION
- aggregation = kotlinx.kover.gradle.plugin.dsl.AggregationType.COVERED_PERCENTAGE
+ bound {
+ minValue = 85
+ coverageUnits = CoverageUnit.INSTRUCTION
+ aggregationForGroup = AggregationType.COVERED_PERCENTAGE
+ }
}
}
- // Rule to ensure that coverage of Presenters is sufficient.
- rule("Check code coverage of presenters") {
- isEnabled = true
- entity = kotlinx.kover.gradle.plugin.dsl.GroupingEntityType.CLASS
- filters {
- includes {
- classes(
- "*Presenter",
- )
- }
- excludes {
- classes(
- "*Fake*Presenter",
- "io.element.android.appnav.loggedin.LoggedInPresenter$*",
- // Some options can't be tested at the moment
- "io.element.android.features.preferences.impl.developer.DeveloperSettingsPresenter$*",
- "*Presenter\$present\$*",
- )
- }
+ filters {
+ includes {
+ classes(
+ "*Presenter",
+ )
}
- bound {
- minValue = 85
- metric = kotlinx.kover.gradle.plugin.dsl.MetricType.INSTRUCTION
- aggregation = kotlinx.kover.gradle.plugin.dsl.AggregationType.COVERED_PERCENTAGE
+ excludes {
+ classes(
+ "*Fake*Presenter",
+ "io.element.android.appnav.loggedin.LoggedInPresenter$*",
+ // Some options can't be tested at the moment
+ "io.element.android.features.preferences.impl.developer.DeveloperSettingsPresenter$*",
+ "*Presenter\$present\$*",
+ )
}
}
- // Rule to ensure that coverage of States is sufficient.
- rule("Check code coverage of states") {
- isEnabled = true
- entity = kotlinx.kover.gradle.plugin.dsl.GroupingEntityType.CLASS
- filters {
- includes {
- classes(
- "^*State$",
- )
+ }
+ variant(KoverVariant.States.variantName) {
+ verify {
+ // Rule to ensure that coverage of States is sufficient.
+ rule("Check code coverage of states") {
+ groupBy = GroupingEntityType.CLASS
+ bound {
+ minValue = 90
+ coverageUnits = CoverageUnit.INSTRUCTION
+ aggregationForGroup = AggregationType.COVERED_PERCENTAGE
}
- excludes {
- classes(
- "io.element.android.appnav.root.RootNavState*",
- "io.element.android.libraries.matrix.api.timeline.item.event.OtherState$*",
- "io.element.android.libraries.matrix.api.timeline.item.event.EventSendState$*",
- "io.element.android.libraries.matrix.api.room.RoomMembershipState*",
- "io.element.android.libraries.matrix.api.room.MatrixRoomMembersState*",
- "io.element.android.libraries.push.impl.notifications.NotificationState*",
- "io.element.android.features.messages.impl.media.local.pdf.PdfViewerState",
- "io.element.android.features.messages.impl.media.local.LocalMediaViewState",
- "io.element.android.features.location.impl.map.MapState*",
- "io.element.android.libraries.matrix.api.timeline.item.event.LocalEventSendState*",
- "io.element.android.libraries.designsystem.swipe.SwipeableActionsState*",
- "io.element.android.features.messages.impl.timeline.components.ExpandableState*",
- "io.element.android.features.messages.impl.timeline.model.bubble.BubbleState*",
- "io.element.android.libraries.maplibre.compose.CameraPositionState*",
- "io.element.android.libraries.maplibre.compose.SaveableCameraPositionState",
- "io.element.android.libraries.maplibre.compose.SymbolState*",
- "io.element.android.features.ftue.api.state.*",
- "io.element.android.features.ftue.impl.welcome.state.*",
- )
- }
- }
- bound {
- minValue = 90
- metric = kotlinx.kover.gradle.plugin.dsl.MetricType.INSTRUCTION
- aggregation = kotlinx.kover.gradle.plugin.dsl.AggregationType.COVERED_PERCENTAGE
}
}
- // Rule to ensure that coverage of Views is sufficient (deactivated for now).
- rule("Check code coverage of views") {
- isEnabled = true
- entity = kotlinx.kover.gradle.plugin.dsl.GroupingEntityType.CLASS
- filters {
- includes {
- classes(
- "*ViewKt",
- )
+ filters {
+ includes {
+ classes(
+ "^*State$",
+ )
+ }
+ excludes {
+ classes(
+ "io.element.android.appnav.root.RootNavState*",
+ "io.element.android.libraries.matrix.api.timeline.item.event.OtherState$*",
+ "io.element.android.libraries.matrix.api.timeline.item.event.EventSendState$*",
+ "io.element.android.libraries.matrix.api.room.RoomMembershipState*",
+ "io.element.android.libraries.matrix.api.room.MatrixRoomMembersState*",
+ "io.element.android.libraries.push.impl.notifications.NotificationState*",
+ "io.element.android.features.messages.impl.media.local.pdf.PdfViewerState",
+ "io.element.android.features.messages.impl.media.local.LocalMediaViewState",
+ "io.element.android.features.location.impl.map.MapState*",
+ "io.element.android.libraries.matrix.api.timeline.item.event.LocalEventSendState*",
+ "io.element.android.libraries.designsystem.swipe.SwipeableActionsState*",
+ "io.element.android.features.messages.impl.timeline.components.ExpandableState*",
+ "io.element.android.features.messages.impl.timeline.model.bubble.BubbleState*",
+ "io.element.android.libraries.maplibre.compose.CameraPositionState*",
+ "io.element.android.libraries.maplibre.compose.SaveableCameraPositionState",
+ "io.element.android.libraries.maplibre.compose.SymbolState*",
+ "io.element.android.features.ftue.api.state.*",
+ "io.element.android.features.ftue.impl.welcome.state.*",
+ )
+ }
+ }
+ }
+ variant(KoverVariant.Views.variantName) {
+ verify {
+ // Rule to ensure that coverage of Views is sufficient (deactivated for now).
+ rule("Check code coverage of views") {
+ groupBy = GroupingEntityType.CLASS
+ bound {
+ // TODO Update this value, for now there are too many missing tests.
+ minValue = 0
+ coverageUnits = CoverageUnit.INSTRUCTION
+ aggregationForGroup = AggregationType.COVERED_PERCENTAGE
}
}
- bound {
- // TODO Update this value, for now there are too many missing tests.
- minValue = 0
- metric = kotlinx.kover.gradle.plugin.dsl.MetricType.INSTRUCTION
- aggregation = kotlinx.kover.gradle.plugin.dsl.AggregationType.COVERED_PERCENTAGE
+ }
+ filters {
+ includes {
+ classes(
+ "*ViewKt",
+ )
}
}
}
@@ -205,22 +234,37 @@ fun Project.setupKover() {
}
}
-fun Project.applyKoverPluginToAllSubProjects() = rootProject.allprojects {
+fun Project.applyKoverPluginToAllSubProjects() = rootProject.subprojects {
if (project.path !in localAarProjects) {
apply(plugin = "org.jetbrains.kotlinx.kover")
+ kover {
+ currentProject {
+ for (variant in koverVariants) {
+ createVariant(variant) {
+ defaultVariants()
+ }
+ }
+ }
+ }
}
}
+fun KoverVariantCreateConfig.defaultVariants() {
+ addWithDependencies("gplayDebug", "debug", optional = true)
+}
+
+fun Project.koverSubprojects() = project.rootProject.subprojects
+ .filter {
+ it.project.projectDir.resolve("build.gradle.kts").exists()
+ }
+ .map { it.path }
+ .sorted()
+ .filter {
+ it !in excludedKoverSubProjects
+ }
+
fun Project.koverDependencies() {
- project.rootProject.subprojects
- .filter {
- it.project.projectDir.resolve("build.gradle.kts").exists()
- }
- .map { it.path }
- .sorted()
- .filter {
- it !in excludedKoverSubProjects
- }
+ project.koverSubprojects()
.forEach {
// println("Add $it to kover")
dependencies.add("kover", project(it))
diff --git a/plugins/src/main/kotlin/extension/locales.kt b/plugins/src/main/kotlin/extension/locales.kt
index c384501a1b..4b5ae81f62 100644
--- a/plugins/src/main/kotlin/extension/locales.kt
+++ b/plugins/src/main/kotlin/extension/locales.kt
@@ -13,10 +13,13 @@ val locales = setOf(
"hu",
"in",
"it",
+ "ka",
+ "pt",
"ro",
"ru",
"sk",
"sv",
"uk",
+ "zh-rCN",
"zh-rTW",
)
diff --git a/samples/minimal/src/main/kotlin/io/element/android/samples/minimal/RoomListScreen.kt b/samples/minimal/src/main/kotlin/io/element/android/samples/minimal/RoomListScreen.kt
index b96adefb6e..7dc75904e3 100644
--- a/samples/minimal/src/main/kotlin/io/element/android/samples/minimal/RoomListScreen.kt
+++ b/samples/minimal/src/main/kotlin/io/element/android/samples/minimal/RoomListScreen.kt
@@ -50,6 +50,7 @@ import io.element.android.libraries.matrix.api.MatrixClient
import io.element.android.libraries.matrix.api.core.RoomId
import io.element.android.libraries.matrix.api.room.RoomMembershipObserver
import io.element.android.libraries.matrix.api.timeline.Timeline
+import io.element.android.libraries.matrix.impl.room.join.DefaultJoinRoom
import io.element.android.libraries.preferences.impl.store.DefaultSessionPreferencesStore
import io.element.android.libraries.push.test.notifications.FakeNotificationDrawerManager
import io.element.android.services.analytics.noop.NoopAnalyticsService
@@ -134,7 +135,7 @@ class RoomListScreen(
),
acceptDeclineInvitePresenter = AcceptDeclineInvitePresenter(
client = matrixClient,
- analyticsService = NoopAnalyticsService(),
+ joinRoom = DefaultJoinRoom(matrixClient, NoopAnalyticsService()),
notificationDrawerManager = FakeNotificationDrawerManager(),
),
analyticsService = NoopAnalyticsService(),
diff --git a/screenshots/de/ui_T_t[f.createroom.impl.configureroom_ConfigureRoomView_null_ConfigureRoomView-Day-3_4_null_0,NEXUS_5,1.0,de].png b/screenshots/de/ui_T_t[f.createroom.impl.configureroom_ConfigureRoomView_null_ConfigureRoomView-Day-3_4_null_0,NEXUS_5,1.0,de].png
index 0e055cf445..25d0af313c 100644
--- a/screenshots/de/ui_T_t[f.createroom.impl.configureroom_ConfigureRoomView_null_ConfigureRoomView-Day-3_4_null_0,NEXUS_5,1.0,de].png
+++ b/screenshots/de/ui_T_t[f.createroom.impl.configureroom_ConfigureRoomView_null_ConfigureRoomView-Day-3_4_null_0,NEXUS_5,1.0,de].png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:ffcf366468b3bd18beb357e567b8c08a026251fa4ebde55c768187e8ab1cab82
-size 73043
+oid sha256:e057c84c3ff17138cb7cac34144269152024f5610170c99ad986a98f49c40552
+size 72868
diff --git a/screenshots/de/ui_T_t[f.createroom.impl.configureroom_ConfigureRoomView_null_ConfigureRoomView-Day-3_4_null_1,NEXUS_5,1.0,de].png b/screenshots/de/ui_T_t[f.createroom.impl.configureroom_ConfigureRoomView_null_ConfigureRoomView-Day-3_4_null_1,NEXUS_5,1.0,de].png
index d1d3e8792e..cf2dac7462 100644
--- a/screenshots/de/ui_T_t[f.createroom.impl.configureroom_ConfigureRoomView_null_ConfigureRoomView-Day-3_4_null_1,NEXUS_5,1.0,de].png
+++ b/screenshots/de/ui_T_t[f.createroom.impl.configureroom_ConfigureRoomView_null_ConfigureRoomView-Day-3_4_null_1,NEXUS_5,1.0,de].png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:61719138545393e23dba65a3f8565eb910d371f23ac1df06117e39f1658d10b0
-size 91265
+oid sha256:e3191f1acd8afc30c0d9096001a895d22c9a880c12dac010a816eeb78f07a2a3
+size 93915
diff --git a/screenshots/de/ui_T_t[f.messages.impl.messagecomposer_AttachmentSourcePickerMenu_null_AttachmentSourcePickerMenu-Day-4_4_null,NEXUS_5,1.0,de].png b/screenshots/de/ui_T_t[f.messages.impl.messagecomposer_AttachmentSourcePickerMenu_null_AttachmentSourcePickerMenu-Day-4_4_null,NEXUS_5,1.0,de].png
index 23cd548932..c5a1a7aef7 100644
--- a/screenshots/de/ui_T_t[f.messages.impl.messagecomposer_AttachmentSourcePickerMenu_null_AttachmentSourcePickerMenu-Day-4_4_null,NEXUS_5,1.0,de].png
+++ b/screenshots/de/ui_T_t[f.messages.impl.messagecomposer_AttachmentSourcePickerMenu_null_AttachmentSourcePickerMenu-Day-4_4_null,NEXUS_5,1.0,de].png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:55d29ddf2d008605691182d209022ad9b126575e4d8054cbbc7fb913fa5ca80b
+oid sha256:8a743918144c0111aea2c3b6a9c4080341ba4c4410fe9575f7da1eb3305c8694
size 28714
diff --git a/screenshots/de/ui_T_t[f.messages.impl_MessagesView_null_MessagesView-Day-0_0_null_2,NEXUS_5,1.0,de].png b/screenshots/de/ui_T_t[f.messages.impl_MessagesView_null_MessagesView-Day-0_0_null_2,NEXUS_5,1.0,de].png
index 2d81633da6..e487f0747b 100644
--- a/screenshots/de/ui_T_t[f.messages.impl_MessagesView_null_MessagesView-Day-0_0_null_2,NEXUS_5,1.0,de].png
+++ b/screenshots/de/ui_T_t[f.messages.impl_MessagesView_null_MessagesView-Day-0_0_null_2,NEXUS_5,1.0,de].png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:5645e0f7662e3c46d522f0bc6df433f93f6bd3ea3d7209982f23fd6ffe9764ba
+oid sha256:6229dac8454f502045fd1b421c367c5f1d68fc5ce166e2b70f137f382822ecfe
size 30561
diff --git a/screenshots/de/ui_T_t[f.preferences.impl.root_PreferencesRootViewDark_null_PreferencesRootViewDark--1_1_null_0,NEXUS_5,1.0,de].png b/screenshots/de/ui_T_t[f.preferences.impl.root_PreferencesRootViewDark_null_PreferencesRootViewDark--1_1_null_0,NEXUS_5,1.0,de].png
index 0e49c40ccc..b31175d7cc 100644
--- a/screenshots/de/ui_T_t[f.preferences.impl.root_PreferencesRootViewDark_null_PreferencesRootViewDark--1_1_null_0,NEXUS_5,1.0,de].png
+++ b/screenshots/de/ui_T_t[f.preferences.impl.root_PreferencesRootViewDark_null_PreferencesRootViewDark--1_1_null_0,NEXUS_5,1.0,de].png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:23f2fc8ed789f22d63925e23ade89babed788e34fd6ff1c8dc08be3b66895833
-size 37976
+oid sha256:38fc12f883433fa7c4109d4cb4c0035cef5f8556d2bacbd9ba7605321f1bd55d
+size 38040
diff --git a/screenshots/de/ui_T_t[f.preferences.impl.root_PreferencesRootViewDark_null_PreferencesRootViewDark--1_1_null_1,NEXUS_5,1.0,de].png b/screenshots/de/ui_T_t[f.preferences.impl.root_PreferencesRootViewDark_null_PreferencesRootViewDark--1_1_null_1,NEXUS_5,1.0,de].png
index 52bdb05f22..18430704b8 100644
--- a/screenshots/de/ui_T_t[f.preferences.impl.root_PreferencesRootViewDark_null_PreferencesRootViewDark--1_1_null_1,NEXUS_5,1.0,de].png
+++ b/screenshots/de/ui_T_t[f.preferences.impl.root_PreferencesRootViewDark_null_PreferencesRootViewDark--1_1_null_1,NEXUS_5,1.0,de].png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:7773e3f5084a8d220874491b3a054dbf31fb009238f5449808e09b5116e4dd07
-size 37633
+oid sha256:a4021f85ec57a5189a6796311413001d38cc3f632705631d10cbf46d075894f7
+size 37685
diff --git a/screenshots/de/ui_T_t[f.preferences.impl.root_PreferencesRootViewLight_null_PreferencesRootViewLight--0_0_null_0,NEXUS_5,1.0,de].png b/screenshots/de/ui_T_t[f.preferences.impl.root_PreferencesRootViewLight_null_PreferencesRootViewLight--0_0_null_0,NEXUS_5,1.0,de].png
index f23ef4afd3..5c5716b7e5 100644
--- a/screenshots/de/ui_T_t[f.preferences.impl.root_PreferencesRootViewLight_null_PreferencesRootViewLight--0_0_null_0,NEXUS_5,1.0,de].png
+++ b/screenshots/de/ui_T_t[f.preferences.impl.root_PreferencesRootViewLight_null_PreferencesRootViewLight--0_0_null_0,NEXUS_5,1.0,de].png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:b54582b2e22a65ba2821dc235170643d958926f95d38352309c116d3ee2f7eb1
-size 39765
+oid sha256:10a80d6905f30856a4cedc9d40bad833448ab21ad29e6f64de17621b35f86a46
+size 39890
diff --git a/screenshots/de/ui_T_t[f.preferences.impl.root_PreferencesRootViewLight_null_PreferencesRootViewLight--0_0_null_1,NEXUS_5,1.0,de].png b/screenshots/de/ui_T_t[f.preferences.impl.root_PreferencesRootViewLight_null_PreferencesRootViewLight--0_0_null_1,NEXUS_5,1.0,de].png
index b45c5e1ddc..812144af07 100644
--- a/screenshots/de/ui_T_t[f.preferences.impl.root_PreferencesRootViewLight_null_PreferencesRootViewLight--0_0_null_1,NEXUS_5,1.0,de].png
+++ b/screenshots/de/ui_T_t[f.preferences.impl.root_PreferencesRootViewLight_null_PreferencesRootViewLight--0_0_null_1,NEXUS_5,1.0,de].png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:b365970794bf20e9b18885293fd9b200177790e197f988f2957ce66108ac3c53
-size 39713
+oid sha256:4fbe8fff63944f56d0d5eb80fde567c3568fc24e663a73e985f84aea2f99c40d
+size 39830
diff --git a/screenshots/de/ui_T_t[f.preferences.impl.user.editprofile_EditUserProfileView_null_EditUserProfileView-Day-10_11_null_0,NEXUS_5,1.0,de].png b/screenshots/de/ui_T_t[f.preferences.impl.user.editprofile_EditUserProfileView_null_EditUserProfileView-Day-10_11_null_0,NEXUS_5,1.0,de].png
index 43fd59dee8..360023cc74 100644
--- a/screenshots/de/ui_T_t[f.preferences.impl.user.editprofile_EditUserProfileView_null_EditUserProfileView-Day-10_11_null_0,NEXUS_5,1.0,de].png
+++ b/screenshots/de/ui_T_t[f.preferences.impl.user.editprofile_EditUserProfileView_null_EditUserProfileView-Day-10_11_null_0,NEXUS_5,1.0,de].png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:51cb6878ea970c2939954b67f81b83d7d9d9948788e80aa3d184b71f0be2b8ec
-size 24413
+oid sha256:4be75ffa81b04cb56ee0b706ac9fce2d8356059194ba23abc8c13cc91f082271
+size 24208
diff --git a/screenshots/de/ui_T_t[f.roomdetails.impl.edit_RoomDetailsEditView_null_RoomDetailsEditView-Day-0_0_null_0,NEXUS_5,1.0,de].png b/screenshots/de/ui_T_t[f.roomdetails.impl.edit_RoomDetailsEditView_null_RoomDetailsEditView-Day-0_0_null_0,NEXUS_5,1.0,de].png
deleted file mode 100644
index 6be3c1195a..0000000000
--- a/screenshots/de/ui_T_t[f.roomdetails.impl.edit_RoomDetailsEditView_null_RoomDetailsEditView-Day-0_0_null_0,NEXUS_5,1.0,de].png
+++ /dev/null
@@ -1,3 +0,0 @@
-version https://git-lfs.github.com/spec/v1
-oid sha256:9162e5a30a917ff54e92419134dce2b60d3e7f87f962a6a5fa2e4e7a8a7753be
-size 32360
diff --git a/screenshots/de/ui_T_t[f.roomdetails.impl.edit_RoomDetailsEditView_null_RoomDetailsEditView-Day-0_0_null_1,NEXUS_5,1.0,de].png b/screenshots/de/ui_T_t[f.roomdetails.impl.edit_RoomDetailsEditView_null_RoomDetailsEditView-Day-0_0_null_1,NEXUS_5,1.0,de].png
deleted file mode 100644
index 35cc7e98d3..0000000000
--- a/screenshots/de/ui_T_t[f.roomdetails.impl.edit_RoomDetailsEditView_null_RoomDetailsEditView-Day-0_0_null_1,NEXUS_5,1.0,de].png
+++ /dev/null
@@ -1,3 +0,0 @@
-version https://git-lfs.github.com/spec/v1
-oid sha256:81b9e5b8eee8dba6b4fb166c269509c77f19ab1be48ebe5a7d98982c81998605
-size 26495
diff --git a/screenshots/de/ui_T_t[f.roomdetails.impl.edit_RoomDetailsEditView_null_RoomDetailsEditView-Day-0_0_null_2,NEXUS_5,1.0,de].png b/screenshots/de/ui_T_t[f.roomdetails.impl.edit_RoomDetailsEditView_null_RoomDetailsEditView-Day-0_0_null_2,NEXUS_5,1.0,de].png
deleted file mode 100644
index 7676db9404..0000000000
--- a/screenshots/de/ui_T_t[f.roomdetails.impl.edit_RoomDetailsEditView_null_RoomDetailsEditView-Day-0_0_null_2,NEXUS_5,1.0,de].png
+++ /dev/null
@@ -1,3 +0,0 @@
-version https://git-lfs.github.com/spec/v1
-oid sha256:fa1b174d118d79076198174aa92bf4255f66c5de04638cf54f3b3e572cd253a5
-size 57738
diff --git a/screenshots/de/ui_T_t[f.roomdetails.impl.edit_RoomDetailsEditView_null_RoomDetailsEditView-Day-0_0_null_3,NEXUS_5,1.0,de].png b/screenshots/de/ui_T_t[f.roomdetails.impl.edit_RoomDetailsEditView_null_RoomDetailsEditView-Day-0_0_null_3,NEXUS_5,1.0,de].png
deleted file mode 100644
index 9567900a73..0000000000
--- a/screenshots/de/ui_T_t[f.roomdetails.impl.edit_RoomDetailsEditView_null_RoomDetailsEditView-Day-0_0_null_3,NEXUS_5,1.0,de].png
+++ /dev/null
@@ -1,3 +0,0 @@
-version https://git-lfs.github.com/spec/v1
-oid sha256:0705569901f8749d7cc59050361b1f8304a9f9007e0deccfd1cdddc8b36181cc
-size 32181
diff --git a/screenshots/de/ui_T_t[f.roomdetails.impl.edit_RoomDetailsEditView_null_RoomDetailsEditView-Day-0_0_null_4,NEXUS_5,1.0,de].png b/screenshots/de/ui_T_t[f.roomdetails.impl.edit_RoomDetailsEditView_null_RoomDetailsEditView-Day-0_0_null_4,NEXUS_5,1.0,de].png
deleted file mode 100644
index ed16ba5dc0..0000000000
--- a/screenshots/de/ui_T_t[f.roomdetails.impl.edit_RoomDetailsEditView_null_RoomDetailsEditView-Day-0_0_null_4,NEXUS_5,1.0,de].png
+++ /dev/null
@@ -1,3 +0,0 @@
-version https://git-lfs.github.com/spec/v1
-oid sha256:ce62ee39c676a2856c3c30d84b969ea69ee6e00b474e721dacadb9ba0e0bf387
-size 32163
diff --git a/screenshots/de/ui_T_t[f.roomdetails.impl.edit_RoomDetailsEditView_null_RoomDetailsEditView-Day-0_0_null_5,NEXUS_5,1.0,de].png b/screenshots/de/ui_T_t[f.roomdetails.impl.edit_RoomDetailsEditView_null_RoomDetailsEditView-Day-0_0_null_5,NEXUS_5,1.0,de].png
deleted file mode 100644
index 02ffa0dd9d..0000000000
--- a/screenshots/de/ui_T_t[f.roomdetails.impl.edit_RoomDetailsEditView_null_RoomDetailsEditView-Day-0_0_null_5,NEXUS_5,1.0,de].png
+++ /dev/null
@@ -1,3 +0,0 @@
-version https://git-lfs.github.com/spec/v1
-oid sha256:2dd3eda8c85591d3cd30359349a98463e4b6ea641e5719ff487bf516d26b4aa7
-size 29732
diff --git a/screenshots/de/ui_T_t[f.roomdetails.impl.edit_RoomDetailsEditView_null_RoomDetailsEditView-Day-0_0_null_6,NEXUS_5,1.0,de].png b/screenshots/de/ui_T_t[f.roomdetails.impl.edit_RoomDetailsEditView_null_RoomDetailsEditView-Day-0_0_null_6,NEXUS_5,1.0,de].png
deleted file mode 100644
index 04eab38e03..0000000000
--- a/screenshots/de/ui_T_t[f.roomdetails.impl.edit_RoomDetailsEditView_null_RoomDetailsEditView-Day-0_0_null_6,NEXUS_5,1.0,de].png
+++ /dev/null
@@ -1,3 +0,0 @@
-version https://git-lfs.github.com/spec/v1
-oid sha256:c18309e49d892529fac2a661016507dbcf519febb3668284932ce3be0abd03df
-size 33464
diff --git a/screenshots/de/ui_T_t[f.roomdetails.impl.edit_RoomDetailsEditView_null_RoomDetailsEditView-Day-3_3_null_0,NEXUS_5,1.0,de].png b/screenshots/de/ui_T_t[f.roomdetails.impl.edit_RoomDetailsEditView_null_RoomDetailsEditView-Day-3_3_null_0,NEXUS_5,1.0,de].png
new file mode 100644
index 0000000000..3a64cbc99c
--- /dev/null
+++ b/screenshots/de/ui_T_t[f.roomdetails.impl.edit_RoomDetailsEditView_null_RoomDetailsEditView-Day-3_3_null_0,NEXUS_5,1.0,de].png
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:d42dcfb1d5591b2ba0ce647a08c72341d7e109c95b5e05be19cfd3398c94300c
+size 32540
diff --git a/screenshots/de/ui_T_t[f.roomdetails.impl.edit_RoomDetailsEditView_null_RoomDetailsEditView-Day-3_3_null_1,NEXUS_5,1.0,de].png b/screenshots/de/ui_T_t[f.roomdetails.impl.edit_RoomDetailsEditView_null_RoomDetailsEditView-Day-3_3_null_1,NEXUS_5,1.0,de].png
new file mode 100644
index 0000000000..6fe4bdc557
--- /dev/null
+++ b/screenshots/de/ui_T_t[f.roomdetails.impl.edit_RoomDetailsEditView_null_RoomDetailsEditView-Day-3_3_null_1,NEXUS_5,1.0,de].png
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:6ef892752a07a8812c8b90602bce695aa7984168f7cf5dd016698bc6f80ec702
+size 26690
diff --git a/screenshots/de/ui_T_t[f.roomdetails.impl.edit_RoomDetailsEditView_null_RoomDetailsEditView-Day-3_3_null_2,NEXUS_5,1.0,de].png b/screenshots/de/ui_T_t[f.roomdetails.impl.edit_RoomDetailsEditView_null_RoomDetailsEditView-Day-3_3_null_2,NEXUS_5,1.0,de].png
new file mode 100644
index 0000000000..ff01fab07d
--- /dev/null
+++ b/screenshots/de/ui_T_t[f.roomdetails.impl.edit_RoomDetailsEditView_null_RoomDetailsEditView-Day-3_3_null_2,NEXUS_5,1.0,de].png
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:0878d5a3267115737f8b503f7d494e92671f8976a7db13832d4afa23d49b6c38
+size 33755
diff --git a/screenshots/de/ui_T_t[f.roomdetails.impl.edit_RoomDetailsEditView_null_RoomDetailsEditView-Day-3_3_null_3,NEXUS_5,1.0,de].png b/screenshots/de/ui_T_t[f.roomdetails.impl.edit_RoomDetailsEditView_null_RoomDetailsEditView-Day-3_3_null_3,NEXUS_5,1.0,de].png
new file mode 100644
index 0000000000..8efa2a2246
--- /dev/null
+++ b/screenshots/de/ui_T_t[f.roomdetails.impl.edit_RoomDetailsEditView_null_RoomDetailsEditView-Day-3_3_null_3,NEXUS_5,1.0,de].png
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:50bb996509baa3da88735e8a3316f136967f731763ec5cfd31de898f56cdc535
+size 57583
diff --git a/screenshots/de/ui_T_t[f.roomdetails.impl.edit_RoomDetailsEditView_null_RoomDetailsEditView-Day-3_3_null_4,NEXUS_5,1.0,de].png b/screenshots/de/ui_T_t[f.roomdetails.impl.edit_RoomDetailsEditView_null_RoomDetailsEditView-Day-3_3_null_4,NEXUS_5,1.0,de].png
new file mode 100644
index 0000000000..af9f8e9d93
--- /dev/null
+++ b/screenshots/de/ui_T_t[f.roomdetails.impl.edit_RoomDetailsEditView_null_RoomDetailsEditView-Day-3_3_null_4,NEXUS_5,1.0,de].png
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:69cf681b19f473129fe15b09045cd5a42d49469d718bf3ccc32f16ee8de1c8ff
+size 32321
diff --git a/screenshots/de/ui_T_t[f.roomdetails.impl.edit_RoomDetailsEditView_null_RoomDetailsEditView-Day-3_3_null_5,NEXUS_5,1.0,de].png b/screenshots/de/ui_T_t[f.roomdetails.impl.edit_RoomDetailsEditView_null_RoomDetailsEditView-Day-3_3_null_5,NEXUS_5,1.0,de].png
new file mode 100644
index 0000000000..d19e87ffd6
--- /dev/null
+++ b/screenshots/de/ui_T_t[f.roomdetails.impl.edit_RoomDetailsEditView_null_RoomDetailsEditView-Day-3_3_null_5,NEXUS_5,1.0,de].png
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:f61b04b0787c4cfb80b2f75f6fff3e65af6a3d273ce37cb210ad93d858d50c52
+size 32340
diff --git a/screenshots/de/ui_T_t[f.roomdetails.impl.edit_RoomDetailsEditView_null_RoomDetailsEditView-Day-3_3_null_6,NEXUS_5,1.0,de].png b/screenshots/de/ui_T_t[f.roomdetails.impl.edit_RoomDetailsEditView_null_RoomDetailsEditView-Day-3_3_null_6,NEXUS_5,1.0,de].png
new file mode 100644
index 0000000000..9c4720588d
--- /dev/null
+++ b/screenshots/de/ui_T_t[f.roomdetails.impl.edit_RoomDetailsEditView_null_RoomDetailsEditView-Day-3_3_null_6,NEXUS_5,1.0,de].png
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:e1f764391457e5fb67f04a2ed7e2c3bdf763f459ece8899e1965917918066bf8
+size 29928
diff --git a/screenshots/de/ui_T_t[f.roomdetails.impl.edit_RoomDetailsEditView_null_RoomDetailsEditView-Day-3_3_null_7,NEXUS_5,1.0,de].png b/screenshots/de/ui_T_t[f.roomdetails.impl.edit_RoomDetailsEditView_null_RoomDetailsEditView-Day-3_3_null_7,NEXUS_5,1.0,de].png
new file mode 100644
index 0000000000..92ffd892c7
--- /dev/null
+++ b/screenshots/de/ui_T_t[f.roomdetails.impl.edit_RoomDetailsEditView_null_RoomDetailsEditView-Day-3_3_null_7,NEXUS_5,1.0,de].png
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:059d474ea5c817e2779b076f96a139e52cc60b2b75faa11703218ff63effcbf0
+size 33643
diff --git a/screenshots/de/ui_T_t[f.roomdetails.impl.invite_RoomInviteMembersView_null_RoomInviteMembersView-Day-1_1_null_0,NEXUS_5,1.0,de].png b/screenshots/de/ui_T_t[f.roomdetails.impl.invite_RoomInviteMembersView_null_RoomInviteMembersView-Day-4_4_null_0,NEXUS_5,1.0,de].png
similarity index 100%
rename from screenshots/de/ui_T_t[f.roomdetails.impl.invite_RoomInviteMembersView_null_RoomInviteMembersView-Day-1_1_null_0,NEXUS_5,1.0,de].png
rename to screenshots/de/ui_T_t[f.roomdetails.impl.invite_RoomInviteMembersView_null_RoomInviteMembersView-Day-4_4_null_0,NEXUS_5,1.0,de].png
diff --git a/screenshots/de/ui_T_t[f.roomdetails.impl.invite_RoomInviteMembersView_null_RoomInviteMembersView-Day-1_1_null_1,NEXUS_5,1.0,de].png b/screenshots/de/ui_T_t[f.roomdetails.impl.invite_RoomInviteMembersView_null_RoomInviteMembersView-Day-4_4_null_1,NEXUS_5,1.0,de].png
similarity index 100%
rename from screenshots/de/ui_T_t[f.roomdetails.impl.invite_RoomInviteMembersView_null_RoomInviteMembersView-Day-1_1_null_1,NEXUS_5,1.0,de].png
rename to screenshots/de/ui_T_t[f.roomdetails.impl.invite_RoomInviteMembersView_null_RoomInviteMembersView-Day-4_4_null_1,NEXUS_5,1.0,de].png
diff --git a/screenshots/de/ui_T_t[f.roomdetails.impl.invite_RoomInviteMembersView_null_RoomInviteMembersView-Day-1_1_null_2,NEXUS_5,1.0,de].png b/screenshots/de/ui_T_t[f.roomdetails.impl.invite_RoomInviteMembersView_null_RoomInviteMembersView-Day-4_4_null_2,NEXUS_5,1.0,de].png
similarity index 100%
rename from screenshots/de/ui_T_t[f.roomdetails.impl.invite_RoomInviteMembersView_null_RoomInviteMembersView-Day-1_1_null_2,NEXUS_5,1.0,de].png
rename to screenshots/de/ui_T_t[f.roomdetails.impl.invite_RoomInviteMembersView_null_RoomInviteMembersView-Day-4_4_null_2,NEXUS_5,1.0,de].png
diff --git a/screenshots/de/ui_T_t[f.roomdetails.impl.invite_RoomInviteMembersView_null_RoomInviteMembersView-Day-1_1_null_3,NEXUS_5,1.0,de].png b/screenshots/de/ui_T_t[f.roomdetails.impl.invite_RoomInviteMembersView_null_RoomInviteMembersView-Day-4_4_null_3,NEXUS_5,1.0,de].png
similarity index 100%
rename from screenshots/de/ui_T_t[f.roomdetails.impl.invite_RoomInviteMembersView_null_RoomInviteMembersView-Day-1_1_null_3,NEXUS_5,1.0,de].png
rename to screenshots/de/ui_T_t[f.roomdetails.impl.invite_RoomInviteMembersView_null_RoomInviteMembersView-Day-4_4_null_3,NEXUS_5,1.0,de].png
diff --git a/screenshots/de/ui_T_t[f.roomdetails.impl.invite_RoomInviteMembersView_null_RoomInviteMembersView-Day-1_1_null_4,NEXUS_5,1.0,de].png b/screenshots/de/ui_T_t[f.roomdetails.impl.invite_RoomInviteMembersView_null_RoomInviteMembersView-Day-4_4_null_4,NEXUS_5,1.0,de].png
similarity index 100%
rename from screenshots/de/ui_T_t[f.roomdetails.impl.invite_RoomInviteMembersView_null_RoomInviteMembersView-Day-1_1_null_4,NEXUS_5,1.0,de].png
rename to screenshots/de/ui_T_t[f.roomdetails.impl.invite_RoomInviteMembersView_null_RoomInviteMembersView-Day-4_4_null_4,NEXUS_5,1.0,de].png
diff --git a/screenshots/de/ui_T_t[f.roomdetails.impl.invite_RoomInviteMembersView_null_RoomInviteMembersView-Day-1_1_null_5,NEXUS_5,1.0,de].png b/screenshots/de/ui_T_t[f.roomdetails.impl.invite_RoomInviteMembersView_null_RoomInviteMembersView-Day-4_4_null_5,NEXUS_5,1.0,de].png
similarity index 100%
rename from screenshots/de/ui_T_t[f.roomdetails.impl.invite_RoomInviteMembersView_null_RoomInviteMembersView-Day-1_1_null_5,NEXUS_5,1.0,de].png
rename to screenshots/de/ui_T_t[f.roomdetails.impl.invite_RoomInviteMembersView_null_RoomInviteMembersView-Day-4_4_null_5,NEXUS_5,1.0,de].png
diff --git a/screenshots/de/ui_T_t[f.roomdetails.impl.invite_RoomInviteMembersView_null_RoomInviteMembersView-Day-1_1_null_6,NEXUS_5,1.0,de].png b/screenshots/de/ui_T_t[f.roomdetails.impl.invite_RoomInviteMembersView_null_RoomInviteMembersView-Day-4_4_null_6,NEXUS_5,1.0,de].png
similarity index 100%
rename from screenshots/de/ui_T_t[f.roomdetails.impl.invite_RoomInviteMembersView_null_RoomInviteMembersView-Day-1_1_null_6,NEXUS_5,1.0,de].png
rename to screenshots/de/ui_T_t[f.roomdetails.impl.invite_RoomInviteMembersView_null_RoomInviteMembersView-Day-4_4_null_6,NEXUS_5,1.0,de].png
diff --git a/screenshots/de/ui_T_t[f.roomdetails.impl.invite_RoomInviteMembersView_null_RoomInviteMembersView-Day-1_1_null_7,NEXUS_5,1.0,de].png b/screenshots/de/ui_T_t[f.roomdetails.impl.invite_RoomInviteMembersView_null_RoomInviteMembersView-Day-4_4_null_7,NEXUS_5,1.0,de].png
similarity index 100%
rename from screenshots/de/ui_T_t[f.roomdetails.impl.invite_RoomInviteMembersView_null_RoomInviteMembersView-Day-1_1_null_7,NEXUS_5,1.0,de].png
rename to screenshots/de/ui_T_t[f.roomdetails.impl.invite_RoomInviteMembersView_null_RoomInviteMembersView-Day-4_4_null_7,NEXUS_5,1.0,de].png
diff --git a/screenshots/de/ui_T_t[f.roomdetails.impl.members.moderation_RoomMembersModerationView_null_RoomMembersModerationView-Day-4_4_null_0,NEXUS_5,1.0,de].png b/screenshots/de/ui_T_t[f.roomdetails.impl.members.moderation_RoomMembersModerationView_null_RoomMembersModerationView-Day-7_7_null_0,NEXUS_5,1.0,de].png
similarity index 100%
rename from screenshots/de/ui_T_t[f.roomdetails.impl.members.moderation_RoomMembersModerationView_null_RoomMembersModerationView-Day-4_4_null_0,NEXUS_5,1.0,de].png
rename to screenshots/de/ui_T_t[f.roomdetails.impl.members.moderation_RoomMembersModerationView_null_RoomMembersModerationView-Day-7_7_null_0,NEXUS_5,1.0,de].png
diff --git a/screenshots/de/ui_T_t[f.roomdetails.impl.members.moderation_RoomMembersModerationView_null_RoomMembersModerationView-Day-4_4_null_1,NEXUS_5,1.0,de].png b/screenshots/de/ui_T_t[f.roomdetails.impl.members.moderation_RoomMembersModerationView_null_RoomMembersModerationView-Day-7_7_null_1,NEXUS_5,1.0,de].png
similarity index 100%
rename from screenshots/de/ui_T_t[f.roomdetails.impl.members.moderation_RoomMembersModerationView_null_RoomMembersModerationView-Day-4_4_null_1,NEXUS_5,1.0,de].png
rename to screenshots/de/ui_T_t[f.roomdetails.impl.members.moderation_RoomMembersModerationView_null_RoomMembersModerationView-Day-7_7_null_1,NEXUS_5,1.0,de].png
diff --git a/screenshots/de/ui_T_t[f.roomdetails.impl.members.moderation_RoomMembersModerationView_null_RoomMembersModerationView-Day-4_4_null_2,NEXUS_5,1.0,de].png b/screenshots/de/ui_T_t[f.roomdetails.impl.members.moderation_RoomMembersModerationView_null_RoomMembersModerationView-Day-7_7_null_2,NEXUS_5,1.0,de].png
similarity index 100%
rename from screenshots/de/ui_T_t[f.roomdetails.impl.members.moderation_RoomMembersModerationView_null_RoomMembersModerationView-Day-4_4_null_2,NEXUS_5,1.0,de].png
rename to screenshots/de/ui_T_t[f.roomdetails.impl.members.moderation_RoomMembersModerationView_null_RoomMembersModerationView-Day-7_7_null_2,NEXUS_5,1.0,de].png
diff --git a/screenshots/de/ui_T_t[f.roomdetails.impl.members.moderation_RoomMembersModerationView_null_RoomMembersModerationView-Day-4_4_null_3,NEXUS_5,1.0,de].png b/screenshots/de/ui_T_t[f.roomdetails.impl.members.moderation_RoomMembersModerationView_null_RoomMembersModerationView-Day-7_7_null_3,NEXUS_5,1.0,de].png
similarity index 100%
rename from screenshots/de/ui_T_t[f.roomdetails.impl.members.moderation_RoomMembersModerationView_null_RoomMembersModerationView-Day-4_4_null_3,NEXUS_5,1.0,de].png
rename to screenshots/de/ui_T_t[f.roomdetails.impl.members.moderation_RoomMembersModerationView_null_RoomMembersModerationView-Day-7_7_null_3,NEXUS_5,1.0,de].png
diff --git a/screenshots/de/ui_T_t[f.roomdetails.impl.members.moderation_RoomMembersModerationView_null_RoomMembersModerationView-Day-4_4_null_4,NEXUS_5,1.0,de].png b/screenshots/de/ui_T_t[f.roomdetails.impl.members.moderation_RoomMembersModerationView_null_RoomMembersModerationView-Day-7_7_null_4,NEXUS_5,1.0,de].png
similarity index 100%
rename from screenshots/de/ui_T_t[f.roomdetails.impl.members.moderation_RoomMembersModerationView_null_RoomMembersModerationView-Day-4_4_null_4,NEXUS_5,1.0,de].png
rename to screenshots/de/ui_T_t[f.roomdetails.impl.members.moderation_RoomMembersModerationView_null_RoomMembersModerationView-Day-7_7_null_4,NEXUS_5,1.0,de].png
diff --git a/screenshots/de/ui_T_t[f.roomdetails.impl.members.moderation_RoomMembersModerationView_null_RoomMembersModerationView-Day-4_4_null_5,NEXUS_5,1.0,de].png b/screenshots/de/ui_T_t[f.roomdetails.impl.members.moderation_RoomMembersModerationView_null_RoomMembersModerationView-Day-7_7_null_5,NEXUS_5,1.0,de].png
similarity index 100%
rename from screenshots/de/ui_T_t[f.roomdetails.impl.members.moderation_RoomMembersModerationView_null_RoomMembersModerationView-Day-4_4_null_5,NEXUS_5,1.0,de].png
rename to screenshots/de/ui_T_t[f.roomdetails.impl.members.moderation_RoomMembersModerationView_null_RoomMembersModerationView-Day-7_7_null_5,NEXUS_5,1.0,de].png
diff --git a/screenshots/de/ui_T_t[f.roomdetails.impl.members.moderation_RoomMembersModerationView_null_RoomMembersModerationView-Day-4_4_null_6,NEXUS_5,1.0,de].png b/screenshots/de/ui_T_t[f.roomdetails.impl.members.moderation_RoomMembersModerationView_null_RoomMembersModerationView-Day-7_7_null_6,NEXUS_5,1.0,de].png
similarity index 100%
rename from screenshots/de/ui_T_t[f.roomdetails.impl.members.moderation_RoomMembersModerationView_null_RoomMembersModerationView-Day-4_4_null_6,NEXUS_5,1.0,de].png
rename to screenshots/de/ui_T_t[f.roomdetails.impl.members.moderation_RoomMembersModerationView_null_RoomMembersModerationView-Day-7_7_null_6,NEXUS_5,1.0,de].png
diff --git a/screenshots/de/ui_T_t[f.roomdetails.impl.members.moderation_RoomMembersModerationView_null_RoomMembersModerationView-Day-4_4_null_7,NEXUS_5,1.0,de].png b/screenshots/de/ui_T_t[f.roomdetails.impl.members.moderation_RoomMembersModerationView_null_RoomMembersModerationView-Day-7_7_null_7,NEXUS_5,1.0,de].png
similarity index 100%
rename from screenshots/de/ui_T_t[f.roomdetails.impl.members.moderation_RoomMembersModerationView_null_RoomMembersModerationView-Day-4_4_null_7,NEXUS_5,1.0,de].png
rename to screenshots/de/ui_T_t[f.roomdetails.impl.members.moderation_RoomMembersModerationView_null_RoomMembersModerationView-Day-7_7_null_7,NEXUS_5,1.0,de].png
diff --git a/screenshots/de/ui_T_t[f.roomdetails.impl.members.moderation_RoomMembersModerationView_null_RoomMembersModerationView-Day-4_4_null_8,NEXUS_5,1.0,de].png b/screenshots/de/ui_T_t[f.roomdetails.impl.members.moderation_RoomMembersModerationView_null_RoomMembersModerationView-Day-7_7_null_8,NEXUS_5,1.0,de].png
similarity index 100%
rename from screenshots/de/ui_T_t[f.roomdetails.impl.members.moderation_RoomMembersModerationView_null_RoomMembersModerationView-Day-4_4_null_8,NEXUS_5,1.0,de].png
rename to screenshots/de/ui_T_t[f.roomdetails.impl.members.moderation_RoomMembersModerationView_null_RoomMembersModerationView-Day-7_7_null_8,NEXUS_5,1.0,de].png
diff --git a/screenshots/de/ui_T_t[f.roomdetails.impl.members_RoomMemberListViewBanned_null_RoomMemberListViewBanned-Day-3_3_null_0,NEXUS_5,1.0,de].png b/screenshots/de/ui_T_t[f.roomdetails.impl.members_RoomMemberListViewBanned_null_RoomMemberListViewBanned-Day-6_6_null_0,NEXUS_5,1.0,de].png
similarity index 100%
rename from screenshots/de/ui_T_t[f.roomdetails.impl.members_RoomMemberListViewBanned_null_RoomMemberListViewBanned-Day-3_3_null_0,NEXUS_5,1.0,de].png
rename to screenshots/de/ui_T_t[f.roomdetails.impl.members_RoomMemberListViewBanned_null_RoomMemberListViewBanned-Day-6_6_null_0,NEXUS_5,1.0,de].png
diff --git a/screenshots/de/ui_T_t[f.roomdetails.impl.members_RoomMemberListViewBanned_null_RoomMemberListViewBanned-Day-3_3_null_1,NEXUS_5,1.0,de].png b/screenshots/de/ui_T_t[f.roomdetails.impl.members_RoomMemberListViewBanned_null_RoomMemberListViewBanned-Day-6_6_null_1,NEXUS_5,1.0,de].png
similarity index 100%
rename from screenshots/de/ui_T_t[f.roomdetails.impl.members_RoomMemberListViewBanned_null_RoomMemberListViewBanned-Day-3_3_null_1,NEXUS_5,1.0,de].png
rename to screenshots/de/ui_T_t[f.roomdetails.impl.members_RoomMemberListViewBanned_null_RoomMemberListViewBanned-Day-6_6_null_1,NEXUS_5,1.0,de].png
diff --git a/screenshots/de/ui_T_t[f.roomdetails.impl.members_RoomMemberListViewBanned_null_RoomMemberListViewBanned-Day-3_3_null_2,NEXUS_5,1.0,de].png b/screenshots/de/ui_T_t[f.roomdetails.impl.members_RoomMemberListViewBanned_null_RoomMemberListViewBanned-Day-6_6_null_2,NEXUS_5,1.0,de].png
similarity index 100%
rename from screenshots/de/ui_T_t[f.roomdetails.impl.members_RoomMemberListViewBanned_null_RoomMemberListViewBanned-Day-3_3_null_2,NEXUS_5,1.0,de].png
rename to screenshots/de/ui_T_t[f.roomdetails.impl.members_RoomMemberListViewBanned_null_RoomMemberListViewBanned-Day-6_6_null_2,NEXUS_5,1.0,de].png
diff --git a/screenshots/de/ui_T_t[f.roomdetails.impl.members_RoomMemberListView_null_RoomMemberListView-Day-2_2_null_0,NEXUS_5,1.0,de].png b/screenshots/de/ui_T_t[f.roomdetails.impl.members_RoomMemberListView_null_RoomMemberListView-Day-5_5_null_0,NEXUS_5,1.0,de].png
similarity index 100%
rename from screenshots/de/ui_T_t[f.roomdetails.impl.members_RoomMemberListView_null_RoomMemberListView-Day-2_2_null_0,NEXUS_5,1.0,de].png
rename to screenshots/de/ui_T_t[f.roomdetails.impl.members_RoomMemberListView_null_RoomMemberListView-Day-5_5_null_0,NEXUS_5,1.0,de].png
diff --git a/screenshots/de/ui_T_t[f.roomdetails.impl.members_RoomMemberListView_null_RoomMemberListView-Day-2_2_null_1,NEXUS_5,1.0,de].png b/screenshots/de/ui_T_t[f.roomdetails.impl.members_RoomMemberListView_null_RoomMemberListView-Day-5_5_null_1,NEXUS_5,1.0,de].png
similarity index 100%
rename from screenshots/de/ui_T_t[f.roomdetails.impl.members_RoomMemberListView_null_RoomMemberListView-Day-2_2_null_1,NEXUS_5,1.0,de].png
rename to screenshots/de/ui_T_t[f.roomdetails.impl.members_RoomMemberListView_null_RoomMemberListView-Day-5_5_null_1,NEXUS_5,1.0,de].png
diff --git a/screenshots/de/ui_T_t[f.roomdetails.impl.members_RoomMemberListView_null_RoomMemberListView-Day-2_2_null_2,NEXUS_5,1.0,de].png b/screenshots/de/ui_T_t[f.roomdetails.impl.members_RoomMemberListView_null_RoomMemberListView-Day-5_5_null_2,NEXUS_5,1.0,de].png
similarity index 100%
rename from screenshots/de/ui_T_t[f.roomdetails.impl.members_RoomMemberListView_null_RoomMemberListView-Day-2_2_null_2,NEXUS_5,1.0,de].png
rename to screenshots/de/ui_T_t[f.roomdetails.impl.members_RoomMemberListView_null_RoomMemberListView-Day-5_5_null_2,NEXUS_5,1.0,de].png
diff --git a/screenshots/de/ui_T_t[f.roomdetails.impl.members_RoomMemberListView_null_RoomMemberListView-Day-2_2_null_3,NEXUS_5,1.0,de].png b/screenshots/de/ui_T_t[f.roomdetails.impl.members_RoomMemberListView_null_RoomMemberListView-Day-5_5_null_3,NEXUS_5,1.0,de].png
similarity index 100%
rename from screenshots/de/ui_T_t[f.roomdetails.impl.members_RoomMemberListView_null_RoomMemberListView-Day-2_2_null_3,NEXUS_5,1.0,de].png
rename to screenshots/de/ui_T_t[f.roomdetails.impl.members_RoomMemberListView_null_RoomMemberListView-Day-5_5_null_3,NEXUS_5,1.0,de].png
diff --git a/screenshots/de/ui_T_t[f.roomdetails.impl.members_RoomMemberListView_null_RoomMemberListView-Day-2_2_null_4,NEXUS_5,1.0,de].png b/screenshots/de/ui_T_t[f.roomdetails.impl.members_RoomMemberListView_null_RoomMemberListView-Day-5_5_null_4,NEXUS_5,1.0,de].png
similarity index 100%
rename from screenshots/de/ui_T_t[f.roomdetails.impl.members_RoomMemberListView_null_RoomMemberListView-Day-2_2_null_4,NEXUS_5,1.0,de].png
rename to screenshots/de/ui_T_t[f.roomdetails.impl.members_RoomMemberListView_null_RoomMemberListView-Day-5_5_null_4,NEXUS_5,1.0,de].png
diff --git a/screenshots/de/ui_T_t[f.roomdetails.impl.members_RoomMemberListView_null_RoomMemberListView-Day-2_2_null_6,NEXUS_5,1.0,de].png b/screenshots/de/ui_T_t[f.roomdetails.impl.members_RoomMemberListView_null_RoomMemberListView-Day-5_5_null_6,NEXUS_5,1.0,de].png
similarity index 100%
rename from screenshots/de/ui_T_t[f.roomdetails.impl.members_RoomMemberListView_null_RoomMemberListView-Day-2_2_null_6,NEXUS_5,1.0,de].png
rename to screenshots/de/ui_T_t[f.roomdetails.impl.members_RoomMemberListView_null_RoomMemberListView-Day-5_5_null_6,NEXUS_5,1.0,de].png
diff --git a/screenshots/de/ui_T_t[f.roomdetails.impl.members_RoomMemberListView_null_RoomMemberListView-Day-2_2_null_7,NEXUS_5,1.0,de].png b/screenshots/de/ui_T_t[f.roomdetails.impl.members_RoomMemberListView_null_RoomMemberListView-Day-5_5_null_7,NEXUS_5,1.0,de].png
similarity index 100%
rename from screenshots/de/ui_T_t[f.roomdetails.impl.members_RoomMemberListView_null_RoomMemberListView-Day-2_2_null_7,NEXUS_5,1.0,de].png
rename to screenshots/de/ui_T_t[f.roomdetails.impl.members_RoomMemberListView_null_RoomMemberListView-Day-5_5_null_7,NEXUS_5,1.0,de].png
diff --git a/screenshots/de/ui_T_t[f.roomdetails.impl.notificationsettings_RoomNotificationSettingsOption_null_RoomNotificationSettingsOption-Day-5_5_null,NEXUS_5,1.0,de].png b/screenshots/de/ui_T_t[f.roomdetails.impl.notificationsettings_RoomNotificationSettingsOption_null_RoomNotificationSettingsOption-Day-8_8_null,NEXUS_5,1.0,de].png
similarity index 100%
rename from screenshots/de/ui_T_t[f.roomdetails.impl.notificationsettings_RoomNotificationSettingsOption_null_RoomNotificationSettingsOption-Day-5_5_null,NEXUS_5,1.0,de].png
rename to screenshots/de/ui_T_t[f.roomdetails.impl.notificationsettings_RoomNotificationSettingsOption_null_RoomNotificationSettingsOption-Day-8_8_null,NEXUS_5,1.0,de].png
diff --git a/screenshots/de/ui_T_t[f.roomdetails.impl.notificationsettings_RoomNotificationSettingsView_null_RoomNotificationSettingsView-Day-6_6_null_0,NEXUS_5,1.0,de].png b/screenshots/de/ui_T_t[f.roomdetails.impl.notificationsettings_RoomNotificationSettingsView_null_RoomNotificationSettingsView-Day-9_9_null_0,NEXUS_5,1.0,de].png
similarity index 100%
rename from screenshots/de/ui_T_t[f.roomdetails.impl.notificationsettings_RoomNotificationSettingsView_null_RoomNotificationSettingsView-Day-6_6_null_0,NEXUS_5,1.0,de].png
rename to screenshots/de/ui_T_t[f.roomdetails.impl.notificationsettings_RoomNotificationSettingsView_null_RoomNotificationSettingsView-Day-9_9_null_0,NEXUS_5,1.0,de].png
diff --git a/screenshots/de/ui_T_t[f.roomdetails.impl.notificationsettings_RoomNotificationSettingsView_null_RoomNotificationSettingsView-Day-6_6_null_1,NEXUS_5,1.0,de].png b/screenshots/de/ui_T_t[f.roomdetails.impl.notificationsettings_RoomNotificationSettingsView_null_RoomNotificationSettingsView-Day-9_9_null_1,NEXUS_5,1.0,de].png
similarity index 100%
rename from screenshots/de/ui_T_t[f.roomdetails.impl.notificationsettings_RoomNotificationSettingsView_null_RoomNotificationSettingsView-Day-6_6_null_1,NEXUS_5,1.0,de].png
rename to screenshots/de/ui_T_t[f.roomdetails.impl.notificationsettings_RoomNotificationSettingsView_null_RoomNotificationSettingsView-Day-9_9_null_1,NEXUS_5,1.0,de].png
diff --git a/screenshots/de/ui_T_t[f.roomdetails.impl.notificationsettings_RoomNotificationSettingsView_null_RoomNotificationSettingsView-Day-6_6_null_2,NEXUS_5,1.0,de].png b/screenshots/de/ui_T_t[f.roomdetails.impl.notificationsettings_RoomNotificationSettingsView_null_RoomNotificationSettingsView-Day-9_9_null_2,NEXUS_5,1.0,de].png
similarity index 100%
rename from screenshots/de/ui_T_t[f.roomdetails.impl.notificationsettings_RoomNotificationSettingsView_null_RoomNotificationSettingsView-Day-6_6_null_2,NEXUS_5,1.0,de].png
rename to screenshots/de/ui_T_t[f.roomdetails.impl.notificationsettings_RoomNotificationSettingsView_null_RoomNotificationSettingsView-Day-9_9_null_2,NEXUS_5,1.0,de].png
diff --git a/screenshots/de/ui_T_t[f.roomdetails.impl.notificationsettings_RoomNotificationSettingsView_null_RoomNotificationSettingsView-Day-6_6_null_3,NEXUS_5,1.0,de].png b/screenshots/de/ui_T_t[f.roomdetails.impl.notificationsettings_RoomNotificationSettingsView_null_RoomNotificationSettingsView-Day-9_9_null_3,NEXUS_5,1.0,de].png
similarity index 100%
rename from screenshots/de/ui_T_t[f.roomdetails.impl.notificationsettings_RoomNotificationSettingsView_null_RoomNotificationSettingsView-Day-6_6_null_3,NEXUS_5,1.0,de].png
rename to screenshots/de/ui_T_t[f.roomdetails.impl.notificationsettings_RoomNotificationSettingsView_null_RoomNotificationSettingsView-Day-9_9_null_3,NEXUS_5,1.0,de].png
diff --git a/screenshots/de/ui_T_t[f.roomdetails.impl.notificationsettings_RoomNotificationSettingsView_null_RoomNotificationSettingsView-Day-6_6_null_4,NEXUS_5,1.0,de].png b/screenshots/de/ui_T_t[f.roomdetails.impl.notificationsettings_RoomNotificationSettingsView_null_RoomNotificationSettingsView-Day-9_9_null_4,NEXUS_5,1.0,de].png
similarity index 100%
rename from screenshots/de/ui_T_t[f.roomdetails.impl.notificationsettings_RoomNotificationSettingsView_null_RoomNotificationSettingsView-Day-6_6_null_4,NEXUS_5,1.0,de].png
rename to screenshots/de/ui_T_t[f.roomdetails.impl.notificationsettings_RoomNotificationSettingsView_null_RoomNotificationSettingsView-Day-9_9_null_4,NEXUS_5,1.0,de].png
diff --git a/screenshots/de/ui_T_t[f.roomdetails.impl.notificationsettings_RoomNotificationSettingsView_null_RoomNotificationSettingsView-Day-6_6_null_5,NEXUS_5,1.0,de].png b/screenshots/de/ui_T_t[f.roomdetails.impl.notificationsettings_RoomNotificationSettingsView_null_RoomNotificationSettingsView-Day-9_9_null_5,NEXUS_5,1.0,de].png
similarity index 100%
rename from screenshots/de/ui_T_t[f.roomdetails.impl.notificationsettings_RoomNotificationSettingsView_null_RoomNotificationSettingsView-Day-6_6_null_5,NEXUS_5,1.0,de].png
rename to screenshots/de/ui_T_t[f.roomdetails.impl.notificationsettings_RoomNotificationSettingsView_null_RoomNotificationSettingsView-Day-9_9_null_5,NEXUS_5,1.0,de].png
diff --git a/screenshots/de/ui_T_t[f.roomdetails.impl.notificationsettings_RoomNotificationSettingsView_null_RoomNotificationSettingsView-Day-6_6_null_6,NEXUS_5,1.0,de].png b/screenshots/de/ui_T_t[f.roomdetails.impl.notificationsettings_RoomNotificationSettingsView_null_RoomNotificationSettingsView-Day-9_9_null_6,NEXUS_5,1.0,de].png
similarity index 100%
rename from screenshots/de/ui_T_t[f.roomdetails.impl.notificationsettings_RoomNotificationSettingsView_null_RoomNotificationSettingsView-Day-6_6_null_6,NEXUS_5,1.0,de].png
rename to screenshots/de/ui_T_t[f.roomdetails.impl.notificationsettings_RoomNotificationSettingsView_null_RoomNotificationSettingsView-Day-9_9_null_6,NEXUS_5,1.0,de].png
diff --git a/screenshots/de/ui_T_t[f.roomdetails.impl.notificationsettings_UserDefinedRoomNotificationSettingsView_null_UserDefinedRoomNotificationSettingsView-Day-7_7_null_0,NEXUS_5,1.0,de].png b/screenshots/de/ui_T_t[f.roomdetails.impl.notificationsettings_UserDefinedRoomNotificationSettingsView_null_UserDefinedRoomNotificationSettingsView-Day-10_10_null_0,NEXUS_5,1.0,de].png
similarity index 100%
rename from screenshots/de/ui_T_t[f.roomdetails.impl.notificationsettings_UserDefinedRoomNotificationSettingsView_null_UserDefinedRoomNotificationSettingsView-Day-7_7_null_0,NEXUS_5,1.0,de].png
rename to screenshots/de/ui_T_t[f.roomdetails.impl.notificationsettings_UserDefinedRoomNotificationSettingsView_null_UserDefinedRoomNotificationSettingsView-Day-10_10_null_0,NEXUS_5,1.0,de].png
diff --git a/screenshots/de/ui_T_t[f.roomdetails.impl.rolesandpermissions.changeroles_ChangeRolesView_null_ChangeRolesView-Day-9_9_null_0,NEXUS_5,1.0,de].png b/screenshots/de/ui_T_t[f.roomdetails.impl.rolesandpermissions.changeroles_ChangeRolesView_null_ChangeRolesView-Day-12_12_null_0,NEXUS_5,1.0,de].png
similarity index 100%
rename from screenshots/de/ui_T_t[f.roomdetails.impl.rolesandpermissions.changeroles_ChangeRolesView_null_ChangeRolesView-Day-9_9_null_0,NEXUS_5,1.0,de].png
rename to screenshots/de/ui_T_t[f.roomdetails.impl.rolesandpermissions.changeroles_ChangeRolesView_null_ChangeRolesView-Day-12_12_null_0,NEXUS_5,1.0,de].png
diff --git a/screenshots/de/ui_T_t[f.roomdetails.impl.rolesandpermissions.changeroles_ChangeRolesView_null_ChangeRolesView-Day-9_9_null_1,NEXUS_5,1.0,de].png b/screenshots/de/ui_T_t[f.roomdetails.impl.rolesandpermissions.changeroles_ChangeRolesView_null_ChangeRolesView-Day-12_12_null_1,NEXUS_5,1.0,de].png
similarity index 100%
rename from screenshots/de/ui_T_t[f.roomdetails.impl.rolesandpermissions.changeroles_ChangeRolesView_null_ChangeRolesView-Day-9_9_null_1,NEXUS_5,1.0,de].png
rename to screenshots/de/ui_T_t[f.roomdetails.impl.rolesandpermissions.changeroles_ChangeRolesView_null_ChangeRolesView-Day-12_12_null_1,NEXUS_5,1.0,de].png
diff --git a/screenshots/de/ui_T_t[f.roomdetails.impl.rolesandpermissions.changeroles_ChangeRolesView_null_ChangeRolesView-Day-9_9_null_10,NEXUS_5,1.0,de].png b/screenshots/de/ui_T_t[f.roomdetails.impl.rolesandpermissions.changeroles_ChangeRolesView_null_ChangeRolesView-Day-12_12_null_10,NEXUS_5,1.0,de].png
similarity index 100%
rename from screenshots/de/ui_T_t[f.roomdetails.impl.rolesandpermissions.changeroles_ChangeRolesView_null_ChangeRolesView-Day-9_9_null_10,NEXUS_5,1.0,de].png
rename to screenshots/de/ui_T_t[f.roomdetails.impl.rolesandpermissions.changeroles_ChangeRolesView_null_ChangeRolesView-Day-12_12_null_10,NEXUS_5,1.0,de].png
diff --git a/screenshots/de/ui_T_t[f.roomdetails.impl.rolesandpermissions.changeroles_ChangeRolesView_null_ChangeRolesView-Day-9_9_null_2,NEXUS_5,1.0,de].png b/screenshots/de/ui_T_t[f.roomdetails.impl.rolesandpermissions.changeroles_ChangeRolesView_null_ChangeRolesView-Day-12_12_null_2,NEXUS_5,1.0,de].png
similarity index 100%
rename from screenshots/de/ui_T_t[f.roomdetails.impl.rolesandpermissions.changeroles_ChangeRolesView_null_ChangeRolesView-Day-9_9_null_2,NEXUS_5,1.0,de].png
rename to screenshots/de/ui_T_t[f.roomdetails.impl.rolesandpermissions.changeroles_ChangeRolesView_null_ChangeRolesView-Day-12_12_null_2,NEXUS_5,1.0,de].png
diff --git a/screenshots/de/ui_T_t[f.roomdetails.impl.rolesandpermissions.changeroles_ChangeRolesView_null_ChangeRolesView-Day-9_9_null_3,NEXUS_5,1.0,de].png b/screenshots/de/ui_T_t[f.roomdetails.impl.rolesandpermissions.changeroles_ChangeRolesView_null_ChangeRolesView-Day-12_12_null_3,NEXUS_5,1.0,de].png
similarity index 100%
rename from screenshots/de/ui_T_t[f.roomdetails.impl.rolesandpermissions.changeroles_ChangeRolesView_null_ChangeRolesView-Day-9_9_null_3,NEXUS_5,1.0,de].png
rename to screenshots/de/ui_T_t[f.roomdetails.impl.rolesandpermissions.changeroles_ChangeRolesView_null_ChangeRolesView-Day-12_12_null_3,NEXUS_5,1.0,de].png
diff --git a/screenshots/de/ui_T_t[f.roomdetails.impl.rolesandpermissions.changeroles_ChangeRolesView_null_ChangeRolesView-Day-9_9_null_4,NEXUS_5,1.0,de].png b/screenshots/de/ui_T_t[f.roomdetails.impl.rolesandpermissions.changeroles_ChangeRolesView_null_ChangeRolesView-Day-12_12_null_4,NEXUS_5,1.0,de].png
similarity index 100%
rename from screenshots/de/ui_T_t[f.roomdetails.impl.rolesandpermissions.changeroles_ChangeRolesView_null_ChangeRolesView-Day-9_9_null_4,NEXUS_5,1.0,de].png
rename to screenshots/de/ui_T_t[f.roomdetails.impl.rolesandpermissions.changeroles_ChangeRolesView_null_ChangeRolesView-Day-12_12_null_4,NEXUS_5,1.0,de].png
diff --git a/screenshots/de/ui_T_t[f.roomdetails.impl.rolesandpermissions.changeroles_ChangeRolesView_null_ChangeRolesView-Day-9_9_null_5,NEXUS_5,1.0,de].png b/screenshots/de/ui_T_t[f.roomdetails.impl.rolesandpermissions.changeroles_ChangeRolesView_null_ChangeRolesView-Day-12_12_null_5,NEXUS_5,1.0,de].png
similarity index 100%
rename from screenshots/de/ui_T_t[f.roomdetails.impl.rolesandpermissions.changeroles_ChangeRolesView_null_ChangeRolesView-Day-9_9_null_5,NEXUS_5,1.0,de].png
rename to screenshots/de/ui_T_t[f.roomdetails.impl.rolesandpermissions.changeroles_ChangeRolesView_null_ChangeRolesView-Day-12_12_null_5,NEXUS_5,1.0,de].png
diff --git a/screenshots/de/ui_T_t[f.roomdetails.impl.rolesandpermissions.changeroles_ChangeRolesView_null_ChangeRolesView-Day-9_9_null_6,NEXUS_5,1.0,de].png b/screenshots/de/ui_T_t[f.roomdetails.impl.rolesandpermissions.changeroles_ChangeRolesView_null_ChangeRolesView-Day-12_12_null_6,NEXUS_5,1.0,de].png
similarity index 100%
rename from screenshots/de/ui_T_t[f.roomdetails.impl.rolesandpermissions.changeroles_ChangeRolesView_null_ChangeRolesView-Day-9_9_null_6,NEXUS_5,1.0,de].png
rename to screenshots/de/ui_T_t[f.roomdetails.impl.rolesandpermissions.changeroles_ChangeRolesView_null_ChangeRolesView-Day-12_12_null_6,NEXUS_5,1.0,de].png
diff --git a/screenshots/de/ui_T_t[f.roomdetails.impl.rolesandpermissions.changeroles_ChangeRolesView_null_ChangeRolesView-Day-9_9_null_7,NEXUS_5,1.0,de].png b/screenshots/de/ui_T_t[f.roomdetails.impl.rolesandpermissions.changeroles_ChangeRolesView_null_ChangeRolesView-Day-12_12_null_7,NEXUS_5,1.0,de].png
similarity index 100%
rename from screenshots/de/ui_T_t[f.roomdetails.impl.rolesandpermissions.changeroles_ChangeRolesView_null_ChangeRolesView-Day-9_9_null_7,NEXUS_5,1.0,de].png
rename to screenshots/de/ui_T_t[f.roomdetails.impl.rolesandpermissions.changeroles_ChangeRolesView_null_ChangeRolesView-Day-12_12_null_7,NEXUS_5,1.0,de].png
diff --git a/screenshots/de/ui_T_t[f.roomdetails.impl.rolesandpermissions.changeroles_ChangeRolesView_null_ChangeRolesView-Day-9_9_null_8,NEXUS_5,1.0,de].png b/screenshots/de/ui_T_t[f.roomdetails.impl.rolesandpermissions.changeroles_ChangeRolesView_null_ChangeRolesView-Day-12_12_null_8,NEXUS_5,1.0,de].png
similarity index 100%
rename from screenshots/de/ui_T_t[f.roomdetails.impl.rolesandpermissions.changeroles_ChangeRolesView_null_ChangeRolesView-Day-9_9_null_8,NEXUS_5,1.0,de].png
rename to screenshots/de/ui_T_t[f.roomdetails.impl.rolesandpermissions.changeroles_ChangeRolesView_null_ChangeRolesView-Day-12_12_null_8,NEXUS_5,1.0,de].png
diff --git a/screenshots/de/ui_T_t[f.roomdetails.impl.rolesandpermissions.changeroles_ChangeRolesView_null_ChangeRolesView-Day-9_9_null_9,NEXUS_5,1.0,de].png b/screenshots/de/ui_T_t[f.roomdetails.impl.rolesandpermissions.changeroles_ChangeRolesView_null_ChangeRolesView-Day-12_12_null_9,NEXUS_5,1.0,de].png
similarity index 100%
rename from screenshots/de/ui_T_t[f.roomdetails.impl.rolesandpermissions.changeroles_ChangeRolesView_null_ChangeRolesView-Day-9_9_null_9,NEXUS_5,1.0,de].png
rename to screenshots/de/ui_T_t[f.roomdetails.impl.rolesandpermissions.changeroles_ChangeRolesView_null_ChangeRolesView-Day-12_12_null_9,NEXUS_5,1.0,de].png
diff --git a/screenshots/de/ui_T_t[f.roomdetails.impl.rolesandpermissions.changeroles_PendingMemberRowWithLongName_null_PendingMemberRowWithLongName-Day-10_10_null,NEXUS_5,1.0,de].png b/screenshots/de/ui_T_t[f.roomdetails.impl.rolesandpermissions.changeroles_PendingMemberRowWithLongName_null_PendingMemberRowWithLongName-Day-13_13_null,NEXUS_5,1.0,de].png
similarity index 100%
rename from screenshots/de/ui_T_t[f.roomdetails.impl.rolesandpermissions.changeroles_PendingMemberRowWithLongName_null_PendingMemberRowWithLongName-Day-10_10_null,NEXUS_5,1.0,de].png
rename to screenshots/de/ui_T_t[f.roomdetails.impl.rolesandpermissions.changeroles_PendingMemberRowWithLongName_null_PendingMemberRowWithLongName-Day-13_13_null,NEXUS_5,1.0,de].png
diff --git a/screenshots/de/ui_T_t[f.roomdetails.impl.rolesandpermissions.permissions_ChangeRoomPermissionsView_null_ChangeRoomPermissionsView-Day-11_11_null_0,NEXUS_5,1.0,de].png b/screenshots/de/ui_T_t[f.roomdetails.impl.rolesandpermissions.permissions_ChangeRoomPermissionsView_null_ChangeRoomPermissionsView-Day-14_14_null_0,NEXUS_5,1.0,de].png
similarity index 100%
rename from screenshots/de/ui_T_t[f.roomdetails.impl.rolesandpermissions.permissions_ChangeRoomPermissionsView_null_ChangeRoomPermissionsView-Day-11_11_null_0,NEXUS_5,1.0,de].png
rename to screenshots/de/ui_T_t[f.roomdetails.impl.rolesandpermissions.permissions_ChangeRoomPermissionsView_null_ChangeRoomPermissionsView-Day-14_14_null_0,NEXUS_5,1.0,de].png
diff --git a/screenshots/de/ui_T_t[f.roomdetails.impl.rolesandpermissions.permissions_ChangeRoomPermissionsView_null_ChangeRoomPermissionsView-Day-11_11_null_1,NEXUS_5,1.0,de].png b/screenshots/de/ui_T_t[f.roomdetails.impl.rolesandpermissions.permissions_ChangeRoomPermissionsView_null_ChangeRoomPermissionsView-Day-14_14_null_1,NEXUS_5,1.0,de].png
similarity index 100%
rename from screenshots/de/ui_T_t[f.roomdetails.impl.rolesandpermissions.permissions_ChangeRoomPermissionsView_null_ChangeRoomPermissionsView-Day-11_11_null_1,NEXUS_5,1.0,de].png
rename to screenshots/de/ui_T_t[f.roomdetails.impl.rolesandpermissions.permissions_ChangeRoomPermissionsView_null_ChangeRoomPermissionsView-Day-14_14_null_1,NEXUS_5,1.0,de].png
diff --git a/screenshots/de/ui_T_t[f.roomdetails.impl.rolesandpermissions.permissions_ChangeRoomPermissionsView_null_ChangeRoomPermissionsView-Day-11_11_null_2,NEXUS_5,1.0,de].png b/screenshots/de/ui_T_t[f.roomdetails.impl.rolesandpermissions.permissions_ChangeRoomPermissionsView_null_ChangeRoomPermissionsView-Day-14_14_null_2,NEXUS_5,1.0,de].png
similarity index 100%
rename from screenshots/de/ui_T_t[f.roomdetails.impl.rolesandpermissions.permissions_ChangeRoomPermissionsView_null_ChangeRoomPermissionsView-Day-11_11_null_2,NEXUS_5,1.0,de].png
rename to screenshots/de/ui_T_t[f.roomdetails.impl.rolesandpermissions.permissions_ChangeRoomPermissionsView_null_ChangeRoomPermissionsView-Day-14_14_null_2,NEXUS_5,1.0,de].png
diff --git a/screenshots/de/ui_T_t[f.roomdetails.impl.rolesandpermissions.permissions_ChangeRoomPermissionsView_null_ChangeRoomPermissionsView-Day-11_11_null_3,NEXUS_5,1.0,de].png b/screenshots/de/ui_T_t[f.roomdetails.impl.rolesandpermissions.permissions_ChangeRoomPermissionsView_null_ChangeRoomPermissionsView-Day-14_14_null_3,NEXUS_5,1.0,de].png
similarity index 100%
rename from screenshots/de/ui_T_t[f.roomdetails.impl.rolesandpermissions.permissions_ChangeRoomPermissionsView_null_ChangeRoomPermissionsView-Day-11_11_null_3,NEXUS_5,1.0,de].png
rename to screenshots/de/ui_T_t[f.roomdetails.impl.rolesandpermissions.permissions_ChangeRoomPermissionsView_null_ChangeRoomPermissionsView-Day-14_14_null_3,NEXUS_5,1.0,de].png
diff --git a/screenshots/de/ui_T_t[f.roomdetails.impl.rolesandpermissions.permissions_ChangeRoomPermissionsView_null_ChangeRoomPermissionsView-Day-11_11_null_4,NEXUS_5,1.0,de].png b/screenshots/de/ui_T_t[f.roomdetails.impl.rolesandpermissions.permissions_ChangeRoomPermissionsView_null_ChangeRoomPermissionsView-Day-14_14_null_4,NEXUS_5,1.0,de].png
similarity index 100%
rename from screenshots/de/ui_T_t[f.roomdetails.impl.rolesandpermissions.permissions_ChangeRoomPermissionsView_null_ChangeRoomPermissionsView-Day-11_11_null_4,NEXUS_5,1.0,de].png
rename to screenshots/de/ui_T_t[f.roomdetails.impl.rolesandpermissions.permissions_ChangeRoomPermissionsView_null_ChangeRoomPermissionsView-Day-14_14_null_4,NEXUS_5,1.0,de].png
diff --git a/screenshots/de/ui_T_t[f.roomdetails.impl.rolesandpermissions.permissions_ChangeRoomPermissionsView_null_ChangeRoomPermissionsView-Day-11_11_null_5,NEXUS_5,1.0,de].png b/screenshots/de/ui_T_t[f.roomdetails.impl.rolesandpermissions.permissions_ChangeRoomPermissionsView_null_ChangeRoomPermissionsView-Day-14_14_null_5,NEXUS_5,1.0,de].png
similarity index 100%
rename from screenshots/de/ui_T_t[f.roomdetails.impl.rolesandpermissions.permissions_ChangeRoomPermissionsView_null_ChangeRoomPermissionsView-Day-11_11_null_5,NEXUS_5,1.0,de].png
rename to screenshots/de/ui_T_t[f.roomdetails.impl.rolesandpermissions.permissions_ChangeRoomPermissionsView_null_ChangeRoomPermissionsView-Day-14_14_null_5,NEXUS_5,1.0,de].png
diff --git a/screenshots/de/ui_T_t[f.roomdetails.impl.rolesandpermissions.permissions_ChangeRoomPermissionsView_null_ChangeRoomPermissionsView-Day-11_11_null_6,NEXUS_5,1.0,de].png b/screenshots/de/ui_T_t[f.roomdetails.impl.rolesandpermissions.permissions_ChangeRoomPermissionsView_null_ChangeRoomPermissionsView-Day-14_14_null_6,NEXUS_5,1.0,de].png
similarity index 100%
rename from screenshots/de/ui_T_t[f.roomdetails.impl.rolesandpermissions.permissions_ChangeRoomPermissionsView_null_ChangeRoomPermissionsView-Day-11_11_null_6,NEXUS_5,1.0,de].png
rename to screenshots/de/ui_T_t[f.roomdetails.impl.rolesandpermissions.permissions_ChangeRoomPermissionsView_null_ChangeRoomPermissionsView-Day-14_14_null_6,NEXUS_5,1.0,de].png
diff --git a/screenshots/de/ui_T_t[f.roomdetails.impl.rolesandpermissions_RolesAndPermissionsView_null_RolesAndPermissionsView-Day-8_8_null_0,NEXUS_5,1.0,de].png b/screenshots/de/ui_T_t[f.roomdetails.impl.rolesandpermissions_RolesAndPermissionsView_null_RolesAndPermissionsView-Day-11_11_null_0,NEXUS_5,1.0,de].png
similarity index 100%
rename from screenshots/de/ui_T_t[f.roomdetails.impl.rolesandpermissions_RolesAndPermissionsView_null_RolesAndPermissionsView-Day-8_8_null_0,NEXUS_5,1.0,de].png
rename to screenshots/de/ui_T_t[f.roomdetails.impl.rolesandpermissions_RolesAndPermissionsView_null_RolesAndPermissionsView-Day-11_11_null_0,NEXUS_5,1.0,de].png
diff --git a/screenshots/de/ui_T_t[f.roomdetails.impl.rolesandpermissions_RolesAndPermissionsView_null_RolesAndPermissionsView-Day-8_8_null_1,NEXUS_5,1.0,de].png b/screenshots/de/ui_T_t[f.roomdetails.impl.rolesandpermissions_RolesAndPermissionsView_null_RolesAndPermissionsView-Day-11_11_null_1,NEXUS_5,1.0,de].png
similarity index 100%
rename from screenshots/de/ui_T_t[f.roomdetails.impl.rolesandpermissions_RolesAndPermissionsView_null_RolesAndPermissionsView-Day-8_8_null_1,NEXUS_5,1.0,de].png
rename to screenshots/de/ui_T_t[f.roomdetails.impl.rolesandpermissions_RolesAndPermissionsView_null_RolesAndPermissionsView-Day-11_11_null_1,NEXUS_5,1.0,de].png
diff --git a/screenshots/de/ui_T_t[f.roomdetails.impl.rolesandpermissions_RolesAndPermissionsView_null_RolesAndPermissionsView-Day-8_8_null_2,NEXUS_5,1.0,de].png b/screenshots/de/ui_T_t[f.roomdetails.impl.rolesandpermissions_RolesAndPermissionsView_null_RolesAndPermissionsView-Day-11_11_null_2,NEXUS_5,1.0,de].png
similarity index 100%
rename from screenshots/de/ui_T_t[f.roomdetails.impl.rolesandpermissions_RolesAndPermissionsView_null_RolesAndPermissionsView-Day-8_8_null_2,NEXUS_5,1.0,de].png
rename to screenshots/de/ui_T_t[f.roomdetails.impl.rolesandpermissions_RolesAndPermissionsView_null_RolesAndPermissionsView-Day-11_11_null_2,NEXUS_5,1.0,de].png
diff --git a/screenshots/de/ui_T_t[f.roomdetails.impl.rolesandpermissions_RolesAndPermissionsView_null_RolesAndPermissionsView-Day-8_8_null_3,NEXUS_5,1.0,de].png b/screenshots/de/ui_T_t[f.roomdetails.impl.rolesandpermissions_RolesAndPermissionsView_null_RolesAndPermissionsView-Day-11_11_null_3,NEXUS_5,1.0,de].png
similarity index 100%
rename from screenshots/de/ui_T_t[f.roomdetails.impl.rolesandpermissions_RolesAndPermissionsView_null_RolesAndPermissionsView-Day-8_8_null_3,NEXUS_5,1.0,de].png
rename to screenshots/de/ui_T_t[f.roomdetails.impl.rolesandpermissions_RolesAndPermissionsView_null_RolesAndPermissionsView-Day-11_11_null_3,NEXUS_5,1.0,de].png
diff --git a/screenshots/de/ui_T_t[f.roomdetails.impl.rolesandpermissions_RolesAndPermissionsView_null_RolesAndPermissionsView-Day-8_8_null_4,NEXUS_5,1.0,de].png b/screenshots/de/ui_T_t[f.roomdetails.impl.rolesandpermissions_RolesAndPermissionsView_null_RolesAndPermissionsView-Day-11_11_null_4,NEXUS_5,1.0,de].png
similarity index 100%
rename from screenshots/de/ui_T_t[f.roomdetails.impl.rolesandpermissions_RolesAndPermissionsView_null_RolesAndPermissionsView-Day-8_8_null_4,NEXUS_5,1.0,de].png
rename to screenshots/de/ui_T_t[f.roomdetails.impl.rolesandpermissions_RolesAndPermissionsView_null_RolesAndPermissionsView-Day-11_11_null_4,NEXUS_5,1.0,de].png
diff --git a/screenshots/de/ui_T_t[f.roomdetails.impl.rolesandpermissions_RolesAndPermissionsView_null_RolesAndPermissionsView-Day-8_8_null_5,NEXUS_5,1.0,de].png b/screenshots/de/ui_T_t[f.roomdetails.impl.rolesandpermissions_RolesAndPermissionsView_null_RolesAndPermissionsView-Day-11_11_null_5,NEXUS_5,1.0,de].png
similarity index 100%
rename from screenshots/de/ui_T_t[f.roomdetails.impl.rolesandpermissions_RolesAndPermissionsView_null_RolesAndPermissionsView-Day-8_8_null_5,NEXUS_5,1.0,de].png
rename to screenshots/de/ui_T_t[f.roomdetails.impl.rolesandpermissions_RolesAndPermissionsView_null_RolesAndPermissionsView-Day-11_11_null_5,NEXUS_5,1.0,de].png
diff --git a/screenshots/de/ui_T_t[f.roomdetails.impl.rolesandpermissions_RolesAndPermissionsView_null_RolesAndPermissionsView-Day-8_8_null_6,NEXUS_5,1.0,de].png b/screenshots/de/ui_T_t[f.roomdetails.impl.rolesandpermissions_RolesAndPermissionsView_null_RolesAndPermissionsView-Day-11_11_null_6,NEXUS_5,1.0,de].png
similarity index 100%
rename from screenshots/de/ui_T_t[f.roomdetails.impl.rolesandpermissions_RolesAndPermissionsView_null_RolesAndPermissionsView-Day-8_8_null_6,NEXUS_5,1.0,de].png
rename to screenshots/de/ui_T_t[f.roomdetails.impl.rolesandpermissions_RolesAndPermissionsView_null_RolesAndPermissionsView-Day-11_11_null_6,NEXUS_5,1.0,de].png
diff --git a/screenshots/de/ui_T_t[f.roomdetails.impl.rolesandpermissions_RolesAndPermissionsView_null_RolesAndPermissionsView-Day-8_8_null_7,NEXUS_5,1.0,de].png b/screenshots/de/ui_T_t[f.roomdetails.impl.rolesandpermissions_RolesAndPermissionsView_null_RolesAndPermissionsView-Day-11_11_null_7,NEXUS_5,1.0,de].png
similarity index 100%
rename from screenshots/de/ui_T_t[f.roomdetails.impl.rolesandpermissions_RolesAndPermissionsView_null_RolesAndPermissionsView-Day-8_8_null_7,NEXUS_5,1.0,de].png
rename to screenshots/de/ui_T_t[f.roomdetails.impl.rolesandpermissions_RolesAndPermissionsView_null_RolesAndPermissionsView-Day-11_11_null_7,NEXUS_5,1.0,de].png
diff --git a/screenshots/de/ui_T_t[f.roomdetails.impl_RoomDetailsDark_null_RoomDetailsDark--1_3_null_0,NEXUS_5,1.0,de].png b/screenshots/de/ui_T_t[f.roomdetails.impl_RoomDetailsDark_null_RoomDetailsDark--1_3_null_0,NEXUS_5,1.0,de].png
index c5c43aa906..ada48900b8 100644
--- a/screenshots/de/ui_T_t[f.roomdetails.impl_RoomDetailsDark_null_RoomDetailsDark--1_3_null_0,NEXUS_5,1.0,de].png
+++ b/screenshots/de/ui_T_t[f.roomdetails.impl_RoomDetailsDark_null_RoomDetailsDark--1_3_null_0,NEXUS_5,1.0,de].png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:44e918047c23d4d222d593f0366458a9c8bedb193ab5243681522c8f01e9c463
-size 50997
+oid sha256:f3896ef3aa772637a1afc52e15192c72efc1330d126c9e3951eb7ffc5aedd6f2
+size 54007
diff --git a/screenshots/de/ui_T_t[f.roomdetails.impl_RoomDetailsDark_null_RoomDetailsDark--1_3_null_1,NEXUS_5,1.0,de].png b/screenshots/de/ui_T_t[f.roomdetails.impl_RoomDetailsDark_null_RoomDetailsDark--1_3_null_1,NEXUS_5,1.0,de].png
index c9ddecf9bb..54f01006b3 100644
--- a/screenshots/de/ui_T_t[f.roomdetails.impl_RoomDetailsDark_null_RoomDetailsDark--1_3_null_1,NEXUS_5,1.0,de].png
+++ b/screenshots/de/ui_T_t[f.roomdetails.impl_RoomDetailsDark_null_RoomDetailsDark--1_3_null_1,NEXUS_5,1.0,de].png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:00c07c7e41360abc1f8dad23d13931eba2ecf60254241cf308b135de2ab54add
-size 37640
+oid sha256:8a85c6949fb790c0e6f22c0982ae8e96cf9d49329982b022b5d37ea996c5f7bd
+size 42197
diff --git a/screenshots/de/ui_T_t[f.roomdetails.impl_RoomDetailsDark_null_RoomDetailsDark--1_3_null_10,NEXUS_5,1.0,de].png b/screenshots/de/ui_T_t[f.roomdetails.impl_RoomDetailsDark_null_RoomDetailsDark--1_3_null_10,NEXUS_5,1.0,de].png
new file mode 100644
index 0000000000..e22271058f
--- /dev/null
+++ b/screenshots/de/ui_T_t[f.roomdetails.impl_RoomDetailsDark_null_RoomDetailsDark--1_3_null_10,NEXUS_5,1.0,de].png
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:1b347a9dce374ef48c507a8d1a3cca32feb4e2eaffb32a6bfc035394d565f79e
+size 52468
diff --git a/screenshots/de/ui_T_t[f.roomdetails.impl_RoomDetailsDark_null_RoomDetailsDark--1_3_null_11,NEXUS_5,1.0,de].png b/screenshots/de/ui_T_t[f.roomdetails.impl_RoomDetailsDark_null_RoomDetailsDark--1_3_null_11,NEXUS_5,1.0,de].png
new file mode 100644
index 0000000000..481a1800cf
--- /dev/null
+++ b/screenshots/de/ui_T_t[f.roomdetails.impl_RoomDetailsDark_null_RoomDetailsDark--1_3_null_11,NEXUS_5,1.0,de].png
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:57c1c14683856279f004d754f6c8d7e89bd1899c4f1eb5ec4ee1943c4a7f3a35
+size 50859
diff --git a/screenshots/de/ui_T_t[f.roomdetails.impl_RoomDetailsDark_null_RoomDetailsDark--1_3_null_2,NEXUS_5,1.0,de].png b/screenshots/de/ui_T_t[f.roomdetails.impl_RoomDetailsDark_null_RoomDetailsDark--1_3_null_2,NEXUS_5,1.0,de].png
index 9ca8b51b47..f7773f4db9 100644
--- a/screenshots/de/ui_T_t[f.roomdetails.impl_RoomDetailsDark_null_RoomDetailsDark--1_3_null_2,NEXUS_5,1.0,de].png
+++ b/screenshots/de/ui_T_t[f.roomdetails.impl_RoomDetailsDark_null_RoomDetailsDark--1_3_null_2,NEXUS_5,1.0,de].png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:6bc6bd14a4eab8b7b81146f2f5520103a6ee8de9daba9e1009e91db2a073f355
-size 40660
+oid sha256:e77f46fd8d4440bb4bc08c2c51171b42c88a5bee92a5179f778b784e59491f3c
+size 44565
diff --git a/screenshots/de/ui_T_t[f.roomdetails.impl_RoomDetailsDark_null_RoomDetailsDark--1_3_null_3,NEXUS_5,1.0,de].png b/screenshots/de/ui_T_t[f.roomdetails.impl_RoomDetailsDark_null_RoomDetailsDark--1_3_null_3,NEXUS_5,1.0,de].png
index 4df2219b68..04ea80a5ab 100644
--- a/screenshots/de/ui_T_t[f.roomdetails.impl_RoomDetailsDark_null_RoomDetailsDark--1_3_null_3,NEXUS_5,1.0,de].png
+++ b/screenshots/de/ui_T_t[f.roomdetails.impl_RoomDetailsDark_null_RoomDetailsDark--1_3_null_3,NEXUS_5,1.0,de].png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:6fa63dcbdaff924ac64c6c1928a7bbb86e91aab1a35f5a4a1243a251936b0b41
-size 37251
+oid sha256:5893717b67314df7707593811f4e3afc8cd5b2726903a3d06501e02750658cd9
+size 41688
diff --git a/screenshots/de/ui_T_t[f.roomdetails.impl_RoomDetailsDark_null_RoomDetailsDark--1_3_null_4,NEXUS_5,1.0,de].png b/screenshots/de/ui_T_t[f.roomdetails.impl_RoomDetailsDark_null_RoomDetailsDark--1_3_null_4,NEXUS_5,1.0,de].png
index 15da961e9a..5b1673e3d7 100644
--- a/screenshots/de/ui_T_t[f.roomdetails.impl_RoomDetailsDark_null_RoomDetailsDark--1_3_null_4,NEXUS_5,1.0,de].png
+++ b/screenshots/de/ui_T_t[f.roomdetails.impl_RoomDetailsDark_null_RoomDetailsDark--1_3_null_4,NEXUS_5,1.0,de].png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:0d140ef66dd402e77cdddb6dd2ff95c1b949217712465e18c40a1e0cc507a079
-size 46919
+oid sha256:7756275f75fd22744d9397527101cdbd2a5ce27b8bb6ce3a06595b9b21c23715
+size 50576
diff --git a/screenshots/de/ui_T_t[f.roomdetails.impl_RoomDetailsDark_null_RoomDetailsDark--1_3_null_5,NEXUS_5,1.0,de].png b/screenshots/de/ui_T_t[f.roomdetails.impl_RoomDetailsDark_null_RoomDetailsDark--1_3_null_5,NEXUS_5,1.0,de].png
index f79aea3be2..84ff773469 100644
--- a/screenshots/de/ui_T_t[f.roomdetails.impl_RoomDetailsDark_null_RoomDetailsDark--1_3_null_5,NEXUS_5,1.0,de].png
+++ b/screenshots/de/ui_T_t[f.roomdetails.impl_RoomDetailsDark_null_RoomDetailsDark--1_3_null_5,NEXUS_5,1.0,de].png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:afe5e68f039af77bf35d3e63b737be2124d1e54bab33e08e47d994fb0d351404
-size 46810
+oid sha256:8bec49c42b92e82dc32c22ba9dc6154c262dc3c740fddccdf8dd08945b61e40d
+size 48827
diff --git a/screenshots/de/ui_T_t[f.roomdetails.impl_RoomDetailsDark_null_RoomDetailsDark--1_3_null_6,NEXUS_5,1.0,de].png b/screenshots/de/ui_T_t[f.roomdetails.impl_RoomDetailsDark_null_RoomDetailsDark--1_3_null_6,NEXUS_5,1.0,de].png
index f79aea3be2..84ff773469 100644
--- a/screenshots/de/ui_T_t[f.roomdetails.impl_RoomDetailsDark_null_RoomDetailsDark--1_3_null_6,NEXUS_5,1.0,de].png
+++ b/screenshots/de/ui_T_t[f.roomdetails.impl_RoomDetailsDark_null_RoomDetailsDark--1_3_null_6,NEXUS_5,1.0,de].png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:afe5e68f039af77bf35d3e63b737be2124d1e54bab33e08e47d994fb0d351404
-size 46810
+oid sha256:8bec49c42b92e82dc32c22ba9dc6154c262dc3c740fddccdf8dd08945b61e40d
+size 48827
diff --git a/screenshots/de/ui_T_t[f.roomdetails.impl_RoomDetailsDark_null_RoomDetailsDark--1_3_null_7,NEXUS_5,1.0,de].png b/screenshots/de/ui_T_t[f.roomdetails.impl_RoomDetailsDark_null_RoomDetailsDark--1_3_null_7,NEXUS_5,1.0,de].png
index c4a69849fb..c1835cef1f 100644
--- a/screenshots/de/ui_T_t[f.roomdetails.impl_RoomDetailsDark_null_RoomDetailsDark--1_3_null_7,NEXUS_5,1.0,de].png
+++ b/screenshots/de/ui_T_t[f.roomdetails.impl_RoomDetailsDark_null_RoomDetailsDark--1_3_null_7,NEXUS_5,1.0,de].png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:7bcbfc3b10210bf50d3301eb1794c131372a76fbeed909278d53e12755b96323
-size 50572
+oid sha256:cca4e2cf77796262a9b1a21784f870328e45e6c96a868c08a715e833747028e7
+size 52663
diff --git a/screenshots/de/ui_T_t[f.roomdetails.impl_RoomDetailsDark_null_RoomDetailsDark--1_3_null_8,NEXUS_5,1.0,de].png b/screenshots/de/ui_T_t[f.roomdetails.impl_RoomDetailsDark_null_RoomDetailsDark--1_3_null_8,NEXUS_5,1.0,de].png
index 6984b00c0d..6dd89ecd62 100644
--- a/screenshots/de/ui_T_t[f.roomdetails.impl_RoomDetailsDark_null_RoomDetailsDark--1_3_null_8,NEXUS_5,1.0,de].png
+++ b/screenshots/de/ui_T_t[f.roomdetails.impl_RoomDetailsDark_null_RoomDetailsDark--1_3_null_8,NEXUS_5,1.0,de].png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:1b80a2234144d2d19362177dffc038d0e64f5a543ebc16958cd25f31e8095f40
-size 49004
+oid sha256:6cca379531c07f20fd2c61bac7e4fd6b50f1027b076129e35fb0be36692b4aa4
+size 52786
diff --git a/screenshots/de/ui_T_t[f.roomdetails.impl_RoomDetailsDark_null_RoomDetailsDark--1_3_null_9,NEXUS_5,1.0,de].png b/screenshots/de/ui_T_t[f.roomdetails.impl_RoomDetailsDark_null_RoomDetailsDark--1_3_null_9,NEXUS_5,1.0,de].png
index 96468ad328..a1a0f36e4d 100644
--- a/screenshots/de/ui_T_t[f.roomdetails.impl_RoomDetailsDark_null_RoomDetailsDark--1_3_null_9,NEXUS_5,1.0,de].png
+++ b/screenshots/de/ui_T_t[f.roomdetails.impl_RoomDetailsDark_null_RoomDetailsDark--1_3_null_9,NEXUS_5,1.0,de].png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:04a335c7fa31f7ec14a74d5ff803147fccd49af04ea838d81175d7d396a4607a
-size 48067
+oid sha256:febadf0ae38b731963fbb69496d951d41eeb74138b75c8c86bf04e879c6ef16c
+size 51984
diff --git a/screenshots/de/ui_T_t[f.roomdetails.impl_RoomDetails_null_RoomDetails--0_2_null_0,NEXUS_5,1.0,de].png b/screenshots/de/ui_T_t[f.roomdetails.impl_RoomDetails_null_RoomDetails--0_2_null_0,NEXUS_5,1.0,de].png
index e38e5371fc..7ed63c9e48 100644
--- a/screenshots/de/ui_T_t[f.roomdetails.impl_RoomDetails_null_RoomDetails--0_2_null_0,NEXUS_5,1.0,de].png
+++ b/screenshots/de/ui_T_t[f.roomdetails.impl_RoomDetails_null_RoomDetails--0_2_null_0,NEXUS_5,1.0,de].png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:a28f5b85688736639c13559ed7e473de84f579709779d60b39ff7dcab9d38199
-size 52807
+oid sha256:7fb56b914195a49fcd3c64febe426135efe372162bf7fd7f73ffbcb93155d8ff
+size 56141
diff --git a/screenshots/de/ui_T_t[f.roomdetails.impl_RoomDetails_null_RoomDetails--0_2_null_1,NEXUS_5,1.0,de].png b/screenshots/de/ui_T_t[f.roomdetails.impl_RoomDetails_null_RoomDetails--0_2_null_1,NEXUS_5,1.0,de].png
index 9fe3389591..91b2a038db 100644
--- a/screenshots/de/ui_T_t[f.roomdetails.impl_RoomDetails_null_RoomDetails--0_2_null_1,NEXUS_5,1.0,de].png
+++ b/screenshots/de/ui_T_t[f.roomdetails.impl_RoomDetails_null_RoomDetails--0_2_null_1,NEXUS_5,1.0,de].png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:80f52afd93e5032d6bce8f663f0964669ac55597a9c59de4f4784939527a96f2
-size 39398
+oid sha256:f67f25b6586ced13de021f8ccb2eb63bc3ea7d28c94fbbaffc97f2e0f0783350
+size 44009
diff --git a/screenshots/de/ui_T_t[f.roomdetails.impl_RoomDetails_null_RoomDetails--0_2_null_10,NEXUS_5,1.0,de].png b/screenshots/de/ui_T_t[f.roomdetails.impl_RoomDetails_null_RoomDetails--0_2_null_10,NEXUS_5,1.0,de].png
new file mode 100644
index 0000000000..2b4139d8ef
--- /dev/null
+++ b/screenshots/de/ui_T_t[f.roomdetails.impl_RoomDetails_null_RoomDetails--0_2_null_10,NEXUS_5,1.0,de].png
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:41c0788a5791097108e77414cc3fd8222f1f13d9ea0f85381624246f9f31d0a5
+size 54277
diff --git a/screenshots/de/ui_T_t[f.roomdetails.impl_RoomDetails_null_RoomDetails--0_2_null_11,NEXUS_5,1.0,de].png b/screenshots/de/ui_T_t[f.roomdetails.impl_RoomDetails_null_RoomDetails--0_2_null_11,NEXUS_5,1.0,de].png
new file mode 100644
index 0000000000..1fbf175814
--- /dev/null
+++ b/screenshots/de/ui_T_t[f.roomdetails.impl_RoomDetails_null_RoomDetails--0_2_null_11,NEXUS_5,1.0,de].png
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:d79241f2e8856b8ba10176a5c8fcd6b967cfb8feda2b59c45a272fdc517c2f67
+size 52812
diff --git a/screenshots/de/ui_T_t[f.roomdetails.impl_RoomDetails_null_RoomDetails--0_2_null_2,NEXUS_5,1.0,de].png b/screenshots/de/ui_T_t[f.roomdetails.impl_RoomDetails_null_RoomDetails--0_2_null_2,NEXUS_5,1.0,de].png
index a3af7cbe90..844c6248bc 100644
--- a/screenshots/de/ui_T_t[f.roomdetails.impl_RoomDetails_null_RoomDetails--0_2_null_2,NEXUS_5,1.0,de].png
+++ b/screenshots/de/ui_T_t[f.roomdetails.impl_RoomDetails_null_RoomDetails--0_2_null_2,NEXUS_5,1.0,de].png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:6152f4e2c02c7c121ce84d27dcba01dedfe544500d4a5975c237540da94ff4ef
-size 42677
+oid sha256:62de5e6c18be633ccd3509a41ca8079a839c9c474b2e10cd83e52a33ddac02a0
+size 46683
diff --git a/screenshots/de/ui_T_t[f.roomdetails.impl_RoomDetails_null_RoomDetails--0_2_null_3,NEXUS_5,1.0,de].png b/screenshots/de/ui_T_t[f.roomdetails.impl_RoomDetails_null_RoomDetails--0_2_null_3,NEXUS_5,1.0,de].png
index 8639a4a1ad..ae540eccc6 100644
--- a/screenshots/de/ui_T_t[f.roomdetails.impl_RoomDetails_null_RoomDetails--0_2_null_3,NEXUS_5,1.0,de].png
+++ b/screenshots/de/ui_T_t[f.roomdetails.impl_RoomDetails_null_RoomDetails--0_2_null_3,NEXUS_5,1.0,de].png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:d51ab086c562326de82edb58e4f7c33fee1ab0e3eb73f44aabaab783cf95cb8f
-size 38372
+oid sha256:2109b1606eae24e5c35eb388b475cca8b44b2dca01c177eaba7c59956d87cee8
+size 43221
diff --git a/screenshots/de/ui_T_t[f.roomdetails.impl_RoomDetails_null_RoomDetails--0_2_null_4,NEXUS_5,1.0,de].png b/screenshots/de/ui_T_t[f.roomdetails.impl_RoomDetails_null_RoomDetails--0_2_null_4,NEXUS_5,1.0,de].png
index 50827c99ce..9046c4da30 100644
--- a/screenshots/de/ui_T_t[f.roomdetails.impl_RoomDetails_null_RoomDetails--0_2_null_4,NEXUS_5,1.0,de].png
+++ b/screenshots/de/ui_T_t[f.roomdetails.impl_RoomDetails_null_RoomDetails--0_2_null_4,NEXUS_5,1.0,de].png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:020766a74ac77c88b6becf982ebf5855a0fed012818f536505bf22c955210253
-size 48645
+oid sha256:412e827894411b887258c79af074786b5474f84a5912492727d8912f874051eb
+size 52499
diff --git a/screenshots/de/ui_T_t[f.roomdetails.impl_RoomDetails_null_RoomDetails--0_2_null_5,NEXUS_5,1.0,de].png b/screenshots/de/ui_T_t[f.roomdetails.impl_RoomDetails_null_RoomDetails--0_2_null_5,NEXUS_5,1.0,de].png
index c3dadf7c2a..3cef94de52 100644
--- a/screenshots/de/ui_T_t[f.roomdetails.impl_RoomDetails_null_RoomDetails--0_2_null_5,NEXUS_5,1.0,de].png
+++ b/screenshots/de/ui_T_t[f.roomdetails.impl_RoomDetails_null_RoomDetails--0_2_null_5,NEXUS_5,1.0,de].png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:4eb98765b3b0d2f220bb5ccd1f0535049e3592c0496528e72b0367d739e7b3ce
-size 48291
+oid sha256:adaed8b3fa4315201b64ddfceb4c0b2231e7b991f89949765ff898973162f6b3
+size 50564
diff --git a/screenshots/de/ui_T_t[f.roomdetails.impl_RoomDetails_null_RoomDetails--0_2_null_6,NEXUS_5,1.0,de].png b/screenshots/de/ui_T_t[f.roomdetails.impl_RoomDetails_null_RoomDetails--0_2_null_6,NEXUS_5,1.0,de].png
index c3dadf7c2a..3cef94de52 100644
--- a/screenshots/de/ui_T_t[f.roomdetails.impl_RoomDetails_null_RoomDetails--0_2_null_6,NEXUS_5,1.0,de].png
+++ b/screenshots/de/ui_T_t[f.roomdetails.impl_RoomDetails_null_RoomDetails--0_2_null_6,NEXUS_5,1.0,de].png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:4eb98765b3b0d2f220bb5ccd1f0535049e3592c0496528e72b0367d739e7b3ce
-size 48291
+oid sha256:adaed8b3fa4315201b64ddfceb4c0b2231e7b991f89949765ff898973162f6b3
+size 50564
diff --git a/screenshots/de/ui_T_t[f.roomdetails.impl_RoomDetails_null_RoomDetails--0_2_null_7,NEXUS_5,1.0,de].png b/screenshots/de/ui_T_t[f.roomdetails.impl_RoomDetails_null_RoomDetails--0_2_null_7,NEXUS_5,1.0,de].png
index 49e6a10c6e..bc6e8f8d48 100644
--- a/screenshots/de/ui_T_t[f.roomdetails.impl_RoomDetails_null_RoomDetails--0_2_null_7,NEXUS_5,1.0,de].png
+++ b/screenshots/de/ui_T_t[f.roomdetails.impl_RoomDetails_null_RoomDetails--0_2_null_7,NEXUS_5,1.0,de].png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:483e119fa4eb4dd1b56dec01409756aa419a6cc450624ca44287e74c19d94009
-size 52367
+oid sha256:ee8ebf7de471d0515f2bf214e782e57df3d9738760015ae3a93ad20526f1b0b7
+size 54341
diff --git a/screenshots/de/ui_T_t[f.roomdetails.impl_RoomDetails_null_RoomDetails--0_2_null_8,NEXUS_5,1.0,de].png b/screenshots/de/ui_T_t[f.roomdetails.impl_RoomDetails_null_RoomDetails--0_2_null_8,NEXUS_5,1.0,de].png
index 135a48b6fb..0404915ee3 100644
--- a/screenshots/de/ui_T_t[f.roomdetails.impl_RoomDetails_null_RoomDetails--0_2_null_8,NEXUS_5,1.0,de].png
+++ b/screenshots/de/ui_T_t[f.roomdetails.impl_RoomDetails_null_RoomDetails--0_2_null_8,NEXUS_5,1.0,de].png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:186e1d4c6eff0862cbacac6d5e6b013512e6bebdca0301c9fa62635904f192f7
-size 50785
+oid sha256:fd285a7b20189ca9b96fc256fb23dee283b7567d889bee219b15e7938641f9aa
+size 54701
diff --git a/screenshots/de/ui_T_t[f.roomdetails.impl_RoomDetails_null_RoomDetails--0_2_null_9,NEXUS_5,1.0,de].png b/screenshots/de/ui_T_t[f.roomdetails.impl_RoomDetails_null_RoomDetails--0_2_null_9,NEXUS_5,1.0,de].png
index bd944a3811..906e5e951e 100644
--- a/screenshots/de/ui_T_t[f.roomdetails.impl_RoomDetails_null_RoomDetails--0_2_null_9,NEXUS_5,1.0,de].png
+++ b/screenshots/de/ui_T_t[f.roomdetails.impl_RoomDetails_null_RoomDetails--0_2_null_9,NEXUS_5,1.0,de].png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:3d0eb2a86db686009297251a6365f0e3e56eddb92f42e3480b1df2e065aa80a2
-size 49672
+oid sha256:4b9be6e6f720f22a9e7cc585fa0e4654f268ec3c0956cb0f7d6bcc1704540c73
+size 53791
diff --git a/screenshots/de/ui_T_t[f.roomdirectory.impl.root_RoomDirectoryView_null_RoomDirectoryView-Day-0_1_null_1,NEXUS_5,1.0,de].png b/screenshots/de/ui_T_t[f.roomdirectory.impl.root_RoomDirectoryView_null_RoomDirectoryView-Day-0_1_null_1,NEXUS_5,1.0,de].png
index e610fd8517..1580acca20 100644
--- a/screenshots/de/ui_T_t[f.roomdirectory.impl.root_RoomDirectoryView_null_RoomDirectoryView-Day-0_1_null_1,NEXUS_5,1.0,de].png
+++ b/screenshots/de/ui_T_t[f.roomdirectory.impl.root_RoomDirectoryView_null_RoomDirectoryView-Day-0_1_null_1,NEXUS_5,1.0,de].png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:70d52b2836caa2ee78dedbace5cd8712569b72bf2ab62995037443570ed60120
-size 31176
+oid sha256:f335e9690df1c4a148e3ea3b19a623b47b4ceadcccd9d679f5146bdd834f046d
+size 30822
diff --git a/screenshots/de/ui_T_t[f.roomdirectory.impl.root_RoomDirectoryView_null_RoomDirectoryView-Day-0_1_null_2,NEXUS_5,1.0,de].png b/screenshots/de/ui_T_t[f.roomdirectory.impl.root_RoomDirectoryView_null_RoomDirectoryView-Day-0_1_null_2,NEXUS_5,1.0,de].png
index bfc8b1e7a7..efdff3c40f 100644
--- a/screenshots/de/ui_T_t[f.roomdirectory.impl.root_RoomDirectoryView_null_RoomDirectoryView-Day-0_1_null_2,NEXUS_5,1.0,de].png
+++ b/screenshots/de/ui_T_t[f.roomdirectory.impl.root_RoomDirectoryView_null_RoomDirectoryView-Day-0_1_null_2,NEXUS_5,1.0,de].png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:0b473dbb8e5f522dc3f0f0f55c3ffec3e63eb01b6b8dc4a4d0583e0bd490ec16
-size 33030
+oid sha256:0efc73384e754500899736dd0595edf6fca3c448d896902d5611f6aedca4415b
+size 32668
diff --git a/screenshots/de/ui_T_t[f.roomdirectory.impl.root_RoomDirectoryView_null_RoomDirectoryView-Day-0_1_null_3,NEXUS_5,1.0,de].png b/screenshots/de/ui_T_t[f.roomdirectory.impl.root_RoomDirectoryView_null_RoomDirectoryView-Day-0_1_null_3,NEXUS_5,1.0,de].png
deleted file mode 100644
index 6e6eb19f30..0000000000
--- a/screenshots/de/ui_T_t[f.roomdirectory.impl.root_RoomDirectoryView_null_RoomDirectoryView-Day-0_1_null_3,NEXUS_5,1.0,de].png
+++ /dev/null
@@ -1,3 +0,0 @@
-version https://git-lfs.github.com/spec/v1
-oid sha256:12e92afc4d44e01074aed18e3cd3954fd6a2624f68459def1a9aa19f776d08bc
-size 32072
diff --git a/screenshots/de/ui_T_t[f.roomdirectory.impl.root_RoomDirectoryView_null_RoomDirectoryView-Day-0_1_null_4,NEXUS_5,1.0,de].png b/screenshots/de/ui_T_t[f.roomdirectory.impl.root_RoomDirectoryView_null_RoomDirectoryView-Day-0_1_null_4,NEXUS_5,1.0,de].png
deleted file mode 100644
index afdf7584a2..0000000000
--- a/screenshots/de/ui_T_t[f.roomdirectory.impl.root_RoomDirectoryView_null_RoomDirectoryView-Day-0_1_null_4,NEXUS_5,1.0,de].png
+++ /dev/null
@@ -1,3 +0,0 @@
-version https://git-lfs.github.com/spec/v1
-oid sha256:152c87a2d68c2da7f7dad0fa09ac72ec81a001d17ba292cf25ac63f7ca922b59
-size 36286
diff --git a/screenshots/de/ui_T_t[f.userprofile.shared_UserProfileView_null_UserProfileView-Day-0_1_null_0,NEXUS_5,1.0,de].png b/screenshots/de/ui_T_t[f.userprofile.shared_UserProfileView_null_UserProfileView-Day-0_1_null_0,NEXUS_5,1.0,de].png
index aa9894c978..b83e2e9323 100644
--- a/screenshots/de/ui_T_t[f.userprofile.shared_UserProfileView_null_UserProfileView-Day-0_1_null_0,NEXUS_5,1.0,de].png
+++ b/screenshots/de/ui_T_t[f.userprofile.shared_UserProfileView_null_UserProfileView-Day-0_1_null_0,NEXUS_5,1.0,de].png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:31040b2d573029b5a412dde7605e29b5098f895e8d3e86d646fa485203e71992
-size 24989
+oid sha256:29533002f7bca46ba3afecfa45dabe220b8b9908d5735f64ac2cebb048a72e5e
+size 23485
diff --git a/screenshots/de/ui_T_t[f.userprofile.shared_UserProfileView_null_UserProfileView-Day-0_1_null_1,NEXUS_5,1.0,de].png b/screenshots/de/ui_T_t[f.userprofile.shared_UserProfileView_null_UserProfileView-Day-0_1_null_1,NEXUS_5,1.0,de].png
index 5a6c028f58..323be582e4 100644
--- a/screenshots/de/ui_T_t[f.userprofile.shared_UserProfileView_null_UserProfileView-Day-0_1_null_1,NEXUS_5,1.0,de].png
+++ b/screenshots/de/ui_T_t[f.userprofile.shared_UserProfileView_null_UserProfileView-Day-0_1_null_1,NEXUS_5,1.0,de].png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:0426f5b82ee1469bead50b8c925646c20aa16a270f2f07b2c86cf595a7de6b20
-size 22561
+oid sha256:ded4855799f7d55a7bc4ed498a4795be6df6638c0a7f0d1a9436d427dd977fda
+size 21507
diff --git a/screenshots/de/ui_T_t[f.userprofile.shared_UserProfileView_null_UserProfileView-Day-0_1_null_2,NEXUS_5,1.0,de].png b/screenshots/de/ui_T_t[f.userprofile.shared_UserProfileView_null_UserProfileView-Day-0_1_null_2,NEXUS_5,1.0,de].png
index c6641e6d07..73811a32dd 100644
--- a/screenshots/de/ui_T_t[f.userprofile.shared_UserProfileView_null_UserProfileView-Day-0_1_null_2,NEXUS_5,1.0,de].png
+++ b/screenshots/de/ui_T_t[f.userprofile.shared_UserProfileView_null_UserProfileView-Day-0_1_null_2,NEXUS_5,1.0,de].png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:cf5b10d4453bac71209799f8e68bfd41985c12bcd19d81ee0b81a34c7854d948
-size 25513
+oid sha256:0423baeddaa9b48b51d596ff8264e02c3997de110d68322431a44ed26d596e28
+size 23889
diff --git a/screenshots/de/ui_T_t[f.userprofile.shared_UserProfileView_null_UserProfileView-Day-0_1_null_3,NEXUS_5,1.0,de].png b/screenshots/de/ui_T_t[f.userprofile.shared_UserProfileView_null_UserProfileView-Day-0_1_null_3,NEXUS_5,1.0,de].png
index fdc900b35e..acbd5401ac 100644
--- a/screenshots/de/ui_T_t[f.userprofile.shared_UserProfileView_null_UserProfileView-Day-0_1_null_3,NEXUS_5,1.0,de].png
+++ b/screenshots/de/ui_T_t[f.userprofile.shared_UserProfileView_null_UserProfileView-Day-0_1_null_3,NEXUS_5,1.0,de].png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:595dde5f7198f76dea6ac81feacd3a35985a1ee203950a81e9d72fec52c57a3b
-size 48375
+oid sha256:4dfa5d39edfa19e9cb3c69da321260d0dcaa133fbde1a33e3fdff6ccd29c43f5
+size 48167
diff --git a/screenshots/de/ui_T_t[f.userprofile.shared_UserProfileView_null_UserProfileView-Day-0_1_null_4,NEXUS_5,1.0,de].png b/screenshots/de/ui_T_t[f.userprofile.shared_UserProfileView_null_UserProfileView-Day-0_1_null_4,NEXUS_5,1.0,de].png
index 0d5055b3a1..97f3903515 100644
--- a/screenshots/de/ui_T_t[f.userprofile.shared_UserProfileView_null_UserProfileView-Day-0_1_null_4,NEXUS_5,1.0,de].png
+++ b/screenshots/de/ui_T_t[f.userprofile.shared_UserProfileView_null_UserProfileView-Day-0_1_null_4,NEXUS_5,1.0,de].png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:b83ffc3f04e84bdd8a6a81a5240272509b55796ae610a77e04e55db616a72f02
-size 42634
+oid sha256:9f8e31b0f577715124fed9394cc2b5117b6fbd516c64e7b071db5b973f740608
+size 42431
diff --git a/screenshots/de/ui_T_t[f.userprofile.shared_UserProfileView_null_UserProfileView-Day-0_1_null_5,NEXUS_5,1.0,de].png b/screenshots/de/ui_T_t[f.userprofile.shared_UserProfileView_null_UserProfileView-Day-0_1_null_5,NEXUS_5,1.0,de].png
index 90ed8002d5..05a5bc7065 100644
--- a/screenshots/de/ui_T_t[f.userprofile.shared_UserProfileView_null_UserProfileView-Day-0_1_null_5,NEXUS_5,1.0,de].png
+++ b/screenshots/de/ui_T_t[f.userprofile.shared_UserProfileView_null_UserProfileView-Day-0_1_null_5,NEXUS_5,1.0,de].png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:83662f34669ebdf973e03383fe455129910d493ef79c5b09ea5235978d5fd0ab
-size 26112
+oid sha256:0914c756819767162b855885a3b313cfffdb5a499667d5d05698fae8648137cf
+size 24539
diff --git a/screenshots/de/ui_T_t[f.userprofile.shared_UserProfileView_null_UserProfileView-Day-0_1_null_6,NEXUS_5,1.0,de].png b/screenshots/de/ui_T_t[f.userprofile.shared_UserProfileView_null_UserProfileView-Day-0_1_null_6,NEXUS_5,1.0,de].png
index e24661cc00..784f9fb85e 100644
--- a/screenshots/de/ui_T_t[f.userprofile.shared_UserProfileView_null_UserProfileView-Day-0_1_null_6,NEXUS_5,1.0,de].png
+++ b/screenshots/de/ui_T_t[f.userprofile.shared_UserProfileView_null_UserProfileView-Day-0_1_null_6,NEXUS_5,1.0,de].png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:2c430dcbfe7123f2dcdb0dbce1de011506438799f189e4a92d0d590921427eb7
-size 27839
+oid sha256:15357bef213fea5de70a9e23072a207008c5658795b5765686fd827c02abf556
+size 23838
diff --git a/screenshots/de/ui_T_t[f.userprofile.shared_UserProfileView_null_UserProfileView-Day-0_1_null_7,NEXUS_5,1.0,de].png b/screenshots/de/ui_T_t[f.userprofile.shared_UserProfileView_null_UserProfileView-Day-0_1_null_7,NEXUS_5,1.0,de].png
new file mode 100644
index 0000000000..d4576b0f9d
--- /dev/null
+++ b/screenshots/de/ui_T_t[f.userprofile.shared_UserProfileView_null_UserProfileView-Day-0_1_null_7,NEXUS_5,1.0,de].png
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:4997cc22c36d135e6e62f93c666d0a9e43941dd34f9b7d0d87619d4b1185567a
+size 24584
diff --git a/screenshots/de/ui_T_t[f.userprofile.shared_UserProfileView_null_UserProfileView-Day-0_1_null_8,NEXUS_5,1.0,de].png b/screenshots/de/ui_T_t[f.userprofile.shared_UserProfileView_null_UserProfileView-Day-0_1_null_8,NEXUS_5,1.0,de].png
new file mode 100644
index 0000000000..b83e2e9323
--- /dev/null
+++ b/screenshots/de/ui_T_t[f.userprofile.shared_UserProfileView_null_UserProfileView-Day-0_1_null_8,NEXUS_5,1.0,de].png
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:29533002f7bca46ba3afecfa45dabe220b8b9908d5735f64ac2cebb048a72e5e
+size 23485
diff --git a/screenshots/de/ui_T_t[l.matrix.ui.components_AvatarActionBottomSheet_null_AvatarActionBottomSheet-Day-1_2_null,NEXUS_5,1.0,de].png b/screenshots/de/ui_T_t[l.matrix.ui.components_AvatarActionBottomSheet_null_AvatarActionBottomSheet-Day-1_2_null,NEXUS_5,1.0,de].png
index de6fc0ebff..e95ffbbaa8 100644
--- a/screenshots/de/ui_T_t[l.matrix.ui.components_AvatarActionBottomSheet_null_AvatarActionBottomSheet-Day-1_2_null,NEXUS_5,1.0,de].png
+++ b/screenshots/de/ui_T_t[l.matrix.ui.components_AvatarActionBottomSheet_null_AvatarActionBottomSheet-Day-1_2_null,NEXUS_5,1.0,de].png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:ada93c6c7e4f0cb3a24332cbf2df7f12038d9a1635cdd3f5ac29f7ffcc173d49
-size 15769
+oid sha256:8697a41a0154a9d9b6eb91f4ed9d3d9c76c5e8a99acf5ee885ab8b7a282ed54c
+size 15882
diff --git a/screenshots/de/ui_T_t[l.matrix.ui.components_InviteSenderView_null_InviteSenderView-Day-2_3_null,NEXUS_5,1.0,de].png b/screenshots/de/ui_T_t[l.matrix.ui.components_InviteSenderView_null_InviteSenderView-Day-3_4_null,NEXUS_5,1.0,de].png
similarity index 100%
rename from screenshots/de/ui_T_t[l.matrix.ui.components_InviteSenderView_null_InviteSenderView-Day-2_3_null,NEXUS_5,1.0,de].png
rename to screenshots/de/ui_T_t[l.matrix.ui.components_InviteSenderView_null_InviteSenderView-Day-3_4_null,NEXUS_5,1.0,de].png
diff --git a/screenshots/html/data.js b/screenshots/html/data.js
index c492a1045f..816ae111cf 100644
--- a/screenshots/html/data.js
+++ b/screenshots/html/data.js
@@ -1,40 +1,40 @@
// Generated file, do not edit
export const screenshots = [
["en","en-dark","de",],
-["ui_S_t[f.preferences.impl.about_AboutView_null_AboutView-Day-0_1_null_0,NEXUS_5,1.0,en]","ui_S_t[f.preferences.impl.about_AboutView_null_AboutView-Night-0_2_null_0,NEXUS_5,1.0,en]",19846,],
+["ui_S_t[f.preferences.impl.about_AboutView_null_AboutView-Day-0_1_null_0,NEXUS_5,1.0,en]","ui_S_t[f.preferences.impl.about_AboutView_null_AboutView-Night-0_2_null_0,NEXUS_5,1.0,en]",19860,],
["ui_S_t[f.invite.impl.response_AcceptDeclineInviteView_null_AcceptDeclineInviteView-Day-0_1_null_0,NEXUS_5,1.0,en]","ui_S_t[f.invite.impl.response_AcceptDeclineInviteView_null_AcceptDeclineInviteView-Night-0_2_null_0,NEXUS_5,1.0,en]",0,],
-["ui_S_t[f.invite.impl.response_AcceptDeclineInviteView_null_AcceptDeclineInviteView-Day-0_1_null_1,NEXUS_5,1.0,en]","ui_S_t[f.invite.impl.response_AcceptDeclineInviteView_null_AcceptDeclineInviteView-Night-0_2_null_1,NEXUS_5,1.0,en]",19846,],
-["ui_S_t[f.invite.impl.response_AcceptDeclineInviteView_null_AcceptDeclineInviteView-Day-0_1_null_2,NEXUS_5,1.0,en]","ui_S_t[f.invite.impl.response_AcceptDeclineInviteView_null_AcceptDeclineInviteView-Night-0_2_null_2,NEXUS_5,1.0,en]",19846,],
-["ui_S_t[f.invite.impl.response_AcceptDeclineInviteView_null_AcceptDeclineInviteView-Day-0_1_null_3,NEXUS_5,1.0,en]","ui_S_t[f.invite.impl.response_AcceptDeclineInviteView_null_AcceptDeclineInviteView-Night-0_2_null_3,NEXUS_5,1.0,en]",19846,],
-["ui_S_t[f.invite.impl.response_AcceptDeclineInviteView_null_AcceptDeclineInviteView-Day-0_1_null_4,NEXUS_5,1.0,en]","ui_S_t[f.invite.impl.response_AcceptDeclineInviteView_null_AcceptDeclineInviteView-Night-0_2_null_4,NEXUS_5,1.0,en]",19846,],
+["ui_S_t[f.invite.impl.response_AcceptDeclineInviteView_null_AcceptDeclineInviteView-Day-0_1_null_1,NEXUS_5,1.0,en]","ui_S_t[f.invite.impl.response_AcceptDeclineInviteView_null_AcceptDeclineInviteView-Night-0_2_null_1,NEXUS_5,1.0,en]",19860,],
+["ui_S_t[f.invite.impl.response_AcceptDeclineInviteView_null_AcceptDeclineInviteView-Day-0_1_null_2,NEXUS_5,1.0,en]","ui_S_t[f.invite.impl.response_AcceptDeclineInviteView_null_AcceptDeclineInviteView-Night-0_2_null_2,NEXUS_5,1.0,en]",19860,],
+["ui_S_t[f.invite.impl.response_AcceptDeclineInviteView_null_AcceptDeclineInviteView-Day-0_1_null_3,NEXUS_5,1.0,en]","ui_S_t[f.invite.impl.response_AcceptDeclineInviteView_null_AcceptDeclineInviteView-Night-0_2_null_3,NEXUS_5,1.0,en]",19860,],
+["ui_S_t[f.invite.impl.response_AcceptDeclineInviteView_null_AcceptDeclineInviteView-Day-0_1_null_4,NEXUS_5,1.0,en]","ui_S_t[f.invite.impl.response_AcceptDeclineInviteView_null_AcceptDeclineInviteView-Night-0_2_null_4,NEXUS_5,1.0,en]",19860,],
["ui_S_t[f.login.impl.accountprovider_AccountProviderView_null_AccountProviderView-Day-0_1_null_0,NEXUS_5,1.0,en]","ui_S_t[f.login.impl.accountprovider_AccountProviderView_null_AccountProviderView-Night-0_2_null_0,NEXUS_5,1.0,en]",0,],
["ui_S_t[f.login.impl.accountprovider_AccountProviderView_null_AccountProviderView-Day-0_1_null_1,NEXUS_5,1.0,en]","ui_S_t[f.login.impl.accountprovider_AccountProviderView_null_AccountProviderView-Night-0_2_null_1,NEXUS_5,1.0,en]",0,],
["ui_S_t[f.login.impl.accountprovider_AccountProviderView_null_AccountProviderView-Day-0_1_null_2,NEXUS_5,1.0,en]","ui_S_t[f.login.impl.accountprovider_AccountProviderView_null_AccountProviderView-Night-0_2_null_2,NEXUS_5,1.0,en]",0,],
["ui_S_t[f.login.impl.accountprovider_AccountProviderView_null_AccountProviderView-Day-0_1_null_3,NEXUS_5,1.0,en]","ui_S_t[f.login.impl.accountprovider_AccountProviderView_null_AccountProviderView-Night-0_2_null_3,NEXUS_5,1.0,en]",0,],
["ui_S_t[f.login.impl.accountprovider_AccountProviderView_null_AccountProviderView-Day-0_1_null_4,NEXUS_5,1.0,en]","ui_S_t[f.login.impl.accountprovider_AccountProviderView_null_AccountProviderView-Night-0_2_null_4,NEXUS_5,1.0,en]",0,],
-["ui_S_t[f.createroom.impl.addpeople_AddPeopleView_null_AddPeopleView-Day-0_1_null_0,NEXUS_5,1.0,en]","ui_S_t[f.createroom.impl.addpeople_AddPeopleView_null_AddPeopleView-Night-0_2_null_0,NEXUS_5,1.0,en]",19846,],
-["ui_S_t[f.createroom.impl.addpeople_AddPeopleView_null_AddPeopleView-Day-0_1_null_1,NEXUS_5,1.0,en]","ui_S_t[f.createroom.impl.addpeople_AddPeopleView_null_AddPeopleView-Night-0_2_null_1,NEXUS_5,1.0,en]",19846,],
-["ui_S_t[f.createroom.impl.addpeople_AddPeopleView_null_AddPeopleView-Day-0_1_null_2,NEXUS_5,1.0,en]","ui_S_t[f.createroom.impl.addpeople_AddPeopleView_null_AddPeopleView-Night-0_2_null_2,NEXUS_5,1.0,en]",19846,],
-["ui_S_t[f.createroom.impl.addpeople_AddPeopleView_null_AddPeopleView-Day-0_1_null_3,NEXUS_5,1.0,en]","ui_S_t[f.createroom.impl.addpeople_AddPeopleView_null_AddPeopleView-Night-0_2_null_3,NEXUS_5,1.0,en]",19846,],
-["ui_S_t[f.preferences.impl.advanced_AdvancedSettingsView_null_AdvancedSettingsView-Day-1_2_null_0,NEXUS_5,1.0,en]","ui_S_t[f.preferences.impl.advanced_AdvancedSettingsView_null_AdvancedSettingsView-Night-1_3_null_0,NEXUS_5,1.0,en]",19846,],
-["ui_S_t[f.preferences.impl.advanced_AdvancedSettingsView_null_AdvancedSettingsView-Day-1_2_null_1,NEXUS_5,1.0,en]","ui_S_t[f.preferences.impl.advanced_AdvancedSettingsView_null_AdvancedSettingsView-Night-1_3_null_1,NEXUS_5,1.0,en]",19846,],
-["ui_S_t[f.preferences.impl.advanced_AdvancedSettingsView_null_AdvancedSettingsView-Day-1_2_null_2,NEXUS_5,1.0,en]","ui_S_t[f.preferences.impl.advanced_AdvancedSettingsView_null_AdvancedSettingsView-Night-1_3_null_2,NEXUS_5,1.0,en]",19846,],
-["ui_S_t[f.preferences.impl.advanced_AdvancedSettingsView_null_AdvancedSettingsView-Day-1_2_null_3,NEXUS_5,1.0,en]","ui_S_t[f.preferences.impl.advanced_AdvancedSettingsView_null_AdvancedSettingsView-Night-1_3_null_3,NEXUS_5,1.0,en]",19846,],
-["ui_S_t[f.preferences.impl.advanced_AdvancedSettingsView_null_AdvancedSettingsView-Day-1_2_null_4,NEXUS_5,1.0,en]","ui_S_t[f.preferences.impl.advanced_AdvancedSettingsView_null_AdvancedSettingsView-Night-1_3_null_4,NEXUS_5,1.0,en]",19846,],
-["ui_S_t[f.analytics.impl_AnalyticsOptInView_null_AnalyticsOptInView-Day-0_1_null_0,NEXUS_5,1.0,en]","ui_S_t[f.analytics.impl_AnalyticsOptInView_null_AnalyticsOptInView-Night-0_2_null_0,NEXUS_5,1.0,en]",19846,],
-["ui_S_t[f.analytics.api.preferences_AnalyticsPreferencesView_null_AnalyticsPreferencesView-Day-0_1_null_0,NEXUS_5,1.0,en]","ui_S_t[f.analytics.api.preferences_AnalyticsPreferencesView_null_AnalyticsPreferencesView-Night-0_2_null_0,NEXUS_5,1.0,en]",19846,],
-["ui_S_t[f.preferences.impl.analytics_AnalyticsSettingsView_null_AnalyticsSettingsView-Day-2_3_null_0,NEXUS_5,1.0,en]","ui_S_t[f.preferences.impl.analytics_AnalyticsSettingsView_null_AnalyticsSettingsView-Night-2_4_null_0,NEXUS_5,1.0,en]",19846,],
-["ui_S_t[services.apperror.impl_AppErrorView_null_AppErrorView-Day-0_1_null,NEXUS_5,1.0,en]","ui_S_t[services.apperror.impl_AppErrorView_null_AppErrorView-Night-0_2_null,NEXUS_5,1.0,en]",19846,],
+["ui_S_t[f.createroom.impl.addpeople_AddPeopleView_null_AddPeopleView-Day-0_1_null_0,NEXUS_5,1.0,en]","ui_S_t[f.createroom.impl.addpeople_AddPeopleView_null_AddPeopleView-Night-0_2_null_0,NEXUS_5,1.0,en]",19860,],
+["ui_S_t[f.createroom.impl.addpeople_AddPeopleView_null_AddPeopleView-Day-0_1_null_1,NEXUS_5,1.0,en]","ui_S_t[f.createroom.impl.addpeople_AddPeopleView_null_AddPeopleView-Night-0_2_null_1,NEXUS_5,1.0,en]",19860,],
+["ui_S_t[f.createroom.impl.addpeople_AddPeopleView_null_AddPeopleView-Day-0_1_null_2,NEXUS_5,1.0,en]","ui_S_t[f.createroom.impl.addpeople_AddPeopleView_null_AddPeopleView-Night-0_2_null_2,NEXUS_5,1.0,en]",19860,],
+["ui_S_t[f.createroom.impl.addpeople_AddPeopleView_null_AddPeopleView-Day-0_1_null_3,NEXUS_5,1.0,en]","ui_S_t[f.createroom.impl.addpeople_AddPeopleView_null_AddPeopleView-Night-0_2_null_3,NEXUS_5,1.0,en]",19860,],
+["ui_S_t[f.preferences.impl.advanced_AdvancedSettingsView_null_AdvancedSettingsView-Day-1_2_null_0,NEXUS_5,1.0,en]","ui_S_t[f.preferences.impl.advanced_AdvancedSettingsView_null_AdvancedSettingsView-Night-1_3_null_0,NEXUS_5,1.0,en]",19860,],
+["ui_S_t[f.preferences.impl.advanced_AdvancedSettingsView_null_AdvancedSettingsView-Day-1_2_null_1,NEXUS_5,1.0,en]","ui_S_t[f.preferences.impl.advanced_AdvancedSettingsView_null_AdvancedSettingsView-Night-1_3_null_1,NEXUS_5,1.0,en]",19860,],
+["ui_S_t[f.preferences.impl.advanced_AdvancedSettingsView_null_AdvancedSettingsView-Day-1_2_null_2,NEXUS_5,1.0,en]","ui_S_t[f.preferences.impl.advanced_AdvancedSettingsView_null_AdvancedSettingsView-Night-1_3_null_2,NEXUS_5,1.0,en]",19860,],
+["ui_S_t[f.preferences.impl.advanced_AdvancedSettingsView_null_AdvancedSettingsView-Day-1_2_null_3,NEXUS_5,1.0,en]","ui_S_t[f.preferences.impl.advanced_AdvancedSettingsView_null_AdvancedSettingsView-Night-1_3_null_3,NEXUS_5,1.0,en]",19860,],
+["ui_S_t[f.preferences.impl.advanced_AdvancedSettingsView_null_AdvancedSettingsView-Day-1_2_null_4,NEXUS_5,1.0,en]","ui_S_t[f.preferences.impl.advanced_AdvancedSettingsView_null_AdvancedSettingsView-Night-1_3_null_4,NEXUS_5,1.0,en]",19860,],
+["ui_S_t[f.analytics.impl_AnalyticsOptInView_null_AnalyticsOptInView-Day-0_1_null_0,NEXUS_5,1.0,en]","ui_S_t[f.analytics.impl_AnalyticsOptInView_null_AnalyticsOptInView-Night-0_2_null_0,NEXUS_5,1.0,en]",19860,],
+["ui_S_t[f.analytics.api.preferences_AnalyticsPreferencesView_null_AnalyticsPreferencesView-Day-0_1_null_0,NEXUS_5,1.0,en]","ui_S_t[f.analytics.api.preferences_AnalyticsPreferencesView_null_AnalyticsPreferencesView-Night-0_2_null_0,NEXUS_5,1.0,en]",19860,],
+["ui_S_t[f.preferences.impl.analytics_AnalyticsSettingsView_null_AnalyticsSettingsView-Day-2_3_null_0,NEXUS_5,1.0,en]","ui_S_t[f.preferences.impl.analytics_AnalyticsSettingsView_null_AnalyticsSettingsView-Night-2_4_null_0,NEXUS_5,1.0,en]",19860,],
+["ui_S_t[services.apperror.impl_AppErrorView_null_AppErrorView-Day-0_1_null,NEXUS_5,1.0,en]","ui_S_t[services.apperror.impl_AppErrorView_null_AppErrorView-Night-0_2_null,NEXUS_5,1.0,en]",19860,],
["ui_S_t[l.designsystem.components.async_AsyncActionView_null_AsyncActionView-Day_0_null_0,NEXUS_5,1.0,en]","ui_S_t[l.designsystem.components.async_AsyncActionView_null_AsyncActionView-Night_1_null_0,NEXUS_5,1.0,en]",0,],
-["ui_S_t[l.designsystem.components.async_AsyncActionView_null_AsyncActionView-Day_0_null_1,NEXUS_5,1.0,en]","ui_S_t[l.designsystem.components.async_AsyncActionView_null_AsyncActionView-Night_1_null_1,NEXUS_5,1.0,en]",19846,],
+["ui_S_t[l.designsystem.components.async_AsyncActionView_null_AsyncActionView-Day_0_null_1,NEXUS_5,1.0,en]","ui_S_t[l.designsystem.components.async_AsyncActionView_null_AsyncActionView-Night_1_null_1,NEXUS_5,1.0,en]",19860,],
["ui_S_t[l.designsystem.components.async_AsyncActionView_null_AsyncActionView-Day_0_null_2,NEXUS_5,1.0,en]","ui_S_t[l.designsystem.components.async_AsyncActionView_null_AsyncActionView-Night_1_null_2,NEXUS_5,1.0,en]",0,],
-["ui_S_t[l.designsystem.components.async_AsyncActionView_null_AsyncActionView-Day_0_null_3,NEXUS_5,1.0,en]","ui_S_t[l.designsystem.components.async_AsyncActionView_null_AsyncActionView-Night_1_null_3,NEXUS_5,1.0,en]",19846,],
+["ui_S_t[l.designsystem.components.async_AsyncActionView_null_AsyncActionView-Day_0_null_3,NEXUS_5,1.0,en]","ui_S_t[l.designsystem.components.async_AsyncActionView_null_AsyncActionView-Night_1_null_3,NEXUS_5,1.0,en]",19860,],
["ui_S_t[l.designsystem.components.async_AsyncActionView_null_AsyncActionView-Day_0_null_4,NEXUS_5,1.0,en]","ui_S_t[l.designsystem.components.async_AsyncActionView_null_AsyncActionView-Night_1_null_4,NEXUS_5,1.0,en]",0,],
-["ui_S_t[l.designsystem.components.async_AsyncFailure_null_AsyncFailure-Day_0_null,NEXUS_5,1.0,en]","ui_S_t[l.designsystem.components.async_AsyncFailure_null_AsyncFailure-Night_1_null,NEXUS_5,1.0,en]",19846,],
+["ui_S_t[l.designsystem.components.async_AsyncFailure_null_AsyncFailure-Day_0_null,NEXUS_5,1.0,en]","ui_S_t[l.designsystem.components.async_AsyncFailure_null_AsyncFailure-Night_1_null,NEXUS_5,1.0,en]",19860,],
["ui_S_t[l.designsystem.components.async_AsyncIndicatorFailure_null_AsyncIndicatorFailure-Day_0_null,NEXUS_5,1.0,en]","ui_S_t[l.designsystem.components.async_AsyncIndicatorFailure_null_AsyncIndicatorFailure-Night_1_null,NEXUS_5,1.0,en]",0,],
["ui_S_t[l.designsystem.components.async_AsyncIndicatorLoading_null_AsyncIndicatorLoading-Day_0_null,NEXUS_5,1.0,en]","ui_S_t[l.designsystem.components.async_AsyncIndicatorLoading_null_AsyncIndicatorLoading-Night_1_null,NEXUS_5,1.0,en]",0,],
["ui_S_t[l.designsystem.components.async_AsyncLoading_null_AsyncLoading-Day_0_null,NEXUS_5,1.0,en]","ui_S_t[l.designsystem.components.async_AsyncLoading_null_AsyncLoading-Night_1_null,NEXUS_5,1.0,en]",0,],
-["ui_S_t[f.messages.impl.messagecomposer_AttachmentSourcePickerMenu_null_AttachmentSourcePickerMenu-Day-4_4_null,NEXUS_5,1.0,en]","ui_S_t[f.messages.impl.messagecomposer_AttachmentSourcePickerMenu_null_AttachmentSourcePickerMenu-Night-4_5_null,NEXUS_5,1.0,en]",19846,],
+["ui_S_t[f.messages.impl.messagecomposer_AttachmentSourcePickerMenu_null_AttachmentSourcePickerMenu-Day-4_4_null,NEXUS_5,1.0,en]","ui_S_t[f.messages.impl.messagecomposer_AttachmentSourcePickerMenu_null_AttachmentSourcePickerMenu-Night-4_5_null,NEXUS_5,1.0,en]",19860,],
["ui_S_t[l.matrix.ui.components_AttachmentThumbnail_null_AttachmentThumbnail-Day-0_1_null_0,NEXUS_5,1.0,en]","ui_S_t[l.matrix.ui.components_AttachmentThumbnail_null_AttachmentThumbnail-Night-0_2_null_0,NEXUS_5,1.0,en]",0,],
["ui_S_t[l.matrix.ui.components_AttachmentThumbnail_null_AttachmentThumbnail-Day-0_1_null_1,NEXUS_5,1.0,en]","ui_S_t[l.matrix.ui.components_AttachmentThumbnail_null_AttachmentThumbnail-Night-0_2_null_1,NEXUS_5,1.0,en]",0,],
["ui_S_t[l.matrix.ui.components_AttachmentThumbnail_null_AttachmentThumbnail-Day-0_1_null_2,NEXUS_5,1.0,en]","ui_S_t[l.matrix.ui.components_AttachmentThumbnail_null_AttachmentThumbnail-Night-0_2_null_2,NEXUS_5,1.0,en]",0,],
@@ -44,11 +44,11 @@ export const screenshots = [
["ui_S_t[l.matrix.ui.components_AttachmentThumbnail_null_AttachmentThumbnail-Day-0_1_null_6,NEXUS_5,1.0,en]","ui_S_t[l.matrix.ui.components_AttachmentThumbnail_null_AttachmentThumbnail-Night-0_2_null_6,NEXUS_5,1.0,en]",0,],
["ui_S_t[l.matrix.ui.components_AttachmentThumbnail_null_AttachmentThumbnail-Day-0_1_null_7,NEXUS_5,1.0,en]","ui_S_t[l.matrix.ui.components_AttachmentThumbnail_null_AttachmentThumbnail-Night-0_2_null_7,NEXUS_5,1.0,en]",0,],
["ui_S_t[l.matrix.ui.components_AttachmentThumbnail_null_AttachmentThumbnail-Day-0_1_null_8,NEXUS_5,1.0,en]","ui_S_t[l.matrix.ui.components_AttachmentThumbnail_null_AttachmentThumbnail-Night-0_2_null_8,NEXUS_5,1.0,en]",0,],
-["ui_S_t[f.messages.impl.attachments.preview_AttachmentsPreviewView_null_AttachmentsPreviewView_0_null_0,NEXUS_5,1.0,en]","",19846,],
-["ui_S_t[f.messages.impl.attachments.preview_AttachmentsPreviewView_null_AttachmentsPreviewView_0_null_1,NEXUS_5,1.0,en]","",19846,],
-["ui_S_t[f.messages.impl.attachments.preview_AttachmentsPreviewView_null_AttachmentsPreviewView_0_null_2,NEXUS_5,1.0,en]","",19846,],
-["ui_S_t[f.messages.impl.attachments.preview_AttachmentsPreviewView_null_AttachmentsPreviewView_0_null_3,NEXUS_5,1.0,en]","",19846,],
-["ui_S_t[l.matrix.ui.components_AvatarActionBottomSheet_null_AvatarActionBottomSheet-Day-1_2_null,NEXUS_5,1.0,en]","ui_S_t[l.matrix.ui.components_AvatarActionBottomSheet_null_AvatarActionBottomSheet-Night-1_3_null,NEXUS_5,1.0,en]",19846,],
+["ui_S_t[f.messages.impl.attachments.preview_AttachmentsPreviewView_null_AttachmentsPreviewView_0_null_0,NEXUS_5,1.0,en]","",19860,],
+["ui_S_t[f.messages.impl.attachments.preview_AttachmentsPreviewView_null_AttachmentsPreviewView_0_null_1,NEXUS_5,1.0,en]","",19860,],
+["ui_S_t[f.messages.impl.attachments.preview_AttachmentsPreviewView_null_AttachmentsPreviewView_0_null_2,NEXUS_5,1.0,en]","",19860,],
+["ui_S_t[f.messages.impl.attachments.preview_AttachmentsPreviewView_null_AttachmentsPreviewView_0_null_3,NEXUS_5,1.0,en]","",19860,],
+["ui_S_t[l.matrix.ui.components_AvatarActionBottomSheet_null_AvatarActionBottomSheet-Day-1_2_null,NEXUS_5,1.0,en]","ui_S_t[l.matrix.ui.components_AvatarActionBottomSheet_null_AvatarActionBottomSheet-Night-1_3_null,NEXUS_5,1.0,en]",19860,],
["ui_S_t[l.designsystem.components.avatar_Avatar_null_Avatars_Avatar_0_null_0,NEXUS_5,1.0,en]","",0,],
["ui_S_t[l.designsystem.components.avatar_Avatar_null_Avatars_Avatar_0_null_1,NEXUS_5,1.0,en]","",0,],
["ui_S_t[l.designsystem.components.avatar_Avatar_null_Avatars_Avatar_0_null_10,NEXUS_5,1.0,en]","",0,],
@@ -113,14 +113,15 @@ export const screenshots = [
["ui_S_t[l.designsystem.components.avatar_Avatar_null_Avatars_Avatar_0_null_8,NEXUS_5,1.0,en]","",0,],
["ui_S_t[l.designsystem.components.avatar_Avatar_null_Avatars_Avatar_0_null_9,NEXUS_5,1.0,en]","",0,],
["ui_S_t[l.designsystem.components.button_BackButton_null_Buttons_BackButton_0_null,NEXUS_5,1.0,en]","",0,],
+["ui_S_t[l.designsystem.components_Badge_null_Badge-Day_0_null,NEXUS_5,1.0,en]","ui_S_t[l.designsystem.components_Badge_null_Badge-Night_1_null,NEXUS_5,1.0,en]",0,],
["ui_S_t[l.designsystem.components_BigCheckmark_null_BigCheckmark-Day_0_null,NEXUS_5,1.0,en]","ui_S_t[l.designsystem.components_BigCheckmark_null_BigCheckmark-Night_1_null,NEXUS_5,1.0,en]",0,],
["ui_S_t[l.designsystem.components_BigIcon_null_BigIcon-Day_0_null,NEXUS_5,1.0,en]","ui_S_t[l.designsystem.components_BigIcon_null_BigIcon-Night_1_null,NEXUS_5,1.0,en]",0,],
-["ui_S_t[f.preferences.impl.blockedusers_BlockedUsersView_null_BlockedUsersView-Day-3_4_null_0,NEXUS_5,1.0,en]","ui_S_t[f.preferences.impl.blockedusers_BlockedUsersView_null_BlockedUsersView-Night-3_5_null_0,NEXUS_5,1.0,en]",19846,],
-["ui_S_t[f.preferences.impl.blockedusers_BlockedUsersView_null_BlockedUsersView-Day-3_4_null_1,NEXUS_5,1.0,en]","ui_S_t[f.preferences.impl.blockedusers_BlockedUsersView_null_BlockedUsersView-Night-3_5_null_1,NEXUS_5,1.0,en]",19846,],
-["ui_S_t[f.preferences.impl.blockedusers_BlockedUsersView_null_BlockedUsersView-Day-3_4_null_2,NEXUS_5,1.0,en]","ui_S_t[f.preferences.impl.blockedusers_BlockedUsersView_null_BlockedUsersView-Night-3_5_null_2,NEXUS_5,1.0,en]",19846,],
-["ui_S_t[f.preferences.impl.blockedusers_BlockedUsersView_null_BlockedUsersView-Day-3_4_null_3,NEXUS_5,1.0,en]","ui_S_t[f.preferences.impl.blockedusers_BlockedUsersView_null_BlockedUsersView-Night-3_5_null_3,NEXUS_5,1.0,en]",19846,],
-["ui_S_t[f.preferences.impl.blockedusers_BlockedUsersView_null_BlockedUsersView-Day-3_4_null_4,NEXUS_5,1.0,en]","ui_S_t[f.preferences.impl.blockedusers_BlockedUsersView_null_BlockedUsersView-Night-3_5_null_4,NEXUS_5,1.0,en]",19846,],
-["ui_S_t[f.preferences.impl.blockedusers_BlockedUsersView_null_BlockedUsersView-Day-3_4_null_5,NEXUS_5,1.0,en]","ui_S_t[f.preferences.impl.blockedusers_BlockedUsersView_null_BlockedUsersView-Night-3_5_null_5,NEXUS_5,1.0,en]",19846,],
+["ui_S_t[f.preferences.impl.blockedusers_BlockedUsersView_null_BlockedUsersView-Day-3_4_null_0,NEXUS_5,1.0,en]","ui_S_t[f.preferences.impl.blockedusers_BlockedUsersView_null_BlockedUsersView-Night-3_5_null_0,NEXUS_5,1.0,en]",19860,],
+["ui_S_t[f.preferences.impl.blockedusers_BlockedUsersView_null_BlockedUsersView-Day-3_4_null_1,NEXUS_5,1.0,en]","ui_S_t[f.preferences.impl.blockedusers_BlockedUsersView_null_BlockedUsersView-Night-3_5_null_1,NEXUS_5,1.0,en]",19860,],
+["ui_S_t[f.preferences.impl.blockedusers_BlockedUsersView_null_BlockedUsersView-Day-3_4_null_2,NEXUS_5,1.0,en]","ui_S_t[f.preferences.impl.blockedusers_BlockedUsersView_null_BlockedUsersView-Night-3_5_null_2,NEXUS_5,1.0,en]",19860,],
+["ui_S_t[f.preferences.impl.blockedusers_BlockedUsersView_null_BlockedUsersView-Day-3_4_null_3,NEXUS_5,1.0,en]","ui_S_t[f.preferences.impl.blockedusers_BlockedUsersView_null_BlockedUsersView-Night-3_5_null_3,NEXUS_5,1.0,en]",19860,],
+["ui_S_t[f.preferences.impl.blockedusers_BlockedUsersView_null_BlockedUsersView-Day-3_4_null_4,NEXUS_5,1.0,en]","ui_S_t[f.preferences.impl.blockedusers_BlockedUsersView_null_BlockedUsersView-Night-3_5_null_4,NEXUS_5,1.0,en]",19860,],
+["ui_S_t[f.preferences.impl.blockedusers_BlockedUsersView_null_BlockedUsersView-Day-3_4_null_5,NEXUS_5,1.0,en]","ui_S_t[f.preferences.impl.blockedusers_BlockedUsersView_null_BlockedUsersView-Night-3_5_null_5,NEXUS_5,1.0,en]",19860,],
["ui_S_t[l.designsystem.components_BloomInitials_null_Bloom_BloomInitials_0_null_0,NEXUS_5,1.0,en]","",0,],
["ui_S_t[l.designsystem.components_BloomInitials_null_Bloom_BloomInitials_0_null_1,NEXUS_5,1.0,en]","",0,],
["ui_S_t[l.designsystem.components_BloomInitials_null_Bloom_BloomInitials_0_null_2,NEXUS_5,1.0,en]","",0,],
@@ -131,36 +132,36 @@ export const screenshots = [
["ui_S_t[l.designsystem.components_BloomInitials_null_Bloom_BloomInitials_0_null_7,NEXUS_5,1.0,en]","",0,],
["ui_S_t[l.designsystem.components_Bloom_null_Bloom_Bloom_0_null,NEXUS_5,1.0,en]","",0,],
["ui_S_t[l.designsystem.theme.components_BottomSheetDragHandle_null_BottomSheetDragHandle-Day_0_null,NEXUS_5,1.0,en]","ui_S_t[l.designsystem.theme.components_BottomSheetDragHandle_null_BottomSheetDragHandle-Night_1_null,NEXUS_5,1.0,en]",0,],
-["ui_S_t[f.rageshake.impl.bugreport_BugReportView_null_BugReportView-Day-0_1_null_0,NEXUS_5,1.0,en]","ui_S_t[f.rageshake.impl.bugreport_BugReportView_null_BugReportView-Night-0_2_null_0,NEXUS_5,1.0,en]",19846,],
-["ui_S_t[f.rageshake.impl.bugreport_BugReportView_null_BugReportView-Day-0_1_null_1,NEXUS_5,1.0,en]","ui_S_t[f.rageshake.impl.bugreport_BugReportView_null_BugReportView-Night-0_2_null_1,NEXUS_5,1.0,en]",19846,],
-["ui_S_t[f.rageshake.impl.bugreport_BugReportView_null_BugReportView-Day-0_1_null_2,NEXUS_5,1.0,en]","ui_S_t[f.rageshake.impl.bugreport_BugReportView_null_BugReportView-Night-0_2_null_2,NEXUS_5,1.0,en]",19846,],
-["ui_S_t[f.rageshake.impl.bugreport_BugReportView_null_BugReportView-Day-0_1_null_3,NEXUS_5,1.0,en]","ui_S_t[f.rageshake.impl.bugreport_BugReportView_null_BugReportView-Night-0_2_null_3,NEXUS_5,1.0,en]",19846,],
-["ui_S_t[f.rageshake.impl.bugreport_BugReportView_null_BugReportView-Day-0_1_null_4,NEXUS_5,1.0,en]","ui_S_t[f.rageshake.impl.bugreport_BugReportView_null_BugReportView-Night-0_2_null_4,NEXUS_5,1.0,en]",19846,],
+["ui_S_t[f.rageshake.impl.bugreport_BugReportView_null_BugReportView-Day-0_1_null_0,NEXUS_5,1.0,en]","ui_S_t[f.rageshake.impl.bugreport_BugReportView_null_BugReportView-Night-0_2_null_0,NEXUS_5,1.0,en]",19860,],
+["ui_S_t[f.rageshake.impl.bugreport_BugReportView_null_BugReportView-Day-0_1_null_1,NEXUS_5,1.0,en]","ui_S_t[f.rageshake.impl.bugreport_BugReportView_null_BugReportView-Night-0_2_null_1,NEXUS_5,1.0,en]",19860,],
+["ui_S_t[f.rageshake.impl.bugreport_BugReportView_null_BugReportView-Day-0_1_null_2,NEXUS_5,1.0,en]","ui_S_t[f.rageshake.impl.bugreport_BugReportView_null_BugReportView-Night-0_2_null_2,NEXUS_5,1.0,en]",19860,],
+["ui_S_t[f.rageshake.impl.bugreport_BugReportView_null_BugReportView-Day-0_1_null_3,NEXUS_5,1.0,en]","ui_S_t[f.rageshake.impl.bugreport_BugReportView_null_BugReportView-Night-0_2_null_3,NEXUS_5,1.0,en]",19860,],
+["ui_S_t[f.rageshake.impl.bugreport_BugReportView_null_BugReportView-Day-0_1_null_4,NEXUS_5,1.0,en]","ui_S_t[f.rageshake.impl.bugreport_BugReportView_null_BugReportView-Night-0_2_null_4,NEXUS_5,1.0,en]",19860,],
["ui_S_t[l.designsystem.atomic.molecules_ButtonColumnMolecule_null_ButtonColumnMolecule-Day_0_null,NEXUS_5,1.0,en]","ui_S_t[l.designsystem.atomic.molecules_ButtonColumnMolecule_null_ButtonColumnMolecule-Night_1_null,NEXUS_5,1.0,en]",0,],
["ui_S_t[l.designsystem.atomic.molecules_ButtonRowMolecule_null_ButtonRowMolecule-Day_0_null,NEXUS_5,1.0,en]","ui_S_t[l.designsystem.atomic.molecules_ButtonRowMolecule_null_ButtonRowMolecule-Night_1_null,NEXUS_5,1.0,en]",0,],
["ui_S_t[f.call.ui_CallScreenView_null_CallScreenView-Day-0_1_null,NEXUS_5,1.0,en]","ui_S_t[f.call.ui_CallScreenView_null_CallScreenView-Night-0_2_null,NEXUS_5,1.0,en]",0,],
-["ui_S_t[f.login.impl.screens.changeaccountprovider_ChangeAccountProviderView_null_ChangeAccountProviderView-Day-4_5_null_0,NEXUS_5,1.0,en]","ui_S_t[f.login.impl.screens.changeaccountprovider_ChangeAccountProviderView_null_ChangeAccountProviderView-Night-4_6_null_0,NEXUS_5,1.0,en]",19846,],
-["ui_S_t[f.roomdetails.impl.rolesandpermissions.changeroles_ChangeRolesView_null_ChangeRolesView-Day-9_9_null_0,NEXUS_5,1.0,en]","ui_S_t[f.roomdetails.impl.rolesandpermissions.changeroles_ChangeRolesView_null_ChangeRolesView-Night-9_10_null_0,NEXUS_5,1.0,en]",19849,],
-["ui_S_t[f.roomdetails.impl.rolesandpermissions.changeroles_ChangeRolesView_null_ChangeRolesView-Day-9_9_null_1,NEXUS_5,1.0,en]","ui_S_t[f.roomdetails.impl.rolesandpermissions.changeroles_ChangeRolesView_null_ChangeRolesView-Night-9_10_null_1,NEXUS_5,1.0,en]",19849,],
-["ui_S_t[f.roomdetails.impl.rolesandpermissions.changeroles_ChangeRolesView_null_ChangeRolesView-Day-9_9_null_10,NEXUS_5,1.0,en]","ui_S_t[f.roomdetails.impl.rolesandpermissions.changeroles_ChangeRolesView_null_ChangeRolesView-Night-9_10_null_10,NEXUS_5,1.0,en]",19849,],
-["ui_S_t[f.roomdetails.impl.rolesandpermissions.changeroles_ChangeRolesView_null_ChangeRolesView-Day-9_9_null_2,NEXUS_5,1.0,en]","ui_S_t[f.roomdetails.impl.rolesandpermissions.changeroles_ChangeRolesView_null_ChangeRolesView-Night-9_10_null_2,NEXUS_5,1.0,en]",19849,],
-["ui_S_t[f.roomdetails.impl.rolesandpermissions.changeroles_ChangeRolesView_null_ChangeRolesView-Day-9_9_null_3,NEXUS_5,1.0,en]","ui_S_t[f.roomdetails.impl.rolesandpermissions.changeroles_ChangeRolesView_null_ChangeRolesView-Night-9_10_null_3,NEXUS_5,1.0,en]",19849,],
-["ui_S_t[f.roomdetails.impl.rolesandpermissions.changeroles_ChangeRolesView_null_ChangeRolesView-Day-9_9_null_4,NEXUS_5,1.0,en]","ui_S_t[f.roomdetails.impl.rolesandpermissions.changeroles_ChangeRolesView_null_ChangeRolesView-Night-9_10_null_4,NEXUS_5,1.0,en]",19849,],
-["ui_S_t[f.roomdetails.impl.rolesandpermissions.changeroles_ChangeRolesView_null_ChangeRolesView-Day-9_9_null_5,NEXUS_5,1.0,en]","ui_S_t[f.roomdetails.impl.rolesandpermissions.changeroles_ChangeRolesView_null_ChangeRolesView-Night-9_10_null_5,NEXUS_5,1.0,en]",19849,],
-["ui_S_t[f.roomdetails.impl.rolesandpermissions.changeroles_ChangeRolesView_null_ChangeRolesView-Day-9_9_null_6,NEXUS_5,1.0,en]","ui_S_t[f.roomdetails.impl.rolesandpermissions.changeroles_ChangeRolesView_null_ChangeRolesView-Night-9_10_null_6,NEXUS_5,1.0,en]",19849,],
-["ui_S_t[f.roomdetails.impl.rolesandpermissions.changeroles_ChangeRolesView_null_ChangeRolesView-Day-9_9_null_7,NEXUS_5,1.0,en]","ui_S_t[f.roomdetails.impl.rolesandpermissions.changeroles_ChangeRolesView_null_ChangeRolesView-Night-9_10_null_7,NEXUS_5,1.0,en]",19849,],
-["ui_S_t[f.roomdetails.impl.rolesandpermissions.changeroles_ChangeRolesView_null_ChangeRolesView-Day-9_9_null_8,NEXUS_5,1.0,en]","ui_S_t[f.roomdetails.impl.rolesandpermissions.changeroles_ChangeRolesView_null_ChangeRolesView-Night-9_10_null_8,NEXUS_5,1.0,en]",19849,],
-["ui_S_t[f.roomdetails.impl.rolesandpermissions.changeroles_ChangeRolesView_null_ChangeRolesView-Day-9_9_null_9,NEXUS_5,1.0,en]","ui_S_t[f.roomdetails.impl.rolesandpermissions.changeroles_ChangeRolesView_null_ChangeRolesView-Night-9_10_null_9,NEXUS_5,1.0,en]",19849,],
-["ui_S_t[f.roomdetails.impl.rolesandpermissions.permissions_ChangeRoomPermissionsView_null_ChangeRoomPermissionsView-Day-11_11_null_0,NEXUS_5,1.0,en]","ui_S_t[f.roomdetails.impl.rolesandpermissions.permissions_ChangeRoomPermissionsView_null_ChangeRoomPermissionsView-Night-11_12_null_0,NEXUS_5,1.0,en]",19849,],
-["ui_S_t[f.roomdetails.impl.rolesandpermissions.permissions_ChangeRoomPermissionsView_null_ChangeRoomPermissionsView-Day-11_11_null_1,NEXUS_5,1.0,en]","ui_S_t[f.roomdetails.impl.rolesandpermissions.permissions_ChangeRoomPermissionsView_null_ChangeRoomPermissionsView-Night-11_12_null_1,NEXUS_5,1.0,en]",19849,],
-["ui_S_t[f.roomdetails.impl.rolesandpermissions.permissions_ChangeRoomPermissionsView_null_ChangeRoomPermissionsView-Day-11_11_null_2,NEXUS_5,1.0,en]","ui_S_t[f.roomdetails.impl.rolesandpermissions.permissions_ChangeRoomPermissionsView_null_ChangeRoomPermissionsView-Night-11_12_null_2,NEXUS_5,1.0,en]",19849,],
-["ui_S_t[f.roomdetails.impl.rolesandpermissions.permissions_ChangeRoomPermissionsView_null_ChangeRoomPermissionsView-Day-11_11_null_3,NEXUS_5,1.0,en]","ui_S_t[f.roomdetails.impl.rolesandpermissions.permissions_ChangeRoomPermissionsView_null_ChangeRoomPermissionsView-Night-11_12_null_3,NEXUS_5,1.0,en]",19849,],
-["ui_S_t[f.roomdetails.impl.rolesandpermissions.permissions_ChangeRoomPermissionsView_null_ChangeRoomPermissionsView-Day-11_11_null_4,NEXUS_5,1.0,en]","ui_S_t[f.roomdetails.impl.rolesandpermissions.permissions_ChangeRoomPermissionsView_null_ChangeRoomPermissionsView-Night-11_12_null_4,NEXUS_5,1.0,en]",19849,],
-["ui_S_t[f.roomdetails.impl.rolesandpermissions.permissions_ChangeRoomPermissionsView_null_ChangeRoomPermissionsView-Day-11_11_null_5,NEXUS_5,1.0,en]","ui_S_t[f.roomdetails.impl.rolesandpermissions.permissions_ChangeRoomPermissionsView_null_ChangeRoomPermissionsView-Night-11_12_null_5,NEXUS_5,1.0,en]",19849,],
-["ui_S_t[f.roomdetails.impl.rolesandpermissions.permissions_ChangeRoomPermissionsView_null_ChangeRoomPermissionsView-Day-11_11_null_6,NEXUS_5,1.0,en]","ui_S_t[f.roomdetails.impl.rolesandpermissions.permissions_ChangeRoomPermissionsView_null_ChangeRoomPermissionsView-Night-11_12_null_6,NEXUS_5,1.0,en]",19849,],
+["ui_S_t[f.login.impl.screens.changeaccountprovider_ChangeAccountProviderView_null_ChangeAccountProviderView-Day-4_5_null_0,NEXUS_5,1.0,en]","ui_S_t[f.login.impl.screens.changeaccountprovider_ChangeAccountProviderView_null_ChangeAccountProviderView-Night-4_6_null_0,NEXUS_5,1.0,en]",19860,],
+["ui_S_t[f.roomdetails.impl.rolesandpermissions.changeroles_ChangeRolesView_null_ChangeRolesView-Day-12_12_null_0,NEXUS_5,1.0,en]","ui_S_t[f.roomdetails.impl.rolesandpermissions.changeroles_ChangeRolesView_null_ChangeRolesView-Night-12_13_null_0,NEXUS_5,1.0,en]",19860,],
+["ui_S_t[f.roomdetails.impl.rolesandpermissions.changeroles_ChangeRolesView_null_ChangeRolesView-Day-12_12_null_1,NEXUS_5,1.0,en]","ui_S_t[f.roomdetails.impl.rolesandpermissions.changeroles_ChangeRolesView_null_ChangeRolesView-Night-12_13_null_1,NEXUS_5,1.0,en]",19860,],
+["ui_S_t[f.roomdetails.impl.rolesandpermissions.changeroles_ChangeRolesView_null_ChangeRolesView-Day-12_12_null_10,NEXUS_5,1.0,en]","ui_S_t[f.roomdetails.impl.rolesandpermissions.changeroles_ChangeRolesView_null_ChangeRolesView-Night-12_13_null_10,NEXUS_5,1.0,en]",19860,],
+["ui_S_t[f.roomdetails.impl.rolesandpermissions.changeroles_ChangeRolesView_null_ChangeRolesView-Day-12_12_null_2,NEXUS_5,1.0,en]","ui_S_t[f.roomdetails.impl.rolesandpermissions.changeroles_ChangeRolesView_null_ChangeRolesView-Night-12_13_null_2,NEXUS_5,1.0,en]",19860,],
+["ui_S_t[f.roomdetails.impl.rolesandpermissions.changeroles_ChangeRolesView_null_ChangeRolesView-Day-12_12_null_3,NEXUS_5,1.0,en]","ui_S_t[f.roomdetails.impl.rolesandpermissions.changeroles_ChangeRolesView_null_ChangeRolesView-Night-12_13_null_3,NEXUS_5,1.0,en]",19860,],
+["ui_S_t[f.roomdetails.impl.rolesandpermissions.changeroles_ChangeRolesView_null_ChangeRolesView-Day-12_12_null_4,NEXUS_5,1.0,en]","ui_S_t[f.roomdetails.impl.rolesandpermissions.changeroles_ChangeRolesView_null_ChangeRolesView-Night-12_13_null_4,NEXUS_5,1.0,en]",19860,],
+["ui_S_t[f.roomdetails.impl.rolesandpermissions.changeroles_ChangeRolesView_null_ChangeRolesView-Day-12_12_null_5,NEXUS_5,1.0,en]","ui_S_t[f.roomdetails.impl.rolesandpermissions.changeroles_ChangeRolesView_null_ChangeRolesView-Night-12_13_null_5,NEXUS_5,1.0,en]",19860,],
+["ui_S_t[f.roomdetails.impl.rolesandpermissions.changeroles_ChangeRolesView_null_ChangeRolesView-Day-12_12_null_6,NEXUS_5,1.0,en]","ui_S_t[f.roomdetails.impl.rolesandpermissions.changeroles_ChangeRolesView_null_ChangeRolesView-Night-12_13_null_6,NEXUS_5,1.0,en]",19860,],
+["ui_S_t[f.roomdetails.impl.rolesandpermissions.changeroles_ChangeRolesView_null_ChangeRolesView-Day-12_12_null_7,NEXUS_5,1.0,en]","ui_S_t[f.roomdetails.impl.rolesandpermissions.changeroles_ChangeRolesView_null_ChangeRolesView-Night-12_13_null_7,NEXUS_5,1.0,en]",19860,],
+["ui_S_t[f.roomdetails.impl.rolesandpermissions.changeroles_ChangeRolesView_null_ChangeRolesView-Day-12_12_null_8,NEXUS_5,1.0,en]","ui_S_t[f.roomdetails.impl.rolesandpermissions.changeroles_ChangeRolesView_null_ChangeRolesView-Night-12_13_null_8,NEXUS_5,1.0,en]",19860,],
+["ui_S_t[f.roomdetails.impl.rolesandpermissions.changeroles_ChangeRolesView_null_ChangeRolesView-Day-12_12_null_9,NEXUS_5,1.0,en]","ui_S_t[f.roomdetails.impl.rolesandpermissions.changeroles_ChangeRolesView_null_ChangeRolesView-Night-12_13_null_9,NEXUS_5,1.0,en]",19860,],
+["ui_S_t[f.roomdetails.impl.rolesandpermissions.permissions_ChangeRoomPermissionsView_null_ChangeRoomPermissionsView-Day-14_14_null_0,NEXUS_5,1.0,en]","ui_S_t[f.roomdetails.impl.rolesandpermissions.permissions_ChangeRoomPermissionsView_null_ChangeRoomPermissionsView-Night-14_15_null_0,NEXUS_5,1.0,en]",19860,],
+["ui_S_t[f.roomdetails.impl.rolesandpermissions.permissions_ChangeRoomPermissionsView_null_ChangeRoomPermissionsView-Day-14_14_null_1,NEXUS_5,1.0,en]","ui_S_t[f.roomdetails.impl.rolesandpermissions.permissions_ChangeRoomPermissionsView_null_ChangeRoomPermissionsView-Night-14_15_null_1,NEXUS_5,1.0,en]",19860,],
+["ui_S_t[f.roomdetails.impl.rolesandpermissions.permissions_ChangeRoomPermissionsView_null_ChangeRoomPermissionsView-Day-14_14_null_2,NEXUS_5,1.0,en]","ui_S_t[f.roomdetails.impl.rolesandpermissions.permissions_ChangeRoomPermissionsView_null_ChangeRoomPermissionsView-Night-14_15_null_2,NEXUS_5,1.0,en]",19860,],
+["ui_S_t[f.roomdetails.impl.rolesandpermissions.permissions_ChangeRoomPermissionsView_null_ChangeRoomPermissionsView-Day-14_14_null_3,NEXUS_5,1.0,en]","ui_S_t[f.roomdetails.impl.rolesandpermissions.permissions_ChangeRoomPermissionsView_null_ChangeRoomPermissionsView-Night-14_15_null_3,NEXUS_5,1.0,en]",19860,],
+["ui_S_t[f.roomdetails.impl.rolesandpermissions.permissions_ChangeRoomPermissionsView_null_ChangeRoomPermissionsView-Day-14_14_null_4,NEXUS_5,1.0,en]","ui_S_t[f.roomdetails.impl.rolesandpermissions.permissions_ChangeRoomPermissionsView_null_ChangeRoomPermissionsView-Night-14_15_null_4,NEXUS_5,1.0,en]",19860,],
+["ui_S_t[f.roomdetails.impl.rolesandpermissions.permissions_ChangeRoomPermissionsView_null_ChangeRoomPermissionsView-Day-14_14_null_5,NEXUS_5,1.0,en]","ui_S_t[f.roomdetails.impl.rolesandpermissions.permissions_ChangeRoomPermissionsView_null_ChangeRoomPermissionsView-Night-14_15_null_5,NEXUS_5,1.0,en]",19860,],
+["ui_S_t[f.roomdetails.impl.rolesandpermissions.permissions_ChangeRoomPermissionsView_null_ChangeRoomPermissionsView-Day-14_14_null_6,NEXUS_5,1.0,en]","ui_S_t[f.roomdetails.impl.rolesandpermissions.permissions_ChangeRoomPermissionsView_null_ChangeRoomPermissionsView-Night-14_15_null_6,NEXUS_5,1.0,en]",19860,],
["ui_S_t[f.login.impl.changeserver_ChangeServerView_null_ChangeServerView-Day-1_2_null_0,NEXUS_5,1.0,en]","ui_S_t[f.login.impl.changeserver_ChangeServerView_null_ChangeServerView-Night-1_3_null_0,NEXUS_5,1.0,en]",0,],
["ui_S_t[l.matrix.ui.components_CheckableResolvedUserRow_null_CheckableResolvedUserRow_0_null,NEXUS_5,1.0,en]","",0,],
-["ui_S_t[l.matrix.ui.components_CheckableUnresolvedUserRow_null_CheckableUnresolvedUserRow_0_null,NEXUS_5,1.0,en]","",19846,],
+["ui_S_t[l.matrix.ui.components_CheckableUnresolvedUserRow_null_CheckableUnresolvedUserRow_0_null,NEXUS_5,1.0,en]","",19860,],
["ui_S_t[l.designsystem.theme.components_Checkboxes_null_Toggles_Checkboxes_0_null,NEXUS_5,1.0,en]","",0,],
["ui_S_t[l.designsystem.theme.components_CircularProgressIndicator_null_ProgressIndicators_CircularProgressIndicator_0_null,NEXUS_5,1.0,en]","",0,],
["ui_S_t[l.designsystem.components_ClickableLinkText_null_Text_ClickableLinkText_0_null,NEXUS_5,1.0,en]","",0,],
@@ -178,42 +179,42 @@ export const screenshots = [
["ui_S_t[Typo_Compound_M3 Title Large,NEXUS_5,1.0,en]","",0,],
["ui_S_t[Typo_Compound_M3 Title Medium,NEXUS_5,1.0,en]","",0,],
["ui_S_t[Typo_Compound_M3 Title Small,NEXUS_5,1.0,en]","",0,],
-["ui_S_t[f.createroom.impl.configureroom_ConfigureRoomView_null_ConfigureRoomView-Day-3_4_null_0,NEXUS_5,1.0,en]","ui_S_t[f.createroom.impl.configureroom_ConfigureRoomView_null_ConfigureRoomView-Night-3_5_null_0,NEXUS_5,1.0,en]",19846,],
-["ui_S_t[f.createroom.impl.configureroom_ConfigureRoomView_null_ConfigureRoomView-Day-3_4_null_1,NEXUS_5,1.0,en]","ui_S_t[f.createroom.impl.configureroom_ConfigureRoomView_null_ConfigureRoomView-Night-3_5_null_1,NEXUS_5,1.0,en]",19846,],
+["ui_S_t[f.createroom.impl.configureroom_ConfigureRoomView_null_ConfigureRoomView-Day-3_4_null_0,NEXUS_5,1.0,en]","ui_S_t[f.createroom.impl.configureroom_ConfigureRoomView_null_ConfigureRoomView-Night-3_5_null_0,NEXUS_5,1.0,en]",19860,],
+["ui_S_t[f.createroom.impl.configureroom_ConfigureRoomView_null_ConfigureRoomView-Day-3_4_null_1,NEXUS_5,1.0,en]","ui_S_t[f.createroom.impl.configureroom_ConfigureRoomView_null_ConfigureRoomView-Night-3_5_null_1,NEXUS_5,1.0,en]",19860,],
["ui_S_t[f.preferences.impl.developer.tracing_ConfigureTracingView_null_ConfigureTracingView-Day-5_6_null_0,NEXUS_5,1.0,en]","ui_S_t[f.preferences.impl.developer.tracing_ConfigureTracingView_null_ConfigureTracingView-Night-5_7_null_0,NEXUS_5,1.0,en]",0,],
-["ui_S_t[f.login.impl.screens.confirmaccountprovider_ConfirmAccountProviderView_null_ConfirmAccountProviderView-Day-5_6_null_0,NEXUS_5,1.0,en]","ui_S_t[f.login.impl.screens.confirmaccountprovider_ConfirmAccountProviderView_null_ConfirmAccountProviderView-Night-5_7_null_0,NEXUS_5,1.0,en]",19846,],
-["ui_S_t[f.roomlist.impl.components_ConfirmRecoveryKeyBanner_null_ConfirmRecoveryKeyBanner-Day-2_3_null,NEXUS_5,1.0,en]","ui_S_t[f.roomlist.impl.components_ConfirmRecoveryKeyBanner_null_ConfirmRecoveryKeyBanner-Night-2_4_null,NEXUS_5,1.0,en]",19846,],
+["ui_S_t[f.login.impl.screens.confirmaccountprovider_ConfirmAccountProviderView_null_ConfirmAccountProviderView-Day-5_6_null_0,NEXUS_5,1.0,en]","ui_S_t[f.login.impl.screens.confirmaccountprovider_ConfirmAccountProviderView_null_ConfirmAccountProviderView-Night-5_7_null_0,NEXUS_5,1.0,en]",19860,],
+["ui_S_t[f.roomlist.impl.components_ConfirmRecoveryKeyBanner_null_ConfirmRecoveryKeyBanner-Day-2_3_null,NEXUS_5,1.0,en]","ui_S_t[f.roomlist.impl.components_ConfirmRecoveryKeyBanner_null_ConfirmRecoveryKeyBanner-Night-2_4_null,NEXUS_5,1.0,en]",19860,],
["ui_S_t[l.designsystem.components.dialogs_ConfirmationDialogContent_null_Dialogs_ConfirmationDialogContent_0_null,NEXUS_5,1.0,en]","",0,],
["ui_S_t[l.designsystem.components.dialogs_ConfirmationDialog_null_ConfirmationDialog-Day_0_null,NEXUS_5,1.0,en]","ui_S_t[l.designsystem.components.dialogs_ConfirmationDialog_null_ConfirmationDialog-Night_1_null,NEXUS_5,1.0,en]",0,],
["ui_S_t[f.networkmonitor.api.ui_ConnectivityIndicatorView_null_ConnectivityIndicatorView-Day-0_1_null,NEXUS_5,1.0,en]","ui_S_t[f.networkmonitor.api.ui_ConnectivityIndicatorView_null_ConnectivityIndicatorView-Night-0_2_null,NEXUS_5,1.0,en]",0,],
-["ui_S_t[f.rageshake.api.crash_CrashDetectionView_null_CrashDetectionView-Day-0_1_null,NEXUS_5,1.0,en]","ui_S_t[f.rageshake.api.crash_CrashDetectionView_null_CrashDetectionView-Night-0_2_null,NEXUS_5,1.0,en]",19846,],
-["ui_S_t[f.securebackup.impl.createkey_CreateNewRecoveryKeyView_null_CreateNewRecoveryKeyView-Day-0_1_null,NEXUS_5,1.0,en]","ui_S_t[f.securebackup.impl.createkey_CreateNewRecoveryKeyView_null_CreateNewRecoveryKeyView-Night-0_2_null,NEXUS_5,1.0,en]",19846,],
-["ui_S_t[f.poll.impl.create_CreatePollView_null_CreatePollView-Day-0_1_null_0,NEXUS_5,1.0,en]","ui_S_t[f.poll.impl.create_CreatePollView_null_CreatePollView-Night-0_2_null_0,NEXUS_5,1.0,en]",19846,],
-["ui_S_t[f.poll.impl.create_CreatePollView_null_CreatePollView-Day-0_1_null_1,NEXUS_5,1.0,en]","ui_S_t[f.poll.impl.create_CreatePollView_null_CreatePollView-Night-0_2_null_1,NEXUS_5,1.0,en]",19846,],
-["ui_S_t[f.poll.impl.create_CreatePollView_null_CreatePollView-Day-0_1_null_2,NEXUS_5,1.0,en]","ui_S_t[f.poll.impl.create_CreatePollView_null_CreatePollView-Night-0_2_null_2,NEXUS_5,1.0,en]",19846,],
-["ui_S_t[f.poll.impl.create_CreatePollView_null_CreatePollView-Day-0_1_null_3,NEXUS_5,1.0,en]","ui_S_t[f.poll.impl.create_CreatePollView_null_CreatePollView-Night-0_2_null_3,NEXUS_5,1.0,en]",19846,],
-["ui_S_t[f.poll.impl.create_CreatePollView_null_CreatePollView-Day-0_1_null_4,NEXUS_5,1.0,en]","ui_S_t[f.poll.impl.create_CreatePollView_null_CreatePollView-Night-0_2_null_4,NEXUS_5,1.0,en]",19846,],
-["ui_S_t[f.poll.impl.create_CreatePollView_null_CreatePollView-Day-0_1_null_5,NEXUS_5,1.0,en]","ui_S_t[f.poll.impl.create_CreatePollView_null_CreatePollView-Night-0_2_null_5,NEXUS_5,1.0,en]",19846,],
-["ui_S_t[f.poll.impl.create_CreatePollView_null_CreatePollView-Day-0_1_null_6,NEXUS_5,1.0,en]","ui_S_t[f.poll.impl.create_CreatePollView_null_CreatePollView-Night-0_2_null_6,NEXUS_5,1.0,en]",19846,],
-["ui_S_t[f.poll.impl.create_CreatePollView_null_CreatePollView-Day-0_1_null_7,NEXUS_5,1.0,en]","ui_S_t[f.poll.impl.create_CreatePollView_null_CreatePollView-Night-0_2_null_7,NEXUS_5,1.0,en]",19846,],
-["ui_S_t[f.createroom.impl.root_CreateRoomRootView_null_CreateRoomRootView-Day-4_5_null_0,NEXUS_5,1.0,en]","ui_S_t[f.createroom.impl.root_CreateRoomRootView_null_CreateRoomRootView-Night-4_6_null_0,NEXUS_5,1.0,en]",19846,],
-["ui_S_t[f.createroom.impl.root_CreateRoomRootView_null_CreateRoomRootView-Day-4_5_null_1,NEXUS_5,1.0,en]","ui_S_t[f.createroom.impl.root_CreateRoomRootView_null_CreateRoomRootView-Night-4_6_null_1,NEXUS_5,1.0,en]",19846,],
-["ui_S_t[f.createroom.impl.root_CreateRoomRootView_null_CreateRoomRootView-Day-4_5_null_2,NEXUS_5,1.0,en]","ui_S_t[f.createroom.impl.root_CreateRoomRootView_null_CreateRoomRootView-Night-4_6_null_2,NEXUS_5,1.0,en]",19846,],
-["ui_S_t[f.createroom.impl.root_CreateRoomRootView_null_CreateRoomRootView-Day-4_5_null_3,NEXUS_5,1.0,en]","ui_S_t[f.createroom.impl.root_CreateRoomRootView_null_CreateRoomRootView-Night-4_6_null_3,NEXUS_5,1.0,en]",19846,],
-["ui_S_t[l.designsystem.theme.components.previews_DatePickerDark_null_DateTimepickers_DatePickerDark_0_null,NEXUS_5,1.0,en]","",19846,],
-["ui_S_t[l.designsystem.theme.components.previews_DatePickerLight_null_DateTimepickers_DatePickerLight_0_null,NEXUS_5,1.0,en]","",19846,],
+["ui_S_t[f.rageshake.api.crash_CrashDetectionView_null_CrashDetectionView-Day-0_1_null,NEXUS_5,1.0,en]","ui_S_t[f.rageshake.api.crash_CrashDetectionView_null_CrashDetectionView-Night-0_2_null,NEXUS_5,1.0,en]",19860,],
+["ui_S_t[f.securebackup.impl.createkey_CreateNewRecoveryKeyView_null_CreateNewRecoveryKeyView-Day-0_1_null,NEXUS_5,1.0,en]","ui_S_t[f.securebackup.impl.createkey_CreateNewRecoveryKeyView_null_CreateNewRecoveryKeyView-Night-0_2_null,NEXUS_5,1.0,en]",19860,],
+["ui_S_t[f.poll.impl.create_CreatePollView_null_CreatePollView-Day-0_1_null_0,NEXUS_5,1.0,en]","ui_S_t[f.poll.impl.create_CreatePollView_null_CreatePollView-Night-0_2_null_0,NEXUS_5,1.0,en]",19860,],
+["ui_S_t[f.poll.impl.create_CreatePollView_null_CreatePollView-Day-0_1_null_1,NEXUS_5,1.0,en]","ui_S_t[f.poll.impl.create_CreatePollView_null_CreatePollView-Night-0_2_null_1,NEXUS_5,1.0,en]",19860,],
+["ui_S_t[f.poll.impl.create_CreatePollView_null_CreatePollView-Day-0_1_null_2,NEXUS_5,1.0,en]","ui_S_t[f.poll.impl.create_CreatePollView_null_CreatePollView-Night-0_2_null_2,NEXUS_5,1.0,en]",19860,],
+["ui_S_t[f.poll.impl.create_CreatePollView_null_CreatePollView-Day-0_1_null_3,NEXUS_5,1.0,en]","ui_S_t[f.poll.impl.create_CreatePollView_null_CreatePollView-Night-0_2_null_3,NEXUS_5,1.0,en]",19860,],
+["ui_S_t[f.poll.impl.create_CreatePollView_null_CreatePollView-Day-0_1_null_4,NEXUS_5,1.0,en]","ui_S_t[f.poll.impl.create_CreatePollView_null_CreatePollView-Night-0_2_null_4,NEXUS_5,1.0,en]",19860,],
+["ui_S_t[f.poll.impl.create_CreatePollView_null_CreatePollView-Day-0_1_null_5,NEXUS_5,1.0,en]","ui_S_t[f.poll.impl.create_CreatePollView_null_CreatePollView-Night-0_2_null_5,NEXUS_5,1.0,en]",19860,],
+["ui_S_t[f.poll.impl.create_CreatePollView_null_CreatePollView-Day-0_1_null_6,NEXUS_5,1.0,en]","ui_S_t[f.poll.impl.create_CreatePollView_null_CreatePollView-Night-0_2_null_6,NEXUS_5,1.0,en]",19860,],
+["ui_S_t[f.poll.impl.create_CreatePollView_null_CreatePollView-Day-0_1_null_7,NEXUS_5,1.0,en]","ui_S_t[f.poll.impl.create_CreatePollView_null_CreatePollView-Night-0_2_null_7,NEXUS_5,1.0,en]",19860,],
+["ui_S_t[f.createroom.impl.root_CreateRoomRootView_null_CreateRoomRootView-Day-4_5_null_0,NEXUS_5,1.0,en]","ui_S_t[f.createroom.impl.root_CreateRoomRootView_null_CreateRoomRootView-Night-4_6_null_0,NEXUS_5,1.0,en]",19860,],
+["ui_S_t[f.createroom.impl.root_CreateRoomRootView_null_CreateRoomRootView-Day-4_5_null_1,NEXUS_5,1.0,en]","ui_S_t[f.createroom.impl.root_CreateRoomRootView_null_CreateRoomRootView-Night-4_6_null_1,NEXUS_5,1.0,en]",19860,],
+["ui_S_t[f.createroom.impl.root_CreateRoomRootView_null_CreateRoomRootView-Day-4_5_null_2,NEXUS_5,1.0,en]","ui_S_t[f.createroom.impl.root_CreateRoomRootView_null_CreateRoomRootView-Night-4_6_null_2,NEXUS_5,1.0,en]",19860,],
+["ui_S_t[f.createroom.impl.root_CreateRoomRootView_null_CreateRoomRootView-Day-4_5_null_3,NEXUS_5,1.0,en]","ui_S_t[f.createroom.impl.root_CreateRoomRootView_null_CreateRoomRootView-Night-4_6_null_3,NEXUS_5,1.0,en]",19860,],
+["ui_S_t[l.designsystem.theme.components.previews_DatePickerDark_null_DateTimepickers_DatePickerDark_0_null,NEXUS_5,1.0,en]","",19860,],
+["ui_S_t[l.designsystem.theme.components.previews_DatePickerLight_null_DateTimepickers_DatePickerLight_0_null,NEXUS_5,1.0,en]","",19860,],
["ui_S_t[f.logout.impl.direct_DefaultDirectLogoutView_null_DefaultDirectLogoutView-Day-1_2_null_0,NEXUS_5,1.0,en]","ui_S_t[f.logout.impl.direct_DefaultDirectLogoutView_null_DefaultDirectLogoutView-Night-1_3_null_0,NEXUS_5,1.0,en]",0,],
-["ui_S_t[f.logout.impl.direct_DefaultDirectLogoutView_null_DefaultDirectLogoutView-Day-1_2_null_1,NEXUS_5,1.0,en]","ui_S_t[f.logout.impl.direct_DefaultDirectLogoutView_null_DefaultDirectLogoutView-Night-1_3_null_1,NEXUS_5,1.0,en]",19846,],
-["ui_S_t[f.logout.impl.direct_DefaultDirectLogoutView_null_DefaultDirectLogoutView-Day-1_2_null_2,NEXUS_5,1.0,en]","ui_S_t[f.logout.impl.direct_DefaultDirectLogoutView_null_DefaultDirectLogoutView-Night-1_3_null_2,NEXUS_5,1.0,en]",19846,],
-["ui_S_t[f.logout.impl.direct_DefaultDirectLogoutView_null_DefaultDirectLogoutView-Day-1_2_null_3,NEXUS_5,1.0,en]","ui_S_t[f.logout.impl.direct_DefaultDirectLogoutView_null_DefaultDirectLogoutView-Night-1_3_null_3,NEXUS_5,1.0,en]",19846,],
+["ui_S_t[f.logout.impl.direct_DefaultDirectLogoutView_null_DefaultDirectLogoutView-Day-1_2_null_1,NEXUS_5,1.0,en]","ui_S_t[f.logout.impl.direct_DefaultDirectLogoutView_null_DefaultDirectLogoutView-Night-1_3_null_1,NEXUS_5,1.0,en]",19860,],
+["ui_S_t[f.logout.impl.direct_DefaultDirectLogoutView_null_DefaultDirectLogoutView-Day-1_2_null_2,NEXUS_5,1.0,en]","ui_S_t[f.logout.impl.direct_DefaultDirectLogoutView_null_DefaultDirectLogoutView-Night-1_3_null_2,NEXUS_5,1.0,en]",19860,],
+["ui_S_t[f.logout.impl.direct_DefaultDirectLogoutView_null_DefaultDirectLogoutView-Day-1_2_null_3,NEXUS_5,1.0,en]","ui_S_t[f.logout.impl.direct_DefaultDirectLogoutView_null_DefaultDirectLogoutView-Night-1_3_null_3,NEXUS_5,1.0,en]",19860,],
["ui_S_t[f.logout.impl.direct_DefaultDirectLogoutView_null_DefaultDirectLogoutView-Day-1_2_null_4,NEXUS_5,1.0,en]","ui_S_t[f.logout.impl.direct_DefaultDirectLogoutView_null_DefaultDirectLogoutView-Night-1_3_null_4,NEXUS_5,1.0,en]",0,],
-["ui_S_t[f.preferences.impl.notifications.edit_DefaultNotificationSettingOption_null_DefaultNotificationSettingOption-Day-7_8_null,NEXUS_5,1.0,en]","ui_S_t[f.preferences.impl.notifications.edit_DefaultNotificationSettingOption_null_DefaultNotificationSettingOption-Night-7_9_null,NEXUS_5,1.0,en]",19846,],
-["ui_S_t[f.roomlist.impl.components_DefaultRoomListTopBarWithIndicator_null_DefaultRoomListTopBarWithIndicator-Day-5_6_null,NEXUS_5,1.0,en]","ui_S_t[f.roomlist.impl.components_DefaultRoomListTopBarWithIndicator_null_DefaultRoomListTopBarWithIndicator-Night-5_7_null,NEXUS_5,1.0,en]",19846,],
-["ui_S_t[f.roomlist.impl.components_DefaultRoomListTopBar_null_DefaultRoomListTopBar-Day-4_5_null,NEXUS_5,1.0,en]","ui_S_t[f.roomlist.impl.components_DefaultRoomListTopBar_null_DefaultRoomListTopBar-Night-4_6_null,NEXUS_5,1.0,en]",19846,],
-["ui_S_t[f.preferences.impl.developer_DeveloperSettingsView_null_DeveloperSettingsView-Day-4_5_null_0,NEXUS_5,1.0,en]","ui_S_t[f.preferences.impl.developer_DeveloperSettingsView_null_DeveloperSettingsView-Night-4_6_null_0,NEXUS_5,1.0,en]",19846,],
-["ui_S_t[f.preferences.impl.developer_DeveloperSettingsView_null_DeveloperSettingsView-Day-4_5_null_1,NEXUS_5,1.0,en]","ui_S_t[f.preferences.impl.developer_DeveloperSettingsView_null_DeveloperSettingsView-Night-4_6_null_1,NEXUS_5,1.0,en]",19846,],
-["ui_S_t[f.preferences.impl.developer_DeveloperSettingsView_null_DeveloperSettingsView-Day-4_5_null_2,NEXUS_5,1.0,en]","ui_S_t[f.preferences.impl.developer_DeveloperSettingsView_null_DeveloperSettingsView-Night-4_6_null_2,NEXUS_5,1.0,en]",19846,],
-["ui_S_t[l.designsystem.atomic.molecules_DialogLikeBannerMolecule_null_DialogLikeBannerMolecule-Day_0_null,NEXUS_5,1.0,en]","ui_S_t[l.designsystem.atomic.molecules_DialogLikeBannerMolecule_null_DialogLikeBannerMolecule-Night_1_null,NEXUS_5,1.0,en]",19846,],
+["ui_S_t[f.preferences.impl.notifications.edit_DefaultNotificationSettingOption_null_DefaultNotificationSettingOption-Day-7_8_null,NEXUS_5,1.0,en]","ui_S_t[f.preferences.impl.notifications.edit_DefaultNotificationSettingOption_null_DefaultNotificationSettingOption-Night-7_9_null,NEXUS_5,1.0,en]",19860,],
+["ui_S_t[f.roomlist.impl.components_DefaultRoomListTopBarWithIndicator_null_DefaultRoomListTopBarWithIndicator-Day-5_6_null,NEXUS_5,1.0,en]","ui_S_t[f.roomlist.impl.components_DefaultRoomListTopBarWithIndicator_null_DefaultRoomListTopBarWithIndicator-Night-5_7_null,NEXUS_5,1.0,en]",19860,],
+["ui_S_t[f.roomlist.impl.components_DefaultRoomListTopBar_null_DefaultRoomListTopBar-Day-4_5_null,NEXUS_5,1.0,en]","ui_S_t[f.roomlist.impl.components_DefaultRoomListTopBar_null_DefaultRoomListTopBar-Night-4_6_null,NEXUS_5,1.0,en]",19860,],
+["ui_S_t[f.preferences.impl.developer_DeveloperSettingsView_null_DeveloperSettingsView-Day-4_5_null_0,NEXUS_5,1.0,en]","ui_S_t[f.preferences.impl.developer_DeveloperSettingsView_null_DeveloperSettingsView-Night-4_6_null_0,NEXUS_5,1.0,en]",19860,],
+["ui_S_t[f.preferences.impl.developer_DeveloperSettingsView_null_DeveloperSettingsView-Day-4_5_null_1,NEXUS_5,1.0,en]","ui_S_t[f.preferences.impl.developer_DeveloperSettingsView_null_DeveloperSettingsView-Night-4_6_null_1,NEXUS_5,1.0,en]",19860,],
+["ui_S_t[f.preferences.impl.developer_DeveloperSettingsView_null_DeveloperSettingsView-Day-4_5_null_2,NEXUS_5,1.0,en]","ui_S_t[f.preferences.impl.developer_DeveloperSettingsView_null_DeveloperSettingsView-Night-4_6_null_2,NEXUS_5,1.0,en]",19860,],
+["ui_S_t[l.designsystem.atomic.molecules_DialogLikeBannerMolecule_null_DialogLikeBannerMolecule-Day_0_null,NEXUS_5,1.0,en]","ui_S_t[l.designsystem.atomic.molecules_DialogLikeBannerMolecule_null_DialogLikeBannerMolecule-Night_1_null,NEXUS_5,1.0,en]",19860,],
["ui_S_t[l.designsystem.theme.components_DialogWithDestructiveButton_null_Dialogs_Dialogwithdestructivebutton_0_null,NEXUS_5,1.0,en]","",0,],
["ui_S_t[l.designsystem.theme.components_DialogWithOnlyMessageAndOkButton_null_Dialogs_Dialogwithonlymessageandokbutton_0_null,NEXUS_5,1.0,en]","",0,],
["ui_S_t[l.designsystem.theme.components_DialogWithThirdButton_null_Dialogs_Dialogwiththirdbutton_0_null,NEXUS_5,1.0,en]","",0,],
@@ -224,21 +225,24 @@ export const screenshots = [
["ui_S_t[l.designsystem.text_DpScale_1_0f__null_DpScale_1_0f__0_null,NEXUS_5,1.0,en]","",0,],
["ui_S_t[l.designsystem.text_DpScale_1_5f__null_DpScale_1_5f__0_null,NEXUS_5,1.0,en]","",0,],
["ui_S_t[l.designsystem.theme.components_DropdownMenuItem_null_Menus_DropdownMenuItem_0_null,NEXUS_5,1.0,en]","",0,],
-["ui_S_t[f.preferences.impl.notifications.edit_EditDefaultNotificationSettingView_null_EditDefaultNotificationSettingView-Day-8_9_null_0,NEXUS_5,1.0,en]","ui_S_t[f.preferences.impl.notifications.edit_EditDefaultNotificationSettingView_null_EditDefaultNotificationSettingView-Night-8_10_null_0,NEXUS_5,1.0,en]",19846,],
-["ui_S_t[f.preferences.impl.notifications.edit_EditDefaultNotificationSettingView_null_EditDefaultNotificationSettingView-Day-8_9_null_1,NEXUS_5,1.0,en]","ui_S_t[f.preferences.impl.notifications.edit_EditDefaultNotificationSettingView_null_EditDefaultNotificationSettingView-Night-8_10_null_1,NEXUS_5,1.0,en]",19846,],
-["ui_S_t[f.preferences.impl.notifications.edit_EditDefaultNotificationSettingView_null_EditDefaultNotificationSettingView-Day-8_9_null_2,NEXUS_5,1.0,en]","ui_S_t[f.preferences.impl.notifications.edit_EditDefaultNotificationSettingView_null_EditDefaultNotificationSettingView-Night-8_10_null_2,NEXUS_5,1.0,en]",19846,],
-["ui_S_t[f.preferences.impl.notifications.edit_EditDefaultNotificationSettingView_null_EditDefaultNotificationSettingView-Day-8_9_null_3,NEXUS_5,1.0,en]","ui_S_t[f.preferences.impl.notifications.edit_EditDefaultNotificationSettingView_null_EditDefaultNotificationSettingView-Night-8_10_null_3,NEXUS_5,1.0,en]",19846,],
-["ui_S_t[f.preferences.impl.notifications.edit_EditDefaultNotificationSettingView_null_EditDefaultNotificationSettingView-Day-8_9_null_4,NEXUS_5,1.0,en]","ui_S_t[f.preferences.impl.notifications.edit_EditDefaultNotificationSettingView_null_EditDefaultNotificationSettingView-Night-8_10_null_4,NEXUS_5,1.0,en]",19846,],
-["ui_S_t[f.preferences.impl.user.editprofile_EditUserProfileView_null_EditUserProfileView-Day-10_11_null_0,NEXUS_5,1.0,en]","ui_S_t[f.preferences.impl.user.editprofile_EditUserProfileView_null_EditUserProfileView-Night-10_12_null_0,NEXUS_5,1.0,en]",19846,],
+["ui_S_t[f.preferences.impl.notifications.edit_EditDefaultNotificationSettingView_null_EditDefaultNotificationSettingView-Day-8_9_null_0,NEXUS_5,1.0,en]","ui_S_t[f.preferences.impl.notifications.edit_EditDefaultNotificationSettingView_null_EditDefaultNotificationSettingView-Night-8_10_null_0,NEXUS_5,1.0,en]",19860,],
+["ui_S_t[f.preferences.impl.notifications.edit_EditDefaultNotificationSettingView_null_EditDefaultNotificationSettingView-Day-8_9_null_1,NEXUS_5,1.0,en]","ui_S_t[f.preferences.impl.notifications.edit_EditDefaultNotificationSettingView_null_EditDefaultNotificationSettingView-Night-8_10_null_1,NEXUS_5,1.0,en]",19860,],
+["ui_S_t[f.preferences.impl.notifications.edit_EditDefaultNotificationSettingView_null_EditDefaultNotificationSettingView-Day-8_9_null_2,NEXUS_5,1.0,en]","ui_S_t[f.preferences.impl.notifications.edit_EditDefaultNotificationSettingView_null_EditDefaultNotificationSettingView-Night-8_10_null_2,NEXUS_5,1.0,en]",19860,],
+["ui_S_t[f.preferences.impl.notifications.edit_EditDefaultNotificationSettingView_null_EditDefaultNotificationSettingView-Day-8_9_null_3,NEXUS_5,1.0,en]","ui_S_t[f.preferences.impl.notifications.edit_EditDefaultNotificationSettingView_null_EditDefaultNotificationSettingView-Night-8_10_null_3,NEXUS_5,1.0,en]",19860,],
+["ui_S_t[f.preferences.impl.notifications.edit_EditDefaultNotificationSettingView_null_EditDefaultNotificationSettingView-Day-8_9_null_4,NEXUS_5,1.0,en]","ui_S_t[f.preferences.impl.notifications.edit_EditDefaultNotificationSettingView_null_EditDefaultNotificationSettingView-Night-8_10_null_4,NEXUS_5,1.0,en]",19860,],
+["ui_S_t[f.preferences.impl.user.editprofile_EditUserProfileView_null_EditUserProfileView-Day-10_11_null_0,NEXUS_5,1.0,en]","ui_S_t[f.preferences.impl.user.editprofile_EditUserProfileView_null_EditUserProfileView-Night-10_12_null_0,NEXUS_5,1.0,en]",19860,],
+["ui_S_t[l.matrix.ui.components_EditableAvatarView_null_EditableAvatarView-Day-2_3_null_0,NEXUS_5,1.0,en]","ui_S_t[l.matrix.ui.components_EditableAvatarView_null_EditableAvatarView-Night-2_4_null_0,NEXUS_5,1.0,en]",0,],
+["ui_S_t[l.matrix.ui.components_EditableAvatarView_null_EditableAvatarView-Day-2_3_null_1,NEXUS_5,1.0,en]","ui_S_t[l.matrix.ui.components_EditableAvatarView_null_EditableAvatarView-Night-2_4_null_1,NEXUS_5,1.0,en]",0,],
+["ui_S_t[l.matrix.ui.components_EditableAvatarView_null_EditableAvatarView-Day-2_3_null_2,NEXUS_5,1.0,en]","ui_S_t[l.matrix.ui.components_EditableAvatarView_null_EditableAvatarView-Night-2_4_null_2,NEXUS_5,1.0,en]",0,],
["ui_S_t[l.designsystem.atomic.atoms_ElementLogoAtomLargeNoBlurShadow_null_ElementLogoAtomLargeNoBlurShadow-Day_0_null,NEXUS_5,1.0,en]","ui_S_t[l.designsystem.atomic.atoms_ElementLogoAtomLargeNoBlurShadow_null_ElementLogoAtomLargeNoBlurShadow-Night_1_null,NEXUS_5,1.0,en]",0,],
["ui_S_t[l.designsystem.atomic.atoms_ElementLogoAtomLarge_null_ElementLogoAtomLarge-Day_0_null,NEXUS_5,1.0,en]","ui_S_t[l.designsystem.atomic.atoms_ElementLogoAtomLarge_null_ElementLogoAtomLarge-Night_1_null,NEXUS_5,1.0,en]",0,],
["ui_S_t[l.designsystem.atomic.atoms_ElementLogoAtomMediumNoBlurShadow_null_ElementLogoAtomMediumNoBlurShadow-Day_0_null,NEXUS_5,1.0,en]","ui_S_t[l.designsystem.atomic.atoms_ElementLogoAtomMediumNoBlurShadow_null_ElementLogoAtomMediumNoBlurShadow-Night_1_null,NEXUS_5,1.0,en]",0,],
["ui_S_t[l.designsystem.atomic.atoms_ElementLogoAtomMedium_null_ElementLogoAtomMedium-Day_0_null,NEXUS_5,1.0,en]","ui_S_t[l.designsystem.atomic.atoms_ElementLogoAtomMedium_null_ElementLogoAtomMedium-Night_1_null,NEXUS_5,1.0,en]",0,],
["ui_S_t[f.messages.impl.timeline.components.customreaction_EmojiItem_null_EmojiItem-Day-34_34_null,NEXUS_5,1.0,en]","ui_S_t[f.messages.impl.timeline.components.customreaction_EmojiItem_null_EmojiItem-Night-34_35_null,NEXUS_5,1.0,en]",0,],
["ui_S_t[f.messages.impl.timeline.components.customreaction_EmojiPicker_null_EmojiPicker-Day-35_35_null,NEXUS_5,1.0,en]","ui_S_t[f.messages.impl.timeline.components.customreaction_EmojiPicker_null_EmojiPicker-Night-35_36_null,NEXUS_5,1.0,en]",0,],
-["ui_S_t[f.messages.impl.timeline.components.virtual_EncryptedHistoryBannerView_null_EncryptedHistoryBannerView-Day-60_60_null,NEXUS_5,1.0,en]","ui_S_t[f.messages.impl.timeline.components.virtual_EncryptedHistoryBannerView_null_EncryptedHistoryBannerView-Night-60_61_null,NEXUS_5,1.0,en]",19849,],
-["ui_S_t[l.designsystem.components.dialogs_ErrorDialogContent_null_Dialogs_ErrorDialogContent_0_null,NEXUS_5,1.0,en]","",19846,],
-["ui_S_t[l.designsystem.components.dialogs_ErrorDialog_null_ErrorDialog-Day_0_null,NEXUS_5,1.0,en]","ui_S_t[l.designsystem.components.dialogs_ErrorDialog_null_ErrorDialog-Night_1_null,NEXUS_5,1.0,en]",19846,],
+["ui_S_t[f.messages.impl.timeline.components.virtual_EncryptedHistoryBannerView_null_EncryptedHistoryBannerView-Day-60_60_null,NEXUS_5,1.0,en]","ui_S_t[f.messages.impl.timeline.components.virtual_EncryptedHistoryBannerView_null_EncryptedHistoryBannerView-Night-60_61_null,NEXUS_5,1.0,en]",19860,],
+["ui_S_t[l.designsystem.components.dialogs_ErrorDialogContent_null_Dialogs_ErrorDialogContent_0_null,NEXUS_5,1.0,en]","",19860,],
+["ui_S_t[l.designsystem.components.dialogs_ErrorDialog_null_ErrorDialog-Day_0_null,NEXUS_5,1.0,en]","ui_S_t[l.designsystem.components.dialogs_ErrorDialog_null_ErrorDialog-Night_1_null,NEXUS_5,1.0,en]",19860,],
["ui_S_t[f.messages.impl.timeline.debug_EventDebugInfoView_null_EventDebugInfoView-Day-65_65_null,NEXUS_5,1.0,en]","ui_S_t[f.messages.impl.timeline.debug_EventDebugInfoView_null_EventDebugInfoView-Night-65_66_null,NEXUS_5,1.0,en]",0,],
["ui_S_t[l.designsystem.theme.components_FilledButtonLarge_null_Buttons_FilledButtonLarge_0_null,NEXUS_5,1.0,en]","",0,],
["ui_S_t[l.designsystem.theme.components_FilledButtonMedium_null_Buttons_FilledButtonMedium_0_null,NEXUS_5,1.0,en]","",0,],
@@ -246,14 +250,14 @@ export const screenshots = [
["ui_S_t[l.designsystem.theme.components_FloatingActionButton_null_FloatingActionButtons_FloatingActionButton_0_null,NEXUS_5,1.0,en]","",0,],
["ui_S_t[l.designsystem.atomic.pages_FlowStepPage_null_FlowStepPage-Day_0_null,NEXUS_5,1.0,en]","ui_S_t[l.designsystem.atomic.pages_FlowStepPage_null_FlowStepPage-Night_1_null,NEXUS_5,1.0,en]",0,],
["ui_S_t[f.messages.impl.timeline.focus_FocusRequestStateView_null_FocusRequestStateView-Day-66_66_null_0,NEXUS_5,1.0,en]","ui_S_t[f.messages.impl.timeline.focus_FocusRequestStateView_null_FocusRequestStateView-Night-66_67_null_0,NEXUS_5,1.0,en]",0,],
-["ui_S_t[f.messages.impl.timeline.focus_FocusRequestStateView_null_FocusRequestStateView-Day-66_66_null_1,NEXUS_5,1.0,en]","ui_S_t[f.messages.impl.timeline.focus_FocusRequestStateView_null_FocusRequestStateView-Night-66_67_null_1,NEXUS_5,1.0,en]",19849,],
-["ui_S_t[f.messages.impl.timeline.focus_FocusRequestStateView_null_FocusRequestStateView-Day-66_66_null_2,NEXUS_5,1.0,en]","ui_S_t[f.messages.impl.timeline.focus_FocusRequestStateView_null_FocusRequestStateView-Night-66_67_null_2,NEXUS_5,1.0,en]",19849,],
-["ui_S_t[f.messages.impl.timeline.focus_FocusRequestStateView_null_FocusRequestStateView-Day-66_66_null_3,NEXUS_5,1.0,en]","ui_S_t[f.messages.impl.timeline.focus_FocusRequestStateView_null_FocusRequestStateView-Night-66_67_null_3,NEXUS_5,1.0,en]",19849,],
+["ui_S_t[f.messages.impl.timeline.focus_FocusRequestStateView_null_FocusRequestStateView-Day-66_66_null_1,NEXUS_5,1.0,en]","ui_S_t[f.messages.impl.timeline.focus_FocusRequestStateView_null_FocusRequestStateView-Night-66_67_null_1,NEXUS_5,1.0,en]",19860,],
+["ui_S_t[f.messages.impl.timeline.focus_FocusRequestStateView_null_FocusRequestStateView-Day-66_66_null_2,NEXUS_5,1.0,en]","ui_S_t[f.messages.impl.timeline.focus_FocusRequestStateView_null_FocusRequestStateView-Night-66_67_null_2,NEXUS_5,1.0,en]",19860,],
+["ui_S_t[f.messages.impl.timeline.focus_FocusRequestStateView_null_FocusRequestStateView-Day-66_66_null_3,NEXUS_5,1.0,en]","ui_S_t[f.messages.impl.timeline.focus_FocusRequestStateView_null_FocusRequestStateView-Night-66_67_null_3,NEXUS_5,1.0,en]",19860,],
["ui_S_t[l.textcomposer.components_FormattingOption_null_FormattingOption-Day-10_11_null,NEXUS_5,1.0,en]","ui_S_t[l.textcomposer.components_FormattingOption_null_FormattingOption-Night-10_12_null,NEXUS_5,1.0,en]",0,],
["ui_S_t[f.messages.impl.forward_ForwardMessagesView_null_ForwardMessagesView-Day-2_2_null_0,NEXUS_5,1.0,en]","ui_S_t[f.messages.impl.forward_ForwardMessagesView_null_ForwardMessagesView-Night-2_3_null_0,NEXUS_5,1.0,en]",0,],
["ui_S_t[f.messages.impl.forward_ForwardMessagesView_null_ForwardMessagesView-Day-2_2_null_1,NEXUS_5,1.0,en]","ui_S_t[f.messages.impl.forward_ForwardMessagesView_null_ForwardMessagesView-Night-2_3_null_1,NEXUS_5,1.0,en]",0,],
["ui_S_t[f.messages.impl.forward_ForwardMessagesView_null_ForwardMessagesView-Day-2_2_null_2,NEXUS_5,1.0,en]","ui_S_t[f.messages.impl.forward_ForwardMessagesView_null_ForwardMessagesView-Night-2_3_null_2,NEXUS_5,1.0,en]",0,],
-["ui_S_t[f.messages.impl.forward_ForwardMessagesView_null_ForwardMessagesView-Day-2_2_null_3,NEXUS_5,1.0,en]","ui_S_t[f.messages.impl.forward_ForwardMessagesView_null_ForwardMessagesView-Night-2_3_null_3,NEXUS_5,1.0,en]",19846,],
+["ui_S_t[f.messages.impl.forward_ForwardMessagesView_null_ForwardMessagesView-Day-2_2_null_3,NEXUS_5,1.0,en]","ui_S_t[f.messages.impl.forward_ForwardMessagesView_null_ForwardMessagesView-Night-2_3_null_3,NEXUS_5,1.0,en]",19860,],
["ui_S_t[l.designsystem.components.button_GradientFloatingActionButtonCircleShape_null_GradientFloatingActionButtonCircleShape-Day_0_null,NEXUS_5,1.0,en]","ui_S_t[l.designsystem.components.button_GradientFloatingActionButtonCircleShape_null_GradientFloatingActionButtonCircleShape-Night_1_null,NEXUS_5,1.0,en]",0,],
["ui_S_t[l.designsystem.components.button_GradientFloatingActionButton_null_GradientFloatingActionButton-Day_0_null,NEXUS_5,1.0,en]","ui_S_t[l.designsystem.components.button_GradientFloatingActionButton_null_GradientFloatingActionButton-Night_1_null,NEXUS_5,1.0,en]",0,],
["ui_S_t[f.messages.impl.timeline.components.group_GroupHeaderView_null_GroupHeaderView-Day-55_55_null,NEXUS_5,1.0,en]","ui_S_t[f.messages.impl.timeline.components.group_GroupHeaderView_null_GroupHeaderView-Night-55_56_null,NEXUS_5,1.0,en]",0,],
@@ -274,27 +278,27 @@ export const screenshots = [
["ui_S_t[l.designsystem.icons_IconsOther_null_IconsOther-Day_0_null_0,NEXUS_5,1.0,en]","ui_S_t[l.designsystem.icons_IconsOther_null_IconsOther-Night_1_null_0,NEXUS_5,1.0,en]",0,],
["ui_S_t[l.designsystem.atomic.molecules_InfoListItemMolecule_null_InfoListItemMolecule-Day_0_null,NEXUS_5,1.0,en]","ui_S_t[l.designsystem.atomic.molecules_InfoListItemMolecule_null_InfoListItemMolecule-Night_1_null,NEXUS_5,1.0,en]",0,],
["ui_S_t[l.designsystem.atomic.organisms_InfoListOrganism_null_InfoListOrganism-Day_0_null,NEXUS_5,1.0,en]","ui_S_t[l.designsystem.atomic.organisms_InfoListOrganism_null_InfoListOrganism-Night_1_null,NEXUS_5,1.0,en]",0,],
-["ui_S_t[l.matrix.ui.components_InviteSenderView_null_InviteSenderView-Day-2_3_null,NEXUS_5,1.0,en]","ui_S_t[l.matrix.ui.components_InviteSenderView_null_InviteSenderView-Night-2_4_null,NEXUS_5,1.0,en]",19846,],
+["ui_S_t[l.matrix.ui.components_InviteSenderView_null_InviteSenderView-Day-3_4_null,NEXUS_5,1.0,en]","ui_S_t[l.matrix.ui.components_InviteSenderView_null_InviteSenderView-Night-3_5_null,NEXUS_5,1.0,en]",19863,],
["ui_S_t[f.joinroom.impl_JoinRoomView_null_JoinRoomView-Day-0_1_null_0,NEXUS_5,1.0,en]","ui_S_t[f.joinroom.impl_JoinRoomView_null_JoinRoomView-Night-0_2_null_0,NEXUS_5,1.0,en]",0,],
-["ui_S_t[f.joinroom.impl_JoinRoomView_null_JoinRoomView-Day-0_1_null_1,NEXUS_5,1.0,en]","ui_S_t[f.joinroom.impl_JoinRoomView_null_JoinRoomView-Night-0_2_null_1,NEXUS_5,1.0,en]",19846,],
-["ui_S_t[f.joinroom.impl_JoinRoomView_null_JoinRoomView-Day-0_1_null_2,NEXUS_5,1.0,en]","ui_S_t[f.joinroom.impl_JoinRoomView_null_JoinRoomView-Night-0_2_null_2,NEXUS_5,1.0,en]",19846,],
-["ui_S_t[f.joinroom.impl_JoinRoomView_null_JoinRoomView-Day-0_1_null_3,NEXUS_5,1.0,en]","ui_S_t[f.joinroom.impl_JoinRoomView_null_JoinRoomView-Night-0_2_null_3,NEXUS_5,1.0,en]",19846,],
-["ui_S_t[f.joinroom.impl_JoinRoomView_null_JoinRoomView-Day-0_1_null_4,NEXUS_5,1.0,en]","ui_S_t[f.joinroom.impl_JoinRoomView_null_JoinRoomView-Night-0_2_null_4,NEXUS_5,1.0,en]",19846,],
-["ui_S_t[f.joinroom.impl_JoinRoomView_null_JoinRoomView-Day-0_1_null_5,NEXUS_5,1.0,en]","ui_S_t[f.joinroom.impl_JoinRoomView_null_JoinRoomView-Night-0_2_null_5,NEXUS_5,1.0,en]",19846,],
-["ui_S_t[f.joinroom.impl_JoinRoomView_null_JoinRoomView-Day-0_1_null_6,NEXUS_5,1.0,en]","ui_S_t[f.joinroom.impl_JoinRoomView_null_JoinRoomView-Night-0_2_null_6,NEXUS_5,1.0,en]",19846,],
-["ui_S_t[f.joinroom.impl_JoinRoomView_null_JoinRoomView-Day-0_1_null_7,NEXUS_5,1.0,en]","ui_S_t[f.joinroom.impl_JoinRoomView_null_JoinRoomView-Night-0_2_null_7,NEXUS_5,1.0,en]",19846,],
-["ui_S_t[f.joinroom.impl_JoinRoomView_null_JoinRoomView-Day-0_1_null_8,NEXUS_5,1.0,en]","ui_S_t[f.joinroom.impl_JoinRoomView_null_JoinRoomView-Night-0_2_null_8,NEXUS_5,1.0,en]",19846,],
-["ui_S_t[f.joinroom.impl_JoinRoomView_null_JoinRoomView-Day-0_1_null_9,NEXUS_5,1.0,en]","ui_S_t[f.joinroom.impl_JoinRoomView_null_JoinRoomView-Night-0_2_null_9,NEXUS_5,1.0,en]",19846,],
+["ui_S_t[f.joinroom.impl_JoinRoomView_null_JoinRoomView-Day-0_1_null_1,NEXUS_5,1.0,en]","ui_S_t[f.joinroom.impl_JoinRoomView_null_JoinRoomView-Night-0_2_null_1,NEXUS_5,1.0,en]",19860,],
+["ui_S_t[f.joinroom.impl_JoinRoomView_null_JoinRoomView-Day-0_1_null_2,NEXUS_5,1.0,en]","ui_S_t[f.joinroom.impl_JoinRoomView_null_JoinRoomView-Night-0_2_null_2,NEXUS_5,1.0,en]",19860,],
+["ui_S_t[f.joinroom.impl_JoinRoomView_null_JoinRoomView-Day-0_1_null_3,NEXUS_5,1.0,en]","ui_S_t[f.joinroom.impl_JoinRoomView_null_JoinRoomView-Night-0_2_null_3,NEXUS_5,1.0,en]",19860,],
+["ui_S_t[f.joinroom.impl_JoinRoomView_null_JoinRoomView-Day-0_1_null_4,NEXUS_5,1.0,en]","ui_S_t[f.joinroom.impl_JoinRoomView_null_JoinRoomView-Night-0_2_null_4,NEXUS_5,1.0,en]",19860,],
+["ui_S_t[f.joinroom.impl_JoinRoomView_null_JoinRoomView-Day-0_1_null_5,NEXUS_5,1.0,en]","ui_S_t[f.joinroom.impl_JoinRoomView_null_JoinRoomView-Night-0_2_null_5,NEXUS_5,1.0,en]",19860,],
+["ui_S_t[f.joinroom.impl_JoinRoomView_null_JoinRoomView-Day-0_1_null_6,NEXUS_5,1.0,en]","ui_S_t[f.joinroom.impl_JoinRoomView_null_JoinRoomView-Night-0_2_null_6,NEXUS_5,1.0,en]",19860,],
+["ui_S_t[f.joinroom.impl_JoinRoomView_null_JoinRoomView-Day-0_1_null_7,NEXUS_5,1.0,en]","ui_S_t[f.joinroom.impl_JoinRoomView_null_JoinRoomView-Night-0_2_null_7,NEXUS_5,1.0,en]",19860,],
+["ui_S_t[f.joinroom.impl_JoinRoomView_null_JoinRoomView-Day-0_1_null_8,NEXUS_5,1.0,en]","ui_S_t[f.joinroom.impl_JoinRoomView_null_JoinRoomView-Night-0_2_null_8,NEXUS_5,1.0,en]",19860,],
+["ui_S_t[f.joinroom.impl_JoinRoomView_null_JoinRoomView-Day-0_1_null_9,NEXUS_5,1.0,en]","ui_S_t[f.joinroom.impl_JoinRoomView_null_JoinRoomView-Night-0_2_null_9,NEXUS_5,1.0,en]",19860,],
["ui_S_t[l.designsystem.components_LabelledCheckbox_null_Toggles_LabelledCheckbox_0_null,NEXUS_5,1.0,en]","",0,],
["ui_S_t[l.designsystem.components_LabelledOutlinedTextField_null_LabelledOutlinedTextField-Day_0_null,NEXUS_5,1.0,en]","ui_S_t[l.designsystem.components_LabelledOutlinedTextField_null_LabelledOutlinedTextField-Night_1_null,NEXUS_5,1.0,en]",0,],
["ui_S_t[l.designsystem.components_LabelledTextField_null_LabelledTextField-Day_0_null,NEXUS_5,1.0,en]","ui_S_t[l.designsystem.components_LabelledTextField_null_LabelledTextField-Night_1_null,NEXUS_5,1.0,en]",0,],
["ui_S_t[f.leaveroom.api_LeaveRoomView_null_LeaveRoomView-Day-0_1_null_0,NEXUS_5,1.0,en]","ui_S_t[f.leaveroom.api_LeaveRoomView_null_LeaveRoomView-Night-0_2_null_0,NEXUS_5,1.0,en]",0,],
-["ui_S_t[f.leaveroom.api_LeaveRoomView_null_LeaveRoomView-Day-0_1_null_1,NEXUS_5,1.0,en]","ui_S_t[f.leaveroom.api_LeaveRoomView_null_LeaveRoomView-Night-0_2_null_1,NEXUS_5,1.0,en]",19846,],
-["ui_S_t[f.leaveroom.api_LeaveRoomView_null_LeaveRoomView-Day-0_1_null_2,NEXUS_5,1.0,en]","ui_S_t[f.leaveroom.api_LeaveRoomView_null_LeaveRoomView-Night-0_2_null_2,NEXUS_5,1.0,en]",19846,],
-["ui_S_t[f.leaveroom.api_LeaveRoomView_null_LeaveRoomView-Day-0_1_null_3,NEXUS_5,1.0,en]","ui_S_t[f.leaveroom.api_LeaveRoomView_null_LeaveRoomView-Night-0_2_null_3,NEXUS_5,1.0,en]",19846,],
-["ui_S_t[f.leaveroom.api_LeaveRoomView_null_LeaveRoomView-Day-0_1_null_4,NEXUS_5,1.0,en]","ui_S_t[f.leaveroom.api_LeaveRoomView_null_LeaveRoomView-Night-0_2_null_4,NEXUS_5,1.0,en]",19846,],
-["ui_S_t[f.leaveroom.api_LeaveRoomView_null_LeaveRoomView-Day-0_1_null_5,NEXUS_5,1.0,en]","ui_S_t[f.leaveroom.api_LeaveRoomView_null_LeaveRoomView-Night-0_2_null_5,NEXUS_5,1.0,en]",19846,],
-["ui_S_t[f.leaveroom.api_LeaveRoomView_null_LeaveRoomView-Day-0_1_null_6,NEXUS_5,1.0,en]","ui_S_t[f.leaveroom.api_LeaveRoomView_null_LeaveRoomView-Night-0_2_null_6,NEXUS_5,1.0,en]",19846,],
+["ui_S_t[f.leaveroom.api_LeaveRoomView_null_LeaveRoomView-Day-0_1_null_1,NEXUS_5,1.0,en]","ui_S_t[f.leaveroom.api_LeaveRoomView_null_LeaveRoomView-Night-0_2_null_1,NEXUS_5,1.0,en]",19860,],
+["ui_S_t[f.leaveroom.api_LeaveRoomView_null_LeaveRoomView-Day-0_1_null_2,NEXUS_5,1.0,en]","ui_S_t[f.leaveroom.api_LeaveRoomView_null_LeaveRoomView-Night-0_2_null_2,NEXUS_5,1.0,en]",19860,],
+["ui_S_t[f.leaveroom.api_LeaveRoomView_null_LeaveRoomView-Day-0_1_null_3,NEXUS_5,1.0,en]","ui_S_t[f.leaveroom.api_LeaveRoomView_null_LeaveRoomView-Night-0_2_null_3,NEXUS_5,1.0,en]",19860,],
+["ui_S_t[f.leaveroom.api_LeaveRoomView_null_LeaveRoomView-Day-0_1_null_4,NEXUS_5,1.0,en]","ui_S_t[f.leaveroom.api_LeaveRoomView_null_LeaveRoomView-Night-0_2_null_4,NEXUS_5,1.0,en]",19860,],
+["ui_S_t[f.leaveroom.api_LeaveRoomView_null_LeaveRoomView-Day-0_1_null_5,NEXUS_5,1.0,en]","ui_S_t[f.leaveroom.api_LeaveRoomView_null_LeaveRoomView-Night-0_2_null_5,NEXUS_5,1.0,en]",19860,],
+["ui_S_t[f.leaveroom.api_LeaveRoomView_null_LeaveRoomView-Day-0_1_null_6,NEXUS_5,1.0,en]","ui_S_t[f.leaveroom.api_LeaveRoomView_null_LeaveRoomView-Night-0_2_null_6,NEXUS_5,1.0,en]",19860,],
["ui_S_t[l.designsystem.background_LightGradientBackground_null_LightGradientBackground-Day_0_null,NEXUS_5,1.0,en]","ui_S_t[l.designsystem.background_LightGradientBackground_null_LightGradientBackground-Night_1_null,NEXUS_5,1.0,en]",0,],
["ui_S_t[l.designsystem.theme.components_LinearProgressIndicator_null_ProgressIndicators_LinearProgressIndicator_0_null,NEXUS_5,1.0,en]","",0,],
["ui_S_t[l.designsystem.components.dialogs_ListDialogContent_null_Dialogs_ListDialogContent_0_null,NEXUS_5,1.0,en]","",0,],
@@ -345,35 +349,35 @@ export const screenshots = [
["ui_S_t[l.designsystem.theme.components_ListSupportingTextSmallPadding_null_Listsections_Listsupportingtext-smallpadding_0_null,NEXUS_5,1.0,en]","",0,],
["ui_S_t[l.textcomposer.components_LiveWaveformView_null_LiveWaveformView-Day-11_12_null,NEXUS_5,1.0,en]","ui_S_t[l.textcomposer.components_LiveWaveformView_null_LiveWaveformView-Night-11_13_null,NEXUS_5,1.0,en]",0,],
["ui_S_t[appnav.room.joined_LoadingRoomNodeView_null_LoadingRoomNodeView-Day-2_2_null_0,NEXUS_5,1.0,en]","ui_S_t[appnav.room.joined_LoadingRoomNodeView_null_LoadingRoomNodeView-Night-2_3_null_0,NEXUS_5,1.0,en]",0,],
-["ui_S_t[appnav.room.joined_LoadingRoomNodeView_null_LoadingRoomNodeView-Day-2_2_null_1,NEXUS_5,1.0,en]","ui_S_t[appnav.room.joined_LoadingRoomNodeView_null_LoadingRoomNodeView-Night-2_3_null_1,NEXUS_5,1.0,en]",19846,],
-["ui_S_t[f.lockscreen.impl.settings_LockScreenSettingsView_null_LockScreenSettingsView-Day-1_2_null_0,NEXUS_5,1.0,en]","ui_S_t[f.lockscreen.impl.settings_LockScreenSettingsView_null_LockScreenSettingsView-Night-1_3_null_0,NEXUS_5,1.0,en]",19846,],
-["ui_S_t[f.lockscreen.impl.settings_LockScreenSettingsView_null_LockScreenSettingsView-Day-1_2_null_1,NEXUS_5,1.0,en]","ui_S_t[f.lockscreen.impl.settings_LockScreenSettingsView_null_LockScreenSettingsView-Night-1_3_null_1,NEXUS_5,1.0,en]",19846,],
-["ui_S_t[f.lockscreen.impl.settings_LockScreenSettingsView_null_LockScreenSettingsView-Day-1_2_null_2,NEXUS_5,1.0,en]","ui_S_t[f.lockscreen.impl.settings_LockScreenSettingsView_null_LockScreenSettingsView-Night-1_3_null_2,NEXUS_5,1.0,en]",19846,],
+["ui_S_t[appnav.room.joined_LoadingRoomNodeView_null_LoadingRoomNodeView-Day-2_2_null_1,NEXUS_5,1.0,en]","ui_S_t[appnav.room.joined_LoadingRoomNodeView_null_LoadingRoomNodeView-Night-2_3_null_1,NEXUS_5,1.0,en]",19860,],
+["ui_S_t[f.lockscreen.impl.settings_LockScreenSettingsView_null_LockScreenSettingsView-Day-1_2_null_0,NEXUS_5,1.0,en]","ui_S_t[f.lockscreen.impl.settings_LockScreenSettingsView_null_LockScreenSettingsView-Night-1_3_null_0,NEXUS_5,1.0,en]",19860,],
+["ui_S_t[f.lockscreen.impl.settings_LockScreenSettingsView_null_LockScreenSettingsView-Day-1_2_null_1,NEXUS_5,1.0,en]","ui_S_t[f.lockscreen.impl.settings_LockScreenSettingsView_null_LockScreenSettingsView-Night-1_3_null_1,NEXUS_5,1.0,en]",19860,],
+["ui_S_t[f.lockscreen.impl.settings_LockScreenSettingsView_null_LockScreenSettingsView-Day-1_2_null_2,NEXUS_5,1.0,en]","ui_S_t[f.lockscreen.impl.settings_LockScreenSettingsView_null_LockScreenSettingsView-Night-1_3_null_2,NEXUS_5,1.0,en]",19860,],
["ui_S_t[appnav.loggedin_LoggedInView_null_LoggedInView-Day-0_0_null_0,NEXUS_5,1.0,en]","ui_S_t[appnav.loggedin_LoggedInView_null_LoggedInView-Night-0_1_null_0,NEXUS_5,1.0,en]",0,],
-["ui_S_t[appnav.loggedin_LoggedInView_null_LoggedInView-Day-0_0_null_1,NEXUS_5,1.0,en]","ui_S_t[appnav.loggedin_LoggedInView_null_LoggedInView-Night-0_1_null_1,NEXUS_5,1.0,en]",19846,],
-["ui_S_t[f.login.impl.screens.loginpassword_LoginPasswordView_null_LoginPasswordView-Day-6_7_null_0,NEXUS_5,1.0,en]","ui_S_t[f.login.impl.screens.loginpassword_LoginPasswordView_null_LoginPasswordView-Night-6_8_null_0,NEXUS_5,1.0,en]",19846,],
-["ui_S_t[f.login.impl.screens.loginpassword_LoginPasswordView_null_LoginPasswordView-Day-6_7_null_1,NEXUS_5,1.0,en]","ui_S_t[f.login.impl.screens.loginpassword_LoginPasswordView_null_LoginPasswordView-Night-6_8_null_1,NEXUS_5,1.0,en]",19846,],
-["ui_S_t[f.login.impl.screens.loginpassword_LoginPasswordView_null_LoginPasswordView-Day-6_7_null_2,NEXUS_5,1.0,en]","ui_S_t[f.login.impl.screens.loginpassword_LoginPasswordView_null_LoginPasswordView-Night-6_8_null_2,NEXUS_5,1.0,en]",19846,],
-["ui_S_t[f.logout.impl_LogoutView_null_LogoutView-Day-0_1_null_0,NEXUS_5,1.0,en]","ui_S_t[f.logout.impl_LogoutView_null_LogoutView-Night-0_2_null_0,NEXUS_5,1.0,en]",19846,],
-["ui_S_t[f.logout.impl_LogoutView_null_LogoutView-Day-0_1_null_1,NEXUS_5,1.0,en]","ui_S_t[f.logout.impl_LogoutView_null_LogoutView-Night-0_2_null_1,NEXUS_5,1.0,en]",19846,],
-["ui_S_t[f.logout.impl_LogoutView_null_LogoutView-Day-0_1_null_2,NEXUS_5,1.0,en]","ui_S_t[f.logout.impl_LogoutView_null_LogoutView-Night-0_2_null_2,NEXUS_5,1.0,en]",19846,],
-["ui_S_t[f.logout.impl_LogoutView_null_LogoutView-Day-0_1_null_3,NEXUS_5,1.0,en]","ui_S_t[f.logout.impl_LogoutView_null_LogoutView-Night-0_2_null_3,NEXUS_5,1.0,en]",19846,],
-["ui_S_t[f.logout.impl_LogoutView_null_LogoutView-Day-0_1_null_4,NEXUS_5,1.0,en]","ui_S_t[f.logout.impl_LogoutView_null_LogoutView-Night-0_2_null_4,NEXUS_5,1.0,en]",19846,],
-["ui_S_t[f.logout.impl_LogoutView_null_LogoutView-Day-0_1_null_5,NEXUS_5,1.0,en]","ui_S_t[f.logout.impl_LogoutView_null_LogoutView-Night-0_2_null_5,NEXUS_5,1.0,en]",19846,],
-["ui_S_t[f.logout.impl_LogoutView_null_LogoutView-Day-0_1_null_6,NEXUS_5,1.0,en]","ui_S_t[f.logout.impl_LogoutView_null_LogoutView-Night-0_2_null_6,NEXUS_5,1.0,en]",19846,],
-["ui_S_t[f.logout.impl_LogoutView_null_LogoutView-Day-0_1_null_7,NEXUS_5,1.0,en]","ui_S_t[f.logout.impl_LogoutView_null_LogoutView-Night-0_2_null_7,NEXUS_5,1.0,en]",19846,],
-["ui_S_t[f.logout.impl_LogoutView_null_LogoutView-Day-0_1_null_8,NEXUS_5,1.0,en]","ui_S_t[f.logout.impl_LogoutView_null_LogoutView-Night-0_2_null_8,NEXUS_5,1.0,en]",19846,],
-["ui_S_t[f.logout.impl_LogoutView_null_LogoutView-Day-0_1_null_9,NEXUS_5,1.0,en]","ui_S_t[f.logout.impl_LogoutView_null_LogoutView-Night-0_2_null_9,NEXUS_5,1.0,en]",19846,],
+["ui_S_t[appnav.loggedin_LoggedInView_null_LoggedInView-Day-0_0_null_1,NEXUS_5,1.0,en]","ui_S_t[appnav.loggedin_LoggedInView_null_LoggedInView-Night-0_1_null_1,NEXUS_5,1.0,en]",19860,],
+["ui_S_t[f.login.impl.screens.loginpassword_LoginPasswordView_null_LoginPasswordView-Day-6_7_null_0,NEXUS_5,1.0,en]","ui_S_t[f.login.impl.screens.loginpassword_LoginPasswordView_null_LoginPasswordView-Night-6_8_null_0,NEXUS_5,1.0,en]",19860,],
+["ui_S_t[f.login.impl.screens.loginpassword_LoginPasswordView_null_LoginPasswordView-Day-6_7_null_1,NEXUS_5,1.0,en]","ui_S_t[f.login.impl.screens.loginpassword_LoginPasswordView_null_LoginPasswordView-Night-6_8_null_1,NEXUS_5,1.0,en]",19860,],
+["ui_S_t[f.login.impl.screens.loginpassword_LoginPasswordView_null_LoginPasswordView-Day-6_7_null_2,NEXUS_5,1.0,en]","ui_S_t[f.login.impl.screens.loginpassword_LoginPasswordView_null_LoginPasswordView-Night-6_8_null_2,NEXUS_5,1.0,en]",19860,],
+["ui_S_t[f.logout.impl_LogoutView_null_LogoutView-Day-0_1_null_0,NEXUS_5,1.0,en]","ui_S_t[f.logout.impl_LogoutView_null_LogoutView-Night-0_2_null_0,NEXUS_5,1.0,en]",19860,],
+["ui_S_t[f.logout.impl_LogoutView_null_LogoutView-Day-0_1_null_1,NEXUS_5,1.0,en]","ui_S_t[f.logout.impl_LogoutView_null_LogoutView-Night-0_2_null_1,NEXUS_5,1.0,en]",19860,],
+["ui_S_t[f.logout.impl_LogoutView_null_LogoutView-Day-0_1_null_2,NEXUS_5,1.0,en]","ui_S_t[f.logout.impl_LogoutView_null_LogoutView-Night-0_2_null_2,NEXUS_5,1.0,en]",19860,],
+["ui_S_t[f.logout.impl_LogoutView_null_LogoutView-Day-0_1_null_3,NEXUS_5,1.0,en]","ui_S_t[f.logout.impl_LogoutView_null_LogoutView-Night-0_2_null_3,NEXUS_5,1.0,en]",19860,],
+["ui_S_t[f.logout.impl_LogoutView_null_LogoutView-Day-0_1_null_4,NEXUS_5,1.0,en]","ui_S_t[f.logout.impl_LogoutView_null_LogoutView-Night-0_2_null_4,NEXUS_5,1.0,en]",19860,],
+["ui_S_t[f.logout.impl_LogoutView_null_LogoutView-Day-0_1_null_5,NEXUS_5,1.0,en]","ui_S_t[f.logout.impl_LogoutView_null_LogoutView-Night-0_2_null_5,NEXUS_5,1.0,en]",19860,],
+["ui_S_t[f.logout.impl_LogoutView_null_LogoutView-Day-0_1_null_6,NEXUS_5,1.0,en]","ui_S_t[f.logout.impl_LogoutView_null_LogoutView-Night-0_2_null_6,NEXUS_5,1.0,en]",19860,],
+["ui_S_t[f.logout.impl_LogoutView_null_LogoutView-Day-0_1_null_7,NEXUS_5,1.0,en]","ui_S_t[f.logout.impl_LogoutView_null_LogoutView-Night-0_2_null_7,NEXUS_5,1.0,en]",19860,],
+["ui_S_t[f.logout.impl_LogoutView_null_LogoutView-Day-0_1_null_8,NEXUS_5,1.0,en]","ui_S_t[f.logout.impl_LogoutView_null_LogoutView-Night-0_2_null_8,NEXUS_5,1.0,en]",19860,],
+["ui_S_t[f.logout.impl_LogoutView_null_LogoutView-Day-0_1_null_9,NEXUS_5,1.0,en]","ui_S_t[f.logout.impl_LogoutView_null_LogoutView-Night-0_2_null_9,NEXUS_5,1.0,en]",19860,],
["ui_S_t[l.designsystem.components.button_MainActionButton_null_Buttons_MainActionButton_0_null,NEXUS_5,1.0,en]","",0,],
-["ui_S_t[l.matrix.ui.components_MatrixUserHeaderPlaceholder_null_MatrixUserHeaderPlaceholder-Day-4_5_null,NEXUS_5,1.0,en]","ui_S_t[l.matrix.ui.components_MatrixUserHeaderPlaceholder_null_MatrixUserHeaderPlaceholder-Night-4_6_null,NEXUS_5,1.0,en]",0,],
-["ui_S_t[l.matrix.ui.components_MatrixUserHeader_null_MatrixUserHeader-Day-3_4_null_0,NEXUS_5,1.0,en]","ui_S_t[l.matrix.ui.components_MatrixUserHeader_null_MatrixUserHeader-Night-3_5_null_0,NEXUS_5,1.0,en]",0,],
-["ui_S_t[l.matrix.ui.components_MatrixUserHeader_null_MatrixUserHeader-Day-3_4_null_1,NEXUS_5,1.0,en]","ui_S_t[l.matrix.ui.components_MatrixUserHeader_null_MatrixUserHeader-Night-3_5_null_1,NEXUS_5,1.0,en]",0,],
-["ui_S_t[l.matrix.ui.components_MatrixUserRow_null_MatrixUserRow-Day-5_6_null_0,NEXUS_5,1.0,en]","ui_S_t[l.matrix.ui.components_MatrixUserRow_null_MatrixUserRow-Night-5_7_null_0,NEXUS_5,1.0,en]",0,],
-["ui_S_t[l.matrix.ui.components_MatrixUserRow_null_MatrixUserRow-Day-5_6_null_1,NEXUS_5,1.0,en]","ui_S_t[l.matrix.ui.components_MatrixUserRow_null_MatrixUserRow-Night-5_7_null_1,NEXUS_5,1.0,en]",0,],
+["ui_S_t[l.matrix.ui.components_MatrixUserHeaderPlaceholder_null_MatrixUserHeaderPlaceholder-Day-5_6_null,NEXUS_5,1.0,en]","ui_S_t[l.matrix.ui.components_MatrixUserHeaderPlaceholder_null_MatrixUserHeaderPlaceholder-Night-5_7_null,NEXUS_5,1.0,en]",0,],
+["ui_S_t[l.matrix.ui.components_MatrixUserHeader_null_MatrixUserHeader-Day-4_5_null_0,NEXUS_5,1.0,en]","ui_S_t[l.matrix.ui.components_MatrixUserHeader_null_MatrixUserHeader-Night-4_6_null_0,NEXUS_5,1.0,en]",0,],
+["ui_S_t[l.matrix.ui.components_MatrixUserHeader_null_MatrixUserHeader-Day-4_5_null_1,NEXUS_5,1.0,en]","ui_S_t[l.matrix.ui.components_MatrixUserHeader_null_MatrixUserHeader-Night-4_6_null_1,NEXUS_5,1.0,en]",0,],
+["ui_S_t[l.matrix.ui.components_MatrixUserRow_null_MatrixUserRow-Day-6_7_null_0,NEXUS_5,1.0,en]","ui_S_t[l.matrix.ui.components_MatrixUserRow_null_MatrixUserRow-Night-6_8_null_0,NEXUS_5,1.0,en]",0,],
+["ui_S_t[l.matrix.ui.components_MatrixUserRow_null_MatrixUserRow-Day-6_7_null_1,NEXUS_5,1.0,en]","ui_S_t[l.matrix.ui.components_MatrixUserRow_null_MatrixUserRow-Night-6_8_null_1,NEXUS_5,1.0,en]",0,],
["ui_S_t[l.mediaviewer.api.viewer_MediaViewerView_null_MediaViewerView_0_null_0,NEXUS_5,1.0,en]","",0,],
["ui_S_t[l.mediaviewer.api.viewer_MediaViewerView_null_MediaViewerView_0_null_1,NEXUS_5,1.0,en]","",0,],
["ui_S_t[l.mediaviewer.api.viewer_MediaViewerView_null_MediaViewerView_0_null_10,NEXUS_5,1.0,en]","",0,],
-["ui_S_t[l.mediaviewer.api.viewer_MediaViewerView_null_MediaViewerView_0_null_2,NEXUS_5,1.0,en]","",19846,],
+["ui_S_t[l.mediaviewer.api.viewer_MediaViewerView_null_MediaViewerView_0_null_2,NEXUS_5,1.0,en]","",19860,],
["ui_S_t[l.mediaviewer.api.viewer_MediaViewerView_null_MediaViewerView_0_null_3,NEXUS_5,1.0,en]","",0,],
["ui_S_t[l.mediaviewer.api.viewer_MediaViewerView_null_MediaViewerView_0_null_4,NEXUS_5,1.0,en]","",0,],
["ui_S_t[l.mediaviewer.api.viewer_MediaViewerView_null_MediaViewerView_0_null_5,NEXUS_5,1.0,en]","",0,],
@@ -383,10 +387,10 @@ export const screenshots = [
["ui_S_t[l.mediaviewer.api.viewer_MediaViewerView_null_MediaViewerView_0_null_9,NEXUS_5,1.0,en]","",0,],
["ui_S_t[l.designsystem.theme.components_MediumTopAppBar_null_AppBars_MediumTopAppBar_0_null,NEXUS_5,1.0,en]","",0,],
["ui_S_t[l.textcomposer.mentions_MentionSpan_null_MentionSpan-Day-18_19_null,NEXUS_5,1.0,en]","ui_S_t[l.textcomposer.mentions_MentionSpan_null_MentionSpan-Night-18_20_null,NEXUS_5,1.0,en]",0,],
-["ui_S_t[f.messages.impl.mentions_MentionSuggestionsPickerView_null_MentionSuggestionsPickerView-Day-3_3_null,NEXUS_5,1.0,en]","ui_S_t[f.messages.impl.mentions_MentionSuggestionsPickerView_null_MentionSuggestionsPickerView-Night-3_4_null,NEXUS_5,1.0,en]",19846,],
+["ui_S_t[f.messages.impl.mentions_MentionSuggestionsPickerView_null_MentionSuggestionsPickerView-Day-3_3_null,NEXUS_5,1.0,en]","ui_S_t[f.messages.impl.mentions_MentionSuggestionsPickerView_null_MentionSuggestionsPickerView-Night-3_4_null,NEXUS_5,1.0,en]",19860,],
["ui_S_t[l.designsystem.theme.components.previews_Menu_null_Menus_Menu_0_null,NEXUS_5,1.0,en]","",0,],
["ui_S_t[f.messages.impl.messagecomposer_MessageComposerViewVoice_null_MessageComposerViewVoice-Day-6_6_null_0,NEXUS_5,1.0,en]","ui_S_t[f.messages.impl.messagecomposer_MessageComposerViewVoice_null_MessageComposerViewVoice-Night-6_7_null_0,NEXUS_5,1.0,en]",0,],
-["ui_S_t[f.messages.impl.messagecomposer_MessageComposerView_null_MessageComposerView-Day-5_5_null_0,NEXUS_5,1.0,en]","ui_S_t[f.messages.impl.messagecomposer_MessageComposerView_null_MessageComposerView-Night-5_6_null_0,NEXUS_5,1.0,en]",19846,],
+["ui_S_t[f.messages.impl.messagecomposer_MessageComposerView_null_MessageComposerView-Day-5_5_null_0,NEXUS_5,1.0,en]","ui_S_t[f.messages.impl.messagecomposer_MessageComposerView_null_MessageComposerView-Night-5_6_null_0,NEXUS_5,1.0,en]",19860,],
["ui_S_t[f.messages.impl.timeline.components_MessageEventBubble_null_MessageEventBubble-Day-10_10_null_0,NEXUS_5,1.0,en]","ui_S_t[f.messages.impl.timeline.components_MessageEventBubble_null_MessageEventBubble-Night-10_11_null_0,NEXUS_5,1.0,en]",0,],
["ui_S_t[f.messages.impl.timeline.components_MessageEventBubble_null_MessageEventBubble-Day-10_10_null_1,NEXUS_5,1.0,en]","ui_S_t[f.messages.impl.timeline.components_MessageEventBubble_null_MessageEventBubble-Night-10_11_null_1,NEXUS_5,1.0,en]",0,],
["ui_S_t[f.messages.impl.timeline.components_MessageEventBubble_null_MessageEventBubble-Day-10_10_null_10,NEXUS_5,1.0,en]","ui_S_t[f.messages.impl.timeline.components_MessageEventBubble_null_MessageEventBubble-Night-10_11_null_10,NEXUS_5,1.0,en]",0,],
@@ -410,48 +414,46 @@ export const screenshots = [
["ui_S_t[f.messages.impl.timeline.components_MessagesReactionButton_null_MessagesReactionButton-Day-12_12_null_1,NEXUS_5,1.0,en]","ui_S_t[f.messages.impl.timeline.components_MessagesReactionButton_null_MessagesReactionButton-Night-12_13_null_1,NEXUS_5,1.0,en]",0,],
["ui_S_t[f.messages.impl.timeline.components_MessagesReactionButton_null_MessagesReactionButton-Day-12_12_null_2,NEXUS_5,1.0,en]","ui_S_t[f.messages.impl.timeline.components_MessagesReactionButton_null_MessagesReactionButton-Night-12_13_null_2,NEXUS_5,1.0,en]",0,],
["ui_S_t[f.messages.impl.timeline.components_MessagesReactionButton_null_MessagesReactionButton-Day-12_12_null_3,NEXUS_5,1.0,en]","ui_S_t[f.messages.impl.timeline.components_MessagesReactionButton_null_MessagesReactionButton-Night-12_13_null_3,NEXUS_5,1.0,en]",0,],
-["ui_S_t[f.messages.impl.typing_MessagesViewWithTyping_null_MessagesViewWithTyping-Day-67_67_null_0,NEXUS_5,1.0,en]","ui_S_t[f.messages.impl.typing_MessagesViewWithTyping_null_MessagesViewWithTyping-Night-67_68_null_0,NEXUS_5,1.0,en]",19849,],
-["ui_S_t[f.messages.impl.typing_MessagesViewWithTyping_null_MessagesViewWithTyping-Day-67_67_null_1,NEXUS_5,1.0,en]","ui_S_t[f.messages.impl.typing_MessagesViewWithTyping_null_MessagesViewWithTyping-Night-67_68_null_1,NEXUS_5,1.0,en]",19849,],
+["ui_S_t[f.messages.impl.typing_MessagesViewWithTyping_null_MessagesViewWithTyping-Day-67_67_null_0,NEXUS_5,1.0,en]","ui_S_t[f.messages.impl.typing_MessagesViewWithTyping_null_MessagesViewWithTyping-Night-67_68_null_0,NEXUS_5,1.0,en]",19860,],
+["ui_S_t[f.messages.impl.typing_MessagesViewWithTyping_null_MessagesViewWithTyping-Day-67_67_null_1,NEXUS_5,1.0,en]","ui_S_t[f.messages.impl.typing_MessagesViewWithTyping_null_MessagesViewWithTyping-Night-67_68_null_1,NEXUS_5,1.0,en]",19860,],
["ui_S_t[f.messages.impl.typing_MessagesViewWithTyping_null_MessagesViewWithTyping-Day-67_67_null_2,NEXUS_5,1.0,en]","ui_S_t[f.messages.impl.typing_MessagesViewWithTyping_null_MessagesViewWithTyping-Night-67_68_null_2,NEXUS_5,1.0,en]",0,],
-["ui_S_t[f.messages.impl_MessagesView_null_MessagesView-Day-0_0_null_0,NEXUS_5,1.0,en]","ui_S_t[f.messages.impl_MessagesView_null_MessagesView-Night-0_1_null_0,NEXUS_5,1.0,en]",19846,],
+["ui_S_t[f.messages.impl_MessagesView_null_MessagesView-Day-0_0_null_0,NEXUS_5,1.0,en]","ui_S_t[f.messages.impl_MessagesView_null_MessagesView-Night-0_1_null_0,NEXUS_5,1.0,en]",19860,],
["ui_S_t[f.messages.impl_MessagesView_null_MessagesView-Day-0_0_null_1,NEXUS_5,1.0,en]","ui_S_t[f.messages.impl_MessagesView_null_MessagesView-Night-0_1_null_1,NEXUS_5,1.0,en]",0,],
-["ui_S_t[f.messages.impl_MessagesView_null_MessagesView-Day-0_0_null_10,NEXUS_5,1.0,en]","ui_S_t[f.messages.impl_MessagesView_null_MessagesView-Night-0_1_null_10,NEXUS_5,1.0,en]",19846,],
-["ui_S_t[f.messages.impl_MessagesView_null_MessagesView-Day-0_0_null_11,NEXUS_5,1.0,en]","ui_S_t[f.messages.impl_MessagesView_null_MessagesView-Night-0_1_null_11,NEXUS_5,1.0,en]",19846,],
-["ui_S_t[f.messages.impl_MessagesView_null_MessagesView-Day-0_0_null_12,NEXUS_5,1.0,en]","ui_S_t[f.messages.impl_MessagesView_null_MessagesView-Night-0_1_null_12,NEXUS_5,1.0,en]",19846,],
-["ui_S_t[f.messages.impl_MessagesView_null_MessagesView-Day-0_0_null_2,NEXUS_5,1.0,en]","ui_S_t[f.messages.impl_MessagesView_null_MessagesView-Night-0_1_null_2,NEXUS_5,1.0,en]",19846,],
-["ui_S_t[f.messages.impl_MessagesView_null_MessagesView-Day-0_0_null_3,NEXUS_5,1.0,en]","ui_S_t[f.messages.impl_MessagesView_null_MessagesView-Night-0_1_null_3,NEXUS_5,1.0,en]",19846,],
-["ui_S_t[f.messages.impl_MessagesView_null_MessagesView-Day-0_0_null_4,NEXUS_5,1.0,en]","ui_S_t[f.messages.impl_MessagesView_null_MessagesView-Night-0_1_null_4,NEXUS_5,1.0,en]",19846,],
-["ui_S_t[f.messages.impl_MessagesView_null_MessagesView-Day-0_0_null_5,NEXUS_5,1.0,en]","ui_S_t[f.messages.impl_MessagesView_null_MessagesView-Night-0_1_null_5,NEXUS_5,1.0,en]",19846,],
-["ui_S_t[f.messages.impl_MessagesView_null_MessagesView-Day-0_0_null_6,NEXUS_5,1.0,en]","ui_S_t[f.messages.impl_MessagesView_null_MessagesView-Night-0_1_null_6,NEXUS_5,1.0,en]",19846,],
-["ui_S_t[f.messages.impl_MessagesView_null_MessagesView-Day-0_0_null_7,NEXUS_5,1.0,en]","ui_S_t[f.messages.impl_MessagesView_null_MessagesView-Night-0_1_null_7,NEXUS_5,1.0,en]",19846,],
-["ui_S_t[f.messages.impl_MessagesView_null_MessagesView-Day-0_0_null_8,NEXUS_5,1.0,en]","ui_S_t[f.messages.impl_MessagesView_null_MessagesView-Night-0_1_null_8,NEXUS_5,1.0,en]",19846,],
-["ui_S_t[f.messages.impl_MessagesView_null_MessagesView-Day-0_0_null_9,NEXUS_5,1.0,en]","ui_S_t[f.messages.impl_MessagesView_null_MessagesView-Night-0_1_null_9,NEXUS_5,1.0,en]",19846,],
-["ui_S_t[f.roomlist.impl.migration_MigrationScreenView_null_MigrationScreenView-Day-9_10_null,NEXUS_5,1.0,en]","ui_S_t[f.roomlist.impl.migration_MigrationScreenView_null_MigrationScreenView-Night-9_11_null,NEXUS_5,1.0,en]",19846,],
+["ui_S_t[f.messages.impl_MessagesView_null_MessagesView-Day-0_0_null_10,NEXUS_5,1.0,en]","ui_S_t[f.messages.impl_MessagesView_null_MessagesView-Night-0_1_null_10,NEXUS_5,1.0,en]",19860,],
+["ui_S_t[f.messages.impl_MessagesView_null_MessagesView-Day-0_0_null_11,NEXUS_5,1.0,en]","ui_S_t[f.messages.impl_MessagesView_null_MessagesView-Night-0_1_null_11,NEXUS_5,1.0,en]",19860,],
+["ui_S_t[f.messages.impl_MessagesView_null_MessagesView-Day-0_0_null_12,NEXUS_5,1.0,en]","ui_S_t[f.messages.impl_MessagesView_null_MessagesView-Night-0_1_null_12,NEXUS_5,1.0,en]",19860,],
+["ui_S_t[f.messages.impl_MessagesView_null_MessagesView-Day-0_0_null_2,NEXUS_5,1.0,en]","ui_S_t[f.messages.impl_MessagesView_null_MessagesView-Night-0_1_null_2,NEXUS_5,1.0,en]",19860,],
+["ui_S_t[f.messages.impl_MessagesView_null_MessagesView-Day-0_0_null_3,NEXUS_5,1.0,en]","ui_S_t[f.messages.impl_MessagesView_null_MessagesView-Night-0_1_null_3,NEXUS_5,1.0,en]",19860,],
+["ui_S_t[f.messages.impl_MessagesView_null_MessagesView-Day-0_0_null_4,NEXUS_5,1.0,en]","ui_S_t[f.messages.impl_MessagesView_null_MessagesView-Night-0_1_null_4,NEXUS_5,1.0,en]",19860,],
+["ui_S_t[f.messages.impl_MessagesView_null_MessagesView-Day-0_0_null_5,NEXUS_5,1.0,en]","ui_S_t[f.messages.impl_MessagesView_null_MessagesView-Night-0_1_null_5,NEXUS_5,1.0,en]",19860,],
+["ui_S_t[f.messages.impl_MessagesView_null_MessagesView-Day-0_0_null_6,NEXUS_5,1.0,en]","ui_S_t[f.messages.impl_MessagesView_null_MessagesView-Night-0_1_null_6,NEXUS_5,1.0,en]",19860,],
+["ui_S_t[f.messages.impl_MessagesView_null_MessagesView-Day-0_0_null_7,NEXUS_5,1.0,en]","ui_S_t[f.messages.impl_MessagesView_null_MessagesView-Night-0_1_null_7,NEXUS_5,1.0,en]",19860,],
+["ui_S_t[f.messages.impl_MessagesView_null_MessagesView-Day-0_0_null_8,NEXUS_5,1.0,en]","ui_S_t[f.messages.impl_MessagesView_null_MessagesView-Night-0_1_null_8,NEXUS_5,1.0,en]",19860,],
+["ui_S_t[f.messages.impl_MessagesView_null_MessagesView-Day-0_0_null_9,NEXUS_5,1.0,en]","ui_S_t[f.messages.impl_MessagesView_null_MessagesView-Night-0_1_null_9,NEXUS_5,1.0,en]",19860,],
+["ui_S_t[f.roomlist.impl.migration_MigrationScreenView_null_MigrationScreenView-Day-9_10_null,NEXUS_5,1.0,en]","ui_S_t[f.roomlist.impl.migration_MigrationScreenView_null_MigrationScreenView-Night-9_11_null,NEXUS_5,1.0,en]",19860,],
["ui_S_t[f.migration.impl_MigrationView_null_MigrationView-Day-0_1_null_0,NEXUS_5,1.0,en]","ui_S_t[f.migration.impl_MigrationView_null_MigrationView-Night-0_2_null_0,NEXUS_5,1.0,en]",0,],
-["ui_S_t[f.migration.impl_MigrationView_null_MigrationView-Day-0_1_null_1,NEXUS_5,1.0,en]","ui_S_t[f.migration.impl_MigrationView_null_MigrationView-Night-0_2_null_1,NEXUS_5,1.0,en]",19846,],
+["ui_S_t[f.migration.impl_MigrationView_null_MigrationView-Day-0_1_null_1,NEXUS_5,1.0,en]","ui_S_t[f.migration.impl_MigrationView_null_MigrationView-Night-0_2_null_1,NEXUS_5,1.0,en]",19860,],
["ui_S_t[l.designsystem.theme.components_ModalBottomSheetDark_null_BottomSheets_ModalBottomSheetDark_0_null,NEXUS_5,1.0,en]","",0,],
-["ui_S_t[l.designsystem.theme.components_ModalBottomSheetLayoutDark_null_BottomSheets_ModalBottomSheetLayoutDark_0_null,NEXUS_5,1.0,en]","",0,],
-["ui_S_t[l.designsystem.theme.components_ModalBottomSheetLayoutLight_null_BottomSheets_ModalBottomSheetLayoutLight_0_null,NEXUS_5,1.0,en]","",0,],
["ui_S_t[l.designsystem.theme.components_ModalBottomSheetLight_null_BottomSheets_ModalBottomSheetLight_0_null,NEXUS_5,1.0,en]","",0,],
["ui_S_t[l.designsystem.components.dialogs_MultipleSelectionDialogContent_null_Dialogs_MultipleSelectionDialogContent_0_null,NEXUS_5,1.0,en]","",0,],
["ui_S_t[l.designsystem.components.dialogs_MultipleSelectionDialog_null_MultipleSelectionDialog-Day_0_null,NEXUS_5,1.0,en]","ui_S_t[l.designsystem.components.dialogs_MultipleSelectionDialog_null_MultipleSelectionDialog-Night_1_null,NEXUS_5,1.0,en]",0,],
["ui_S_t[l.designsystem.components.list_MutipleSelectionListItemSelectedTrailingContent_null_Listitems_MultipleselectionListitem-selectionintrailingcontent_0_null,NEXUS_5,1.0,en]","",0,],
["ui_S_t[l.designsystem.components.list_MutipleSelectionListItemSelected_null_Listitems_MultipleselectionListitem-selectioninsupportingtext_0_null,NEXUS_5,1.0,en]","",0,],
["ui_S_t[l.designsystem.components.list_MutipleSelectionListItem_null_Listitems_MultipleselectionListitem-noselection_0_null,NEXUS_5,1.0,en]","",0,],
-["ui_S_t[f.preferences.impl.notifications_NotificationSettingsView_null_NotificationSettingsView-Day-6_7_null_0,NEXUS_5,1.0,en]","ui_S_t[f.preferences.impl.notifications_NotificationSettingsView_null_NotificationSettingsView-Night-6_8_null_0,NEXUS_5,1.0,en]",19846,],
-["ui_S_t[f.preferences.impl.notifications_NotificationSettingsView_null_NotificationSettingsView-Day-6_7_null_1,NEXUS_5,1.0,en]","ui_S_t[f.preferences.impl.notifications_NotificationSettingsView_null_NotificationSettingsView-Night-6_8_null_1,NEXUS_5,1.0,en]",19846,],
-["ui_S_t[f.preferences.impl.notifications_NotificationSettingsView_null_NotificationSettingsView-Day-6_7_null_2,NEXUS_5,1.0,en]","ui_S_t[f.preferences.impl.notifications_NotificationSettingsView_null_NotificationSettingsView-Night-6_8_null_2,NEXUS_5,1.0,en]",19846,],
-["ui_S_t[f.preferences.impl.notifications_NotificationSettingsView_null_NotificationSettingsView-Day-6_7_null_3,NEXUS_5,1.0,en]","ui_S_t[f.preferences.impl.notifications_NotificationSettingsView_null_NotificationSettingsView-Night-6_8_null_3,NEXUS_5,1.0,en]",19846,],
-["ui_S_t[f.preferences.impl.notifications_NotificationSettingsView_null_NotificationSettingsView-Day-6_7_null_4,NEXUS_5,1.0,en]","ui_S_t[f.preferences.impl.notifications_NotificationSettingsView_null_NotificationSettingsView-Night-6_8_null_4,NEXUS_5,1.0,en]",19846,],
-["ui_S_t[f.ftue.impl.notifications_NotificationsOptInView_null_NotificationsOptInView-Day-0_1_null_0,NEXUS_5,1.0,en]","ui_S_t[f.ftue.impl.notifications_NotificationsOptInView_null_NotificationsOptInView-Night-0_2_null_0,NEXUS_5,1.0,en]",19846,],
+["ui_S_t[f.preferences.impl.notifications_NotificationSettingsView_null_NotificationSettingsView-Day-6_7_null_0,NEXUS_5,1.0,en]","ui_S_t[f.preferences.impl.notifications_NotificationSettingsView_null_NotificationSettingsView-Night-6_8_null_0,NEXUS_5,1.0,en]",19860,],
+["ui_S_t[f.preferences.impl.notifications_NotificationSettingsView_null_NotificationSettingsView-Day-6_7_null_1,NEXUS_5,1.0,en]","ui_S_t[f.preferences.impl.notifications_NotificationSettingsView_null_NotificationSettingsView-Night-6_8_null_1,NEXUS_5,1.0,en]",19860,],
+["ui_S_t[f.preferences.impl.notifications_NotificationSettingsView_null_NotificationSettingsView-Day-6_7_null_2,NEXUS_5,1.0,en]","ui_S_t[f.preferences.impl.notifications_NotificationSettingsView_null_NotificationSettingsView-Night-6_8_null_2,NEXUS_5,1.0,en]",19860,],
+["ui_S_t[f.preferences.impl.notifications_NotificationSettingsView_null_NotificationSettingsView-Day-6_7_null_3,NEXUS_5,1.0,en]","ui_S_t[f.preferences.impl.notifications_NotificationSettingsView_null_NotificationSettingsView-Night-6_8_null_3,NEXUS_5,1.0,en]",19860,],
+["ui_S_t[f.preferences.impl.notifications_NotificationSettingsView_null_NotificationSettingsView-Day-6_7_null_4,NEXUS_5,1.0,en]","ui_S_t[f.preferences.impl.notifications_NotificationSettingsView_null_NotificationSettingsView-Night-6_8_null_4,NEXUS_5,1.0,en]",19860,],
+["ui_S_t[f.ftue.impl.notifications_NotificationsOptInView_null_NotificationsOptInView-Day-0_1_null_0,NEXUS_5,1.0,en]","ui_S_t[f.ftue.impl.notifications_NotificationsOptInView_null_NotificationsOptInView-Night-0_2_null_0,NEXUS_5,1.0,en]",19860,],
["ui_S_t[f.login.impl.oidc.webview_OidcView_null_OidcView-Day-3_4_null_0,NEXUS_5,1.0,en]","ui_S_t[f.login.impl.oidc.webview_OidcView_null_OidcView-Night-3_5_null_0,NEXUS_5,1.0,en]",0,],
["ui_S_t[f.login.impl.oidc.webview_OidcView_null_OidcView-Day-3_4_null_1,NEXUS_5,1.0,en]","ui_S_t[f.login.impl.oidc.webview_OidcView_null_OidcView-Night-3_5_null_1,NEXUS_5,1.0,en]",0,],
["ui_S_t[l.designsystem.atomic.pages_OnBoardingPage_null_OnBoardingPage-Day_0_null,NEXUS_5,1.0,en]","ui_S_t[l.designsystem.atomic.pages_OnBoardingPage_null_OnBoardingPage-Night_1_null,NEXUS_5,1.0,en]",0,],
-["ui_S_t[f.onboarding.impl_OnBoardingView_null_OnBoardingView-Day-0_1_null_0,NEXUS_5,1.0,en]","ui_S_t[f.onboarding.impl_OnBoardingView_null_OnBoardingView-Night-0_2_null_0,NEXUS_5,1.0,en]",19846,],
-["ui_S_t[f.onboarding.impl_OnBoardingView_null_OnBoardingView-Day-0_1_null_1,NEXUS_5,1.0,en]","ui_S_t[f.onboarding.impl_OnBoardingView_null_OnBoardingView-Night-0_2_null_1,NEXUS_5,1.0,en]",19846,],
-["ui_S_t[f.onboarding.impl_OnBoardingView_null_OnBoardingView-Day-0_1_null_2,NEXUS_5,1.0,en]","ui_S_t[f.onboarding.impl_OnBoardingView_null_OnBoardingView-Night-0_2_null_2,NEXUS_5,1.0,en]",19846,],
-["ui_S_t[f.onboarding.impl_OnBoardingView_null_OnBoardingView-Day-0_1_null_3,NEXUS_5,1.0,en]","ui_S_t[f.onboarding.impl_OnBoardingView_null_OnBoardingView-Night-0_2_null_3,NEXUS_5,1.0,en]",19846,],
-["ui_S_t[f.onboarding.impl_OnBoardingView_null_OnBoardingView-Day-0_1_null_4,NEXUS_5,1.0,en]","ui_S_t[f.onboarding.impl_OnBoardingView_null_OnBoardingView-Night-0_2_null_4,NEXUS_5,1.0,en]",19846,],
+["ui_S_t[f.onboarding.impl_OnBoardingView_null_OnBoardingView-Day-0_1_null_0,NEXUS_5,1.0,en]","ui_S_t[f.onboarding.impl_OnBoardingView_null_OnBoardingView-Night-0_2_null_0,NEXUS_5,1.0,en]",19860,],
+["ui_S_t[f.onboarding.impl_OnBoardingView_null_OnBoardingView-Day-0_1_null_1,NEXUS_5,1.0,en]","ui_S_t[f.onboarding.impl_OnBoardingView_null_OnBoardingView-Night-0_2_null_1,NEXUS_5,1.0,en]",19860,],
+["ui_S_t[f.onboarding.impl_OnBoardingView_null_OnBoardingView-Day-0_1_null_2,NEXUS_5,1.0,en]","ui_S_t[f.onboarding.impl_OnBoardingView_null_OnBoardingView-Night-0_2_null_2,NEXUS_5,1.0,en]",19860,],
+["ui_S_t[f.onboarding.impl_OnBoardingView_null_OnBoardingView-Day-0_1_null_3,NEXUS_5,1.0,en]","ui_S_t[f.onboarding.impl_OnBoardingView_null_OnBoardingView-Night-0_2_null_3,NEXUS_5,1.0,en]",19860,],
+["ui_S_t[f.onboarding.impl_OnBoardingView_null_OnBoardingView-Day-0_1_null_4,NEXUS_5,1.0,en]","ui_S_t[f.onboarding.impl_OnBoardingView_null_OnBoardingView-Night-0_2_null_4,NEXUS_5,1.0,en]",19860,],
["ui_S_t[l.designsystem.background_OnboardingBackground_null_OnboardingBackground-Day_0_null,NEXUS_5,1.0,en]","ui_S_t[l.designsystem.background_OnboardingBackground_null_OnboardingBackground-Night_1_null,NEXUS_5,1.0,en]",0,],
["ui_S_t[l.designsystem.theme.components_OutlinedButtonLarge_null_Buttons_OutlinedButtonLarge_0_null,NEXUS_5,1.0,en]","",0,],
["ui_S_t[l.designsystem.theme.components_OutlinedButtonMedium_null_Buttons_OutlinedButtonMedium_0_null,NEXUS_5,1.0,en]","",0,],
@@ -464,47 +466,47 @@ export const screenshots = [
["ui_S_t[l.designsystem.components_PageTitleWithIconFull_null_PageTitleWithIconFull-Day_0_null_3,NEXUS_5,1.0,en]","ui_S_t[l.designsystem.components_PageTitleWithIconFull_null_PageTitleWithIconFull-Night_1_null_3,NEXUS_5,1.0,en]",0,],
["ui_S_t[l.designsystem.components_PageTitleWithIconFull_null_PageTitleWithIconFull-Day_0_null_4,NEXUS_5,1.0,en]","ui_S_t[l.designsystem.components_PageTitleWithIconFull_null_PageTitleWithIconFull-Night_1_null_4,NEXUS_5,1.0,en]",0,],
["ui_S_t[l.designsystem.components_PageTitleWithIconMinimal_null_PageTitleWithIconMinimal-Day_0_null,NEXUS_5,1.0,en]","ui_S_t[l.designsystem.components_PageTitleWithIconMinimal_null_PageTitleWithIconMinimal-Night_1_null,NEXUS_5,1.0,en]",0,],
-["ui_S_t[f.roomdetails.impl.rolesandpermissions.changeroles_PendingMemberRowWithLongName_null_PendingMemberRowWithLongName-Day-10_10_null,NEXUS_5,1.0,en]","ui_S_t[f.roomdetails.impl.rolesandpermissions.changeroles_PendingMemberRowWithLongName_null_PendingMemberRowWithLongName-Night-10_11_null,NEXUS_5,1.0,en]",19849,],
-["ui_S_t[l.permissions.api_PermissionsView_null_PermissionsView-Day-0_1_null_0,NEXUS_5,1.0,en]","ui_S_t[l.permissions.api_PermissionsView_null_PermissionsView-Night-0_2_null_0,NEXUS_5,1.0,en]",19846,],
-["ui_S_t[l.permissions.api_PermissionsView_null_PermissionsView-Day-0_1_null_1,NEXUS_5,1.0,en]","ui_S_t[l.permissions.api_PermissionsView_null_PermissionsView-Night-0_2_null_1,NEXUS_5,1.0,en]",19846,],
-["ui_S_t[l.permissions.api_PermissionsView_null_PermissionsView-Day-0_1_null_2,NEXUS_5,1.0,en]","ui_S_t[l.permissions.api_PermissionsView_null_PermissionsView-Night-0_2_null_2,NEXUS_5,1.0,en]",19846,],
-["ui_S_t[l.permissions.api_PermissionsView_null_PermissionsView-Day-0_1_null_3,NEXUS_5,1.0,en]","ui_S_t[l.permissions.api_PermissionsView_null_PermissionsView-Night-0_2_null_3,NEXUS_5,1.0,en]",19846,],
+["ui_S_t[f.roomdetails.impl.rolesandpermissions.changeroles_PendingMemberRowWithLongName_null_PendingMemberRowWithLongName-Day-13_13_null,NEXUS_5,1.0,en]","ui_S_t[f.roomdetails.impl.rolesandpermissions.changeroles_PendingMemberRowWithLongName_null_PendingMemberRowWithLongName-Night-13_14_null,NEXUS_5,1.0,en]",19860,],
+["ui_S_t[l.permissions.api_PermissionsView_null_PermissionsView-Day-0_1_null_0,NEXUS_5,1.0,en]","ui_S_t[l.permissions.api_PermissionsView_null_PermissionsView-Night-0_2_null_0,NEXUS_5,1.0,en]",19860,],
+["ui_S_t[l.permissions.api_PermissionsView_null_PermissionsView-Day-0_1_null_1,NEXUS_5,1.0,en]","ui_S_t[l.permissions.api_PermissionsView_null_PermissionsView-Night-0_2_null_1,NEXUS_5,1.0,en]",19860,],
+["ui_S_t[l.permissions.api_PermissionsView_null_PermissionsView-Day-0_1_null_2,NEXUS_5,1.0,en]","ui_S_t[l.permissions.api_PermissionsView_null_PermissionsView-Night-0_2_null_2,NEXUS_5,1.0,en]",19860,],
+["ui_S_t[l.permissions.api_PermissionsView_null_PermissionsView-Day-0_1_null_3,NEXUS_5,1.0,en]","ui_S_t[l.permissions.api_PermissionsView_null_PermissionsView-Night-0_2_null_3,NEXUS_5,1.0,en]",19860,],
["ui_S_t[f.lockscreen.impl.components_PinEntryTextField_null_PinEntryTextField-Day-0_1_null,NEXUS_5,1.0,en]","ui_S_t[f.lockscreen.impl.components_PinEntryTextField_null_PinEntryTextField-Night-0_2_null,NEXUS_5,1.0,en]",0,],
["ui_S_t[l.designsystem.components_PinIcon_null_PinIcon-Day_0_null,NEXUS_5,1.0,en]","ui_S_t[l.designsystem.components_PinIcon_null_PinIcon-Night_1_null,NEXUS_5,1.0,en]",0,],
["ui_S_t[f.lockscreen.impl.unlock.keypad_PinKeypad_null_PinKeypad-Day-6_7_null,NEXUS_5,1.0,en]","ui_S_t[f.lockscreen.impl.unlock.keypad_PinKeypad_null_PinKeypad-Night-6_8_null,NEXUS_5,1.0,en]",0,],
-["ui_S_t[f.lockscreen.impl.unlock_PinUnlockViewInApp_null_PinUnlockViewInApp-Day-4_5_null_0,NEXUS_5,1.0,en]","ui_S_t[f.lockscreen.impl.unlock_PinUnlockViewInApp_null_PinUnlockViewInApp-Night-4_6_null_0,NEXUS_5,1.0,en]",19846,],
-["ui_S_t[f.lockscreen.impl.unlock_PinUnlockViewInApp_null_PinUnlockViewInApp-Day-4_5_null_1,NEXUS_5,1.0,en]","ui_S_t[f.lockscreen.impl.unlock_PinUnlockViewInApp_null_PinUnlockViewInApp-Night-4_6_null_1,NEXUS_5,1.0,en]",19846,],
-["ui_S_t[f.lockscreen.impl.unlock_PinUnlockViewInApp_null_PinUnlockViewInApp-Day-4_5_null_2,NEXUS_5,1.0,en]","ui_S_t[f.lockscreen.impl.unlock_PinUnlockViewInApp_null_PinUnlockViewInApp-Night-4_6_null_2,NEXUS_5,1.0,en]",19846,],
-["ui_S_t[f.lockscreen.impl.unlock_PinUnlockViewInApp_null_PinUnlockViewInApp-Day-4_5_null_3,NEXUS_5,1.0,en]","ui_S_t[f.lockscreen.impl.unlock_PinUnlockViewInApp_null_PinUnlockViewInApp-Night-4_6_null_3,NEXUS_5,1.0,en]",19846,],
-["ui_S_t[f.lockscreen.impl.unlock_PinUnlockViewInApp_null_PinUnlockViewInApp-Day-4_5_null_4,NEXUS_5,1.0,en]","ui_S_t[f.lockscreen.impl.unlock_PinUnlockViewInApp_null_PinUnlockViewInApp-Night-4_6_null_4,NEXUS_5,1.0,en]",19846,],
-["ui_S_t[f.lockscreen.impl.unlock_PinUnlockViewInApp_null_PinUnlockViewInApp-Day-4_5_null_5,NEXUS_5,1.0,en]","ui_S_t[f.lockscreen.impl.unlock_PinUnlockViewInApp_null_PinUnlockViewInApp-Night-4_6_null_5,NEXUS_5,1.0,en]",19846,],
-["ui_S_t[f.lockscreen.impl.unlock_PinUnlockViewInApp_null_PinUnlockViewInApp-Day-4_5_null_6,NEXUS_5,1.0,en]","ui_S_t[f.lockscreen.impl.unlock_PinUnlockViewInApp_null_PinUnlockViewInApp-Night-4_6_null_6,NEXUS_5,1.0,en]",19846,],
-["ui_S_t[f.lockscreen.impl.unlock_PinUnlockView_null_PinUnlockView-Day-5_6_null_0,NEXUS_5,1.0,en]","ui_S_t[f.lockscreen.impl.unlock_PinUnlockView_null_PinUnlockView-Night-5_7_null_0,NEXUS_5,1.0,en]",19846,],
-["ui_S_t[f.lockscreen.impl.unlock_PinUnlockView_null_PinUnlockView-Day-5_6_null_1,NEXUS_5,1.0,en]","ui_S_t[f.lockscreen.impl.unlock_PinUnlockView_null_PinUnlockView-Night-5_7_null_1,NEXUS_5,1.0,en]",19846,],
-["ui_S_t[f.lockscreen.impl.unlock_PinUnlockView_null_PinUnlockView-Day-5_6_null_2,NEXUS_5,1.0,en]","ui_S_t[f.lockscreen.impl.unlock_PinUnlockView_null_PinUnlockView-Night-5_7_null_2,NEXUS_5,1.0,en]",19846,],
-["ui_S_t[f.lockscreen.impl.unlock_PinUnlockView_null_PinUnlockView-Day-5_6_null_3,NEXUS_5,1.0,en]","ui_S_t[f.lockscreen.impl.unlock_PinUnlockView_null_PinUnlockView-Night-5_7_null_3,NEXUS_5,1.0,en]",19846,],
-["ui_S_t[f.lockscreen.impl.unlock_PinUnlockView_null_PinUnlockView-Day-5_6_null_4,NEXUS_5,1.0,en]","ui_S_t[f.lockscreen.impl.unlock_PinUnlockView_null_PinUnlockView-Night-5_7_null_4,NEXUS_5,1.0,en]",19846,],
-["ui_S_t[f.lockscreen.impl.unlock_PinUnlockView_null_PinUnlockView-Day-5_6_null_5,NEXUS_5,1.0,en]","ui_S_t[f.lockscreen.impl.unlock_PinUnlockView_null_PinUnlockView-Night-5_7_null_5,NEXUS_5,1.0,en]",19846,],
-["ui_S_t[f.lockscreen.impl.unlock_PinUnlockView_null_PinUnlockView-Day-5_6_null_6,NEXUS_5,1.0,en]","ui_S_t[f.lockscreen.impl.unlock_PinUnlockView_null_PinUnlockView-Night-5_7_null_6,NEXUS_5,1.0,en]",19846,],
+["ui_S_t[f.lockscreen.impl.unlock_PinUnlockViewInApp_null_PinUnlockViewInApp-Day-4_5_null_0,NEXUS_5,1.0,en]","ui_S_t[f.lockscreen.impl.unlock_PinUnlockViewInApp_null_PinUnlockViewInApp-Night-4_6_null_0,NEXUS_5,1.0,en]",19860,],
+["ui_S_t[f.lockscreen.impl.unlock_PinUnlockViewInApp_null_PinUnlockViewInApp-Day-4_5_null_1,NEXUS_5,1.0,en]","ui_S_t[f.lockscreen.impl.unlock_PinUnlockViewInApp_null_PinUnlockViewInApp-Night-4_6_null_1,NEXUS_5,1.0,en]",19860,],
+["ui_S_t[f.lockscreen.impl.unlock_PinUnlockViewInApp_null_PinUnlockViewInApp-Day-4_5_null_2,NEXUS_5,1.0,en]","ui_S_t[f.lockscreen.impl.unlock_PinUnlockViewInApp_null_PinUnlockViewInApp-Night-4_6_null_2,NEXUS_5,1.0,en]",19860,],
+["ui_S_t[f.lockscreen.impl.unlock_PinUnlockViewInApp_null_PinUnlockViewInApp-Day-4_5_null_3,NEXUS_5,1.0,en]","ui_S_t[f.lockscreen.impl.unlock_PinUnlockViewInApp_null_PinUnlockViewInApp-Night-4_6_null_3,NEXUS_5,1.0,en]",19860,],
+["ui_S_t[f.lockscreen.impl.unlock_PinUnlockViewInApp_null_PinUnlockViewInApp-Day-4_5_null_4,NEXUS_5,1.0,en]","ui_S_t[f.lockscreen.impl.unlock_PinUnlockViewInApp_null_PinUnlockViewInApp-Night-4_6_null_4,NEXUS_5,1.0,en]",19860,],
+["ui_S_t[f.lockscreen.impl.unlock_PinUnlockViewInApp_null_PinUnlockViewInApp-Day-4_5_null_5,NEXUS_5,1.0,en]","ui_S_t[f.lockscreen.impl.unlock_PinUnlockViewInApp_null_PinUnlockViewInApp-Night-4_6_null_5,NEXUS_5,1.0,en]",19860,],
+["ui_S_t[f.lockscreen.impl.unlock_PinUnlockViewInApp_null_PinUnlockViewInApp-Day-4_5_null_6,NEXUS_5,1.0,en]","ui_S_t[f.lockscreen.impl.unlock_PinUnlockViewInApp_null_PinUnlockViewInApp-Night-4_6_null_6,NEXUS_5,1.0,en]",19860,],
+["ui_S_t[f.lockscreen.impl.unlock_PinUnlockView_null_PinUnlockView-Day-5_6_null_0,NEXUS_5,1.0,en]","ui_S_t[f.lockscreen.impl.unlock_PinUnlockView_null_PinUnlockView-Night-5_7_null_0,NEXUS_5,1.0,en]",19860,],
+["ui_S_t[f.lockscreen.impl.unlock_PinUnlockView_null_PinUnlockView-Day-5_6_null_1,NEXUS_5,1.0,en]","ui_S_t[f.lockscreen.impl.unlock_PinUnlockView_null_PinUnlockView-Night-5_7_null_1,NEXUS_5,1.0,en]",19860,],
+["ui_S_t[f.lockscreen.impl.unlock_PinUnlockView_null_PinUnlockView-Day-5_6_null_2,NEXUS_5,1.0,en]","ui_S_t[f.lockscreen.impl.unlock_PinUnlockView_null_PinUnlockView-Night-5_7_null_2,NEXUS_5,1.0,en]",19860,],
+["ui_S_t[f.lockscreen.impl.unlock_PinUnlockView_null_PinUnlockView-Day-5_6_null_3,NEXUS_5,1.0,en]","ui_S_t[f.lockscreen.impl.unlock_PinUnlockView_null_PinUnlockView-Night-5_7_null_3,NEXUS_5,1.0,en]",19860,],
+["ui_S_t[f.lockscreen.impl.unlock_PinUnlockView_null_PinUnlockView-Day-5_6_null_4,NEXUS_5,1.0,en]","ui_S_t[f.lockscreen.impl.unlock_PinUnlockView_null_PinUnlockView-Night-5_7_null_4,NEXUS_5,1.0,en]",19860,],
+["ui_S_t[f.lockscreen.impl.unlock_PinUnlockView_null_PinUnlockView-Day-5_6_null_5,NEXUS_5,1.0,en]","ui_S_t[f.lockscreen.impl.unlock_PinUnlockView_null_PinUnlockView-Night-5_7_null_5,NEXUS_5,1.0,en]",19860,],
+["ui_S_t[f.lockscreen.impl.unlock_PinUnlockView_null_PinUnlockView-Day-5_6_null_6,NEXUS_5,1.0,en]","ui_S_t[f.lockscreen.impl.unlock_PinUnlockView_null_PinUnlockView-Night-5_7_null_6,NEXUS_5,1.0,en]",19860,],
["ui_S_t[l.designsystem.atomic.atoms_PlaceholderAtom_null_PlaceholderAtom-Day_0_null,NEXUS_5,1.0,en]","ui_S_t[l.designsystem.atomic.atoms_PlaceholderAtom_null_PlaceholderAtom-Night_1_null,NEXUS_5,1.0,en]",0,],
-["ui_S_t[f.poll.api.pollcontent_PollAnswerViewDisclosedNotSelected_null_PollAnswerViewDisclosedNotSelected-Day-0_1_null,NEXUS_5,1.0,en]","ui_S_t[f.poll.api.pollcontent_PollAnswerViewDisclosedNotSelected_null_PollAnswerViewDisclosedNotSelected-Night-0_2_null,NEXUS_5,1.0,en]",19846,],
-["ui_S_t[f.poll.api.pollcontent_PollAnswerViewDisclosedSelected_null_PollAnswerViewDisclosedSelected-Day-1_2_null,NEXUS_5,1.0,en]","ui_S_t[f.poll.api.pollcontent_PollAnswerViewDisclosedSelected_null_PollAnswerViewDisclosedSelected-Night-1_3_null,NEXUS_5,1.0,en]",19846,],
-["ui_S_t[f.poll.api.pollcontent_PollAnswerViewEndedSelected_null_PollAnswerViewEndedSelected-Day-6_7_null,NEXUS_5,1.0,en]","ui_S_t[f.poll.api.pollcontent_PollAnswerViewEndedSelected_null_PollAnswerViewEndedSelected-Night-6_8_null,NEXUS_5,1.0,en]",19846,],
-["ui_S_t[f.poll.api.pollcontent_PollAnswerViewEndedWinnerNotSelected_null_PollAnswerViewEndedWinnerNotSelected-Day-4_5_null,NEXUS_5,1.0,en]","ui_S_t[f.poll.api.pollcontent_PollAnswerViewEndedWinnerNotSelected_null_PollAnswerViewEndedWinnerNotSelected-Night-4_6_null,NEXUS_5,1.0,en]",19846,],
-["ui_S_t[f.poll.api.pollcontent_PollAnswerViewEndedWinnerSelected_null_PollAnswerViewEndedWinnerSelected-Day-5_6_null,NEXUS_5,1.0,en]","ui_S_t[f.poll.api.pollcontent_PollAnswerViewEndedWinnerSelected_null_PollAnswerViewEndedWinnerSelected-Night-5_7_null,NEXUS_5,1.0,en]",19846,],
+["ui_S_t[f.poll.api.pollcontent_PollAnswerViewDisclosedNotSelected_null_PollAnswerViewDisclosedNotSelected-Day-0_1_null,NEXUS_5,1.0,en]","ui_S_t[f.poll.api.pollcontent_PollAnswerViewDisclosedNotSelected_null_PollAnswerViewDisclosedNotSelected-Night-0_2_null,NEXUS_5,1.0,en]",19860,],
+["ui_S_t[f.poll.api.pollcontent_PollAnswerViewDisclosedSelected_null_PollAnswerViewDisclosedSelected-Day-1_2_null,NEXUS_5,1.0,en]","ui_S_t[f.poll.api.pollcontent_PollAnswerViewDisclosedSelected_null_PollAnswerViewDisclosedSelected-Night-1_3_null,NEXUS_5,1.0,en]",19860,],
+["ui_S_t[f.poll.api.pollcontent_PollAnswerViewEndedSelected_null_PollAnswerViewEndedSelected-Day-6_7_null,NEXUS_5,1.0,en]","ui_S_t[f.poll.api.pollcontent_PollAnswerViewEndedSelected_null_PollAnswerViewEndedSelected-Night-6_8_null,NEXUS_5,1.0,en]",19860,],
+["ui_S_t[f.poll.api.pollcontent_PollAnswerViewEndedWinnerNotSelected_null_PollAnswerViewEndedWinnerNotSelected-Day-4_5_null,NEXUS_5,1.0,en]","ui_S_t[f.poll.api.pollcontent_PollAnswerViewEndedWinnerNotSelected_null_PollAnswerViewEndedWinnerNotSelected-Night-4_6_null,NEXUS_5,1.0,en]",19860,],
+["ui_S_t[f.poll.api.pollcontent_PollAnswerViewEndedWinnerSelected_null_PollAnswerViewEndedWinnerSelected-Day-5_6_null,NEXUS_5,1.0,en]","ui_S_t[f.poll.api.pollcontent_PollAnswerViewEndedWinnerSelected_null_PollAnswerViewEndedWinnerSelected-Night-5_7_null,NEXUS_5,1.0,en]",19860,],
["ui_S_t[f.poll.api.pollcontent_PollAnswerViewUndisclosedNotSelected_null_PollAnswerViewUndisclosedNotSelected-Day-2_3_null,NEXUS_5,1.0,en]","ui_S_t[f.poll.api.pollcontent_PollAnswerViewUndisclosedNotSelected_null_PollAnswerViewUndisclosedNotSelected-Night-2_4_null,NEXUS_5,1.0,en]",0,],
["ui_S_t[f.poll.api.pollcontent_PollAnswerViewUndisclosedSelected_null_PollAnswerViewUndisclosedSelected-Day-3_4_null,NEXUS_5,1.0,en]","ui_S_t[f.poll.api.pollcontent_PollAnswerViewUndisclosedSelected_null_PollAnswerViewUndisclosedSelected-Night-3_5_null,NEXUS_5,1.0,en]",0,],
-["ui_S_t[f.poll.api.pollcontent_PollContentViewCreatorEditable_null_PollContentViewCreatorEditable-Day-10_11_null,NEXUS_5,1.0,en]","ui_S_t[f.poll.api.pollcontent_PollContentViewCreatorEditable_null_PollContentViewCreatorEditable-Night-10_12_null,NEXUS_5,1.0,en]",19846,],
-["ui_S_t[f.poll.api.pollcontent_PollContentViewCreatorEnded_null_PollContentViewCreatorEnded-Day-12_13_null,NEXUS_5,1.0,en]","ui_S_t[f.poll.api.pollcontent_PollContentViewCreatorEnded_null_PollContentViewCreatorEnded-Night-12_14_null,NEXUS_5,1.0,en]",19846,],
-["ui_S_t[f.poll.api.pollcontent_PollContentViewCreator_null_PollContentViewCreator-Day-11_12_null,NEXUS_5,1.0,en]","ui_S_t[f.poll.api.pollcontent_PollContentViewCreator_null_PollContentViewCreator-Night-11_13_null,NEXUS_5,1.0,en]",19846,],
-["ui_S_t[f.poll.api.pollcontent_PollContentViewDisclosed_null_PollContentViewDisclosed-Day-8_9_null,NEXUS_5,1.0,en]","ui_S_t[f.poll.api.pollcontent_PollContentViewDisclosed_null_PollContentViewDisclosed-Night-8_10_null,NEXUS_5,1.0,en]",19846,],
-["ui_S_t[f.poll.api.pollcontent_PollContentViewEnded_null_PollContentViewEnded-Day-9_10_null,NEXUS_5,1.0,en]","ui_S_t[f.poll.api.pollcontent_PollContentViewEnded_null_PollContentViewEnded-Night-9_11_null,NEXUS_5,1.0,en]",19846,],
-["ui_S_t[f.poll.api.pollcontent_PollContentViewUndisclosed_null_PollContentViewUndisclosed-Day-7_8_null,NEXUS_5,1.0,en]","ui_S_t[f.poll.api.pollcontent_PollContentViewUndisclosed_null_PollContentViewUndisclosed-Night-7_9_null,NEXUS_5,1.0,en]",19846,],
-["ui_S_t[f.poll.impl.history_PollHistoryView_null_PollHistoryView-Day-1_2_null_0,NEXUS_5,1.0,en]","ui_S_t[f.poll.impl.history_PollHistoryView_null_PollHistoryView-Night-1_3_null_0,NEXUS_5,1.0,en]",19846,],
-["ui_S_t[f.poll.impl.history_PollHistoryView_null_PollHistoryView-Day-1_2_null_1,NEXUS_5,1.0,en]","ui_S_t[f.poll.impl.history_PollHistoryView_null_PollHistoryView-Night-1_3_null_1,NEXUS_5,1.0,en]",19846,],
-["ui_S_t[f.poll.impl.history_PollHistoryView_null_PollHistoryView-Day-1_2_null_2,NEXUS_5,1.0,en]","ui_S_t[f.poll.impl.history_PollHistoryView_null_PollHistoryView-Night-1_3_null_2,NEXUS_5,1.0,en]",19846,],
-["ui_S_t[f.poll.impl.history_PollHistoryView_null_PollHistoryView-Day-1_2_null_3,NEXUS_5,1.0,en]","ui_S_t[f.poll.impl.history_PollHistoryView_null_PollHistoryView-Night-1_3_null_3,NEXUS_5,1.0,en]",19846,],
-["ui_S_t[f.poll.impl.history_PollHistoryView_null_PollHistoryView-Day-1_2_null_4,NEXUS_5,1.0,en]","ui_S_t[f.poll.impl.history_PollHistoryView_null_PollHistoryView-Night-1_3_null_4,NEXUS_5,1.0,en]",19846,],
+["ui_S_t[f.poll.api.pollcontent_PollContentViewCreatorEditable_null_PollContentViewCreatorEditable-Day-10_11_null,NEXUS_5,1.0,en]","ui_S_t[f.poll.api.pollcontent_PollContentViewCreatorEditable_null_PollContentViewCreatorEditable-Night-10_12_null,NEXUS_5,1.0,en]",19860,],
+["ui_S_t[f.poll.api.pollcontent_PollContentViewCreatorEnded_null_PollContentViewCreatorEnded-Day-12_13_null,NEXUS_5,1.0,en]","ui_S_t[f.poll.api.pollcontent_PollContentViewCreatorEnded_null_PollContentViewCreatorEnded-Night-12_14_null,NEXUS_5,1.0,en]",19860,],
+["ui_S_t[f.poll.api.pollcontent_PollContentViewCreator_null_PollContentViewCreator-Day-11_12_null,NEXUS_5,1.0,en]","ui_S_t[f.poll.api.pollcontent_PollContentViewCreator_null_PollContentViewCreator-Night-11_13_null,NEXUS_5,1.0,en]",19860,],
+["ui_S_t[f.poll.api.pollcontent_PollContentViewDisclosed_null_PollContentViewDisclosed-Day-8_9_null,NEXUS_5,1.0,en]","ui_S_t[f.poll.api.pollcontent_PollContentViewDisclosed_null_PollContentViewDisclosed-Night-8_10_null,NEXUS_5,1.0,en]",19860,],
+["ui_S_t[f.poll.api.pollcontent_PollContentViewEnded_null_PollContentViewEnded-Day-9_10_null,NEXUS_5,1.0,en]","ui_S_t[f.poll.api.pollcontent_PollContentViewEnded_null_PollContentViewEnded-Night-9_11_null,NEXUS_5,1.0,en]",19860,],
+["ui_S_t[f.poll.api.pollcontent_PollContentViewUndisclosed_null_PollContentViewUndisclosed-Day-7_8_null,NEXUS_5,1.0,en]","ui_S_t[f.poll.api.pollcontent_PollContentViewUndisclosed_null_PollContentViewUndisclosed-Night-7_9_null,NEXUS_5,1.0,en]",19860,],
+["ui_S_t[f.poll.impl.history_PollHistoryView_null_PollHistoryView-Day-1_2_null_0,NEXUS_5,1.0,en]","ui_S_t[f.poll.impl.history_PollHistoryView_null_PollHistoryView-Night-1_3_null_0,NEXUS_5,1.0,en]",19860,],
+["ui_S_t[f.poll.impl.history_PollHistoryView_null_PollHistoryView-Day-1_2_null_1,NEXUS_5,1.0,en]","ui_S_t[f.poll.impl.history_PollHistoryView_null_PollHistoryView-Night-1_3_null_1,NEXUS_5,1.0,en]",19860,],
+["ui_S_t[f.poll.impl.history_PollHistoryView_null_PollHistoryView-Day-1_2_null_2,NEXUS_5,1.0,en]","ui_S_t[f.poll.impl.history_PollHistoryView_null_PollHistoryView-Night-1_3_null_2,NEXUS_5,1.0,en]",19860,],
+["ui_S_t[f.poll.impl.history_PollHistoryView_null_PollHistoryView-Day-1_2_null_3,NEXUS_5,1.0,en]","ui_S_t[f.poll.impl.history_PollHistoryView_null_PollHistoryView-Night-1_3_null_3,NEXUS_5,1.0,en]",19860,],
+["ui_S_t[f.poll.impl.history_PollHistoryView_null_PollHistoryView-Day-1_2_null_4,NEXUS_5,1.0,en]","ui_S_t[f.poll.impl.history_PollHistoryView_null_PollHistoryView-Night-1_3_null_4,NEXUS_5,1.0,en]",19860,],
["ui_S_t[l.designsystem.components.preferences_PreferenceCategory_null_Preferences_PreferenceCategory_0_null,NEXUS_5,1.0,en]","",0,],
["ui_S_t[l.designsystem.components.preferences_PreferenceCheckbox_null_Preferences_PreferenceCheckbox_0_null,NEXUS_5,1.0,en]","",0,],
["ui_S_t[l.designsystem.components.preferences_PreferenceDivider_null_Preferences_PreferenceDivider_0_null,NEXUS_5,1.0,en]","",0,],
@@ -520,158 +522,164 @@ export const screenshots = [
["ui_S_t[l.designsystem.components.preferences_PreferenceTextLight_null_Preferences_PreferenceTextLight_0_null,NEXUS_5,1.0,en]","",0,],
["ui_S_t[l.designsystem.components.preferences_PreferenceTextWithEndBadgeDark_null_Preferences_PreferenceTextWithEndBadgeDark_0_null,NEXUS_5,1.0,en]","",0,],
["ui_S_t[l.designsystem.components.preferences_PreferenceTextWithEndBadgeLight_null_Preferences_PreferenceTextWithEndBadgeLight_0_null,NEXUS_5,1.0,en]","",0,],
-["ui_S_t[f.preferences.impl.root_PreferencesRootViewDark_null_PreferencesRootViewDark--1_1_null_0,NEXUS_5,1.0,en]","",19846,],
-["ui_S_t[f.preferences.impl.root_PreferencesRootViewDark_null_PreferencesRootViewDark--1_1_null_1,NEXUS_5,1.0,en]","",19846,],
-["ui_S_t[f.preferences.impl.root_PreferencesRootViewLight_null_PreferencesRootViewLight--0_0_null_0,NEXUS_5,1.0,en]","",19846,],
-["ui_S_t[f.preferences.impl.root_PreferencesRootViewLight_null_PreferencesRootViewLight--0_0_null_1,NEXUS_5,1.0,en]","",19846,],
+["ui_S_t[f.preferences.impl.root_PreferencesRootViewDark_null_PreferencesRootViewDark--1_1_null_0,NEXUS_5,1.0,en]","",19860,],
+["ui_S_t[f.preferences.impl.root_PreferencesRootViewDark_null_PreferencesRootViewDark--1_1_null_1,NEXUS_5,1.0,en]","",19860,],
+["ui_S_t[f.preferences.impl.root_PreferencesRootViewLight_null_PreferencesRootViewLight--0_0_null_0,NEXUS_5,1.0,en]","",19860,],
+["ui_S_t[f.preferences.impl.root_PreferencesRootViewLight_null_PreferencesRootViewLight--0_0_null_1,NEXUS_5,1.0,en]","",19860,],
["ui_S_t[f.messages.impl.timeline.components.event_ProgressButton_null_ProgressButton-Day-54_54_null,NEXUS_5,1.0,en]","ui_S_t[f.messages.impl.timeline.components.event_ProgressButton_null_ProgressButton-Night-54_55_null,NEXUS_5,1.0,en]",0,],
-["ui_S_t[l.designsystem.components_ProgressDialogContent_null_Dialogs_ProgressDialogContent_0_null,NEXUS_5,1.0,en]","",19846,],
-["ui_S_t[l.designsystem.components_ProgressDialog_null_ProgressDialog-Day_0_null,NEXUS_5,1.0,en]","ui_S_t[l.designsystem.components_ProgressDialog_null_ProgressDialog-Night_1_null,NEXUS_5,1.0,en]",19846,],
+["ui_S_t[l.designsystem.components_ProgressDialogContent_null_Dialogs_ProgressDialogContent_0_null,NEXUS_5,1.0,en]","",19860,],
+["ui_S_t[l.designsystem.components_ProgressDialog_null_ProgressDialog-Day_0_null,NEXUS_5,1.0,en]","ui_S_t[l.designsystem.components_ProgressDialog_null_ProgressDialog-Night_1_null,NEXUS_5,1.0,en]",19860,],
["ui_S_t[l.designsystem.theme.components_RadioButton_null_Toggles_RadioButton_0_null,NEXUS_5,1.0,en]","",0,],
-["ui_S_t[f.rageshake.api.detection_RageshakeDialogContent_null_RageshakeDialogContent-Day-1_2_null,NEXUS_5,1.0,en]","ui_S_t[f.rageshake.api.detection_RageshakeDialogContent_null_RageshakeDialogContent-Night-1_3_null,NEXUS_5,1.0,en]",19846,],
-["ui_S_t[f.rageshake.api.preferences_RageshakePreferencesView_null_RageshakePreferencesView-Day-2_3_null_0,NEXUS_5,1.0,en]","ui_S_t[f.rageshake.api.preferences_RageshakePreferencesView_null_RageshakePreferencesView-Night-2_4_null_0,NEXUS_5,1.0,en]",19846,],
+["ui_S_t[f.rageshake.api.detection_RageshakeDialogContent_null_RageshakeDialogContent-Day-1_2_null,NEXUS_5,1.0,en]","ui_S_t[f.rageshake.api.detection_RageshakeDialogContent_null_RageshakeDialogContent-Night-1_3_null,NEXUS_5,1.0,en]",19860,],
+["ui_S_t[f.rageshake.api.preferences_RageshakePreferencesView_null_RageshakePreferencesView-Day-2_3_null_0,NEXUS_5,1.0,en]","ui_S_t[f.rageshake.api.preferences_RageshakePreferencesView_null_RageshakePreferencesView-Night-2_4_null_0,NEXUS_5,1.0,en]",19860,],
["ui_S_t[f.rageshake.api.preferences_RageshakePreferencesView_null_RageshakePreferencesView-Day-2_3_null_1,NEXUS_5,1.0,en]","ui_S_t[f.rageshake.api.preferences_RageshakePreferencesView_null_RageshakePreferencesView-Night-2_4_null_1,NEXUS_5,1.0,en]",0,],
-["ui_S_t[f.messages.impl.timeline.components.receipt.bottomsheet_ReadReceiptBottomSheet_null_ReadReceiptBottomSheet-Day-58_58_null_0,NEXUS_5,1.0,en]","ui_S_t[f.messages.impl.timeline.components.receipt.bottomsheet_ReadReceiptBottomSheet_null_ReadReceiptBottomSheet-Night-58_59_null_0,NEXUS_5,1.0,en]",19849,],
-["ui_S_t[f.messages.impl.timeline.components.receipt.bottomsheet_ReadReceiptBottomSheet_null_ReadReceiptBottomSheet-Day-58_58_null_1,NEXUS_5,1.0,en]","ui_S_t[f.messages.impl.timeline.components.receipt.bottomsheet_ReadReceiptBottomSheet_null_ReadReceiptBottomSheet-Night-58_59_null_1,NEXUS_5,1.0,en]",19849,],
-["ui_S_t[f.messages.impl.timeline.components.receipt.bottomsheet_ReadReceiptBottomSheet_null_ReadReceiptBottomSheet-Day-58_58_null_2,NEXUS_5,1.0,en]","ui_S_t[f.messages.impl.timeline.components.receipt.bottomsheet_ReadReceiptBottomSheet_null_ReadReceiptBottomSheet-Night-58_59_null_2,NEXUS_5,1.0,en]",19849,],
-["ui_S_t[f.messages.impl.timeline.components.receipt.bottomsheet_ReadReceiptBottomSheet_null_ReadReceiptBottomSheet-Day-58_58_null_3,NEXUS_5,1.0,en]","ui_S_t[f.messages.impl.timeline.components.receipt.bottomsheet_ReadReceiptBottomSheet_null_ReadReceiptBottomSheet-Night-58_59_null_3,NEXUS_5,1.0,en]",19849,],
-["ui_S_t[f.messages.impl.timeline.components.receipt.bottomsheet_ReadReceiptBottomSheet_null_ReadReceiptBottomSheet-Day-58_58_null_4,NEXUS_5,1.0,en]","ui_S_t[f.messages.impl.timeline.components.receipt.bottomsheet_ReadReceiptBottomSheet_null_ReadReceiptBottomSheet-Night-58_59_null_4,NEXUS_5,1.0,en]",19849,],
-["ui_S_t[f.messages.impl.timeline.components.receipt.bottomsheet_ReadReceiptBottomSheet_null_ReadReceiptBottomSheet-Day-58_58_null_5,NEXUS_5,1.0,en]","ui_S_t[f.messages.impl.timeline.components.receipt.bottomsheet_ReadReceiptBottomSheet_null_ReadReceiptBottomSheet-Night-58_59_null_5,NEXUS_5,1.0,en]",19849,],
-["ui_S_t[f.securebackup.impl.setup.views_RecoveryKeyView_null_RecoveryKeyView-Day-7_8_null_0,NEXUS_5,1.0,en]","ui_S_t[f.securebackup.impl.setup.views_RecoveryKeyView_null_RecoveryKeyView-Night-7_9_null_0,NEXUS_5,1.0,en]",19846,],
-["ui_S_t[f.securebackup.impl.setup.views_RecoveryKeyView_null_RecoveryKeyView-Day-7_8_null_1,NEXUS_5,1.0,en]","ui_S_t[f.securebackup.impl.setup.views_RecoveryKeyView_null_RecoveryKeyView-Night-7_9_null_1,NEXUS_5,1.0,en]",19846,],
-["ui_S_t[f.securebackup.impl.setup.views_RecoveryKeyView_null_RecoveryKeyView-Day-7_8_null_10,NEXUS_5,1.0,en]","ui_S_t[f.securebackup.impl.setup.views_RecoveryKeyView_null_RecoveryKeyView-Night-7_9_null_10,NEXUS_5,1.0,en]",19846,],
-["ui_S_t[f.securebackup.impl.setup.views_RecoveryKeyView_null_RecoveryKeyView-Day-7_8_null_11,NEXUS_5,1.0,en]","ui_S_t[f.securebackup.impl.setup.views_RecoveryKeyView_null_RecoveryKeyView-Night-7_9_null_11,NEXUS_5,1.0,en]",19846,],
-["ui_S_t[f.securebackup.impl.setup.views_RecoveryKeyView_null_RecoveryKeyView-Day-7_8_null_2,NEXUS_5,1.0,en]","ui_S_t[f.securebackup.impl.setup.views_RecoveryKeyView_null_RecoveryKeyView-Night-7_9_null_2,NEXUS_5,1.0,en]",19846,],
-["ui_S_t[f.securebackup.impl.setup.views_RecoveryKeyView_null_RecoveryKeyView-Day-7_8_null_3,NEXUS_5,1.0,en]","ui_S_t[f.securebackup.impl.setup.views_RecoveryKeyView_null_RecoveryKeyView-Night-7_9_null_3,NEXUS_5,1.0,en]",19846,],
-["ui_S_t[f.securebackup.impl.setup.views_RecoveryKeyView_null_RecoveryKeyView-Day-7_8_null_4,NEXUS_5,1.0,en]","ui_S_t[f.securebackup.impl.setup.views_RecoveryKeyView_null_RecoveryKeyView-Night-7_9_null_4,NEXUS_5,1.0,en]",19846,],
-["ui_S_t[f.securebackup.impl.setup.views_RecoveryKeyView_null_RecoveryKeyView-Day-7_8_null_5,NEXUS_5,1.0,en]","ui_S_t[f.securebackup.impl.setup.views_RecoveryKeyView_null_RecoveryKeyView-Night-7_9_null_5,NEXUS_5,1.0,en]",19846,],
-["ui_S_t[f.securebackup.impl.setup.views_RecoveryKeyView_null_RecoveryKeyView-Day-7_8_null_6,NEXUS_5,1.0,en]","ui_S_t[f.securebackup.impl.setup.views_RecoveryKeyView_null_RecoveryKeyView-Night-7_9_null_6,NEXUS_5,1.0,en]",19846,],
-["ui_S_t[f.securebackup.impl.setup.views_RecoveryKeyView_null_RecoveryKeyView-Day-7_8_null_7,NEXUS_5,1.0,en]","ui_S_t[f.securebackup.impl.setup.views_RecoveryKeyView_null_RecoveryKeyView-Night-7_9_null_7,NEXUS_5,1.0,en]",19846,],
-["ui_S_t[f.securebackup.impl.setup.views_RecoveryKeyView_null_RecoveryKeyView-Day-7_8_null_8,NEXUS_5,1.0,en]","ui_S_t[f.securebackup.impl.setup.views_RecoveryKeyView_null_RecoveryKeyView-Night-7_9_null_8,NEXUS_5,1.0,en]",19846,],
-["ui_S_t[f.securebackup.impl.setup.views_RecoveryKeyView_null_RecoveryKeyView-Day-7_8_null_9,NEXUS_5,1.0,en]","ui_S_t[f.securebackup.impl.setup.views_RecoveryKeyView_null_RecoveryKeyView-Night-7_9_null_9,NEXUS_5,1.0,en]",19846,],
+["ui_S_t[f.messages.impl.timeline.components.receipt.bottomsheet_ReadReceiptBottomSheet_null_ReadReceiptBottomSheet-Day-58_58_null_0,NEXUS_5,1.0,en]","ui_S_t[f.messages.impl.timeline.components.receipt.bottomsheet_ReadReceiptBottomSheet_null_ReadReceiptBottomSheet-Night-58_59_null_0,NEXUS_5,1.0,en]",19860,],
+["ui_S_t[f.messages.impl.timeline.components.receipt.bottomsheet_ReadReceiptBottomSheet_null_ReadReceiptBottomSheet-Day-58_58_null_1,NEXUS_5,1.0,en]","ui_S_t[f.messages.impl.timeline.components.receipt.bottomsheet_ReadReceiptBottomSheet_null_ReadReceiptBottomSheet-Night-58_59_null_1,NEXUS_5,1.0,en]",19860,],
+["ui_S_t[f.messages.impl.timeline.components.receipt.bottomsheet_ReadReceiptBottomSheet_null_ReadReceiptBottomSheet-Day-58_58_null_2,NEXUS_5,1.0,en]","ui_S_t[f.messages.impl.timeline.components.receipt.bottomsheet_ReadReceiptBottomSheet_null_ReadReceiptBottomSheet-Night-58_59_null_2,NEXUS_5,1.0,en]",19860,],
+["ui_S_t[f.messages.impl.timeline.components.receipt.bottomsheet_ReadReceiptBottomSheet_null_ReadReceiptBottomSheet-Day-58_58_null_3,NEXUS_5,1.0,en]","ui_S_t[f.messages.impl.timeline.components.receipt.bottomsheet_ReadReceiptBottomSheet_null_ReadReceiptBottomSheet-Night-58_59_null_3,NEXUS_5,1.0,en]",19860,],
+["ui_S_t[f.messages.impl.timeline.components.receipt.bottomsheet_ReadReceiptBottomSheet_null_ReadReceiptBottomSheet-Day-58_58_null_4,NEXUS_5,1.0,en]","ui_S_t[f.messages.impl.timeline.components.receipt.bottomsheet_ReadReceiptBottomSheet_null_ReadReceiptBottomSheet-Night-58_59_null_4,NEXUS_5,1.0,en]",19860,],
+["ui_S_t[f.messages.impl.timeline.components.receipt.bottomsheet_ReadReceiptBottomSheet_null_ReadReceiptBottomSheet-Day-58_58_null_5,NEXUS_5,1.0,en]","ui_S_t[f.messages.impl.timeline.components.receipt.bottomsheet_ReadReceiptBottomSheet_null_ReadReceiptBottomSheet-Night-58_59_null_5,NEXUS_5,1.0,en]",19860,],
+["ui_S_t[f.securebackup.impl.setup.views_RecoveryKeyView_null_RecoveryKeyView-Day-7_8_null_0,NEXUS_5,1.0,en]","ui_S_t[f.securebackup.impl.setup.views_RecoveryKeyView_null_RecoveryKeyView-Night-7_9_null_0,NEXUS_5,1.0,en]",19860,],
+["ui_S_t[f.securebackup.impl.setup.views_RecoveryKeyView_null_RecoveryKeyView-Day-7_8_null_1,NEXUS_5,1.0,en]","ui_S_t[f.securebackup.impl.setup.views_RecoveryKeyView_null_RecoveryKeyView-Night-7_9_null_1,NEXUS_5,1.0,en]",19860,],
+["ui_S_t[f.securebackup.impl.setup.views_RecoveryKeyView_null_RecoveryKeyView-Day-7_8_null_10,NEXUS_5,1.0,en]","ui_S_t[f.securebackup.impl.setup.views_RecoveryKeyView_null_RecoveryKeyView-Night-7_9_null_10,NEXUS_5,1.0,en]",19860,],
+["ui_S_t[f.securebackup.impl.setup.views_RecoveryKeyView_null_RecoveryKeyView-Day-7_8_null_11,NEXUS_5,1.0,en]","ui_S_t[f.securebackup.impl.setup.views_RecoveryKeyView_null_RecoveryKeyView-Night-7_9_null_11,NEXUS_5,1.0,en]",19860,],
+["ui_S_t[f.securebackup.impl.setup.views_RecoveryKeyView_null_RecoveryKeyView-Day-7_8_null_2,NEXUS_5,1.0,en]","ui_S_t[f.securebackup.impl.setup.views_RecoveryKeyView_null_RecoveryKeyView-Night-7_9_null_2,NEXUS_5,1.0,en]",19860,],
+["ui_S_t[f.securebackup.impl.setup.views_RecoveryKeyView_null_RecoveryKeyView-Day-7_8_null_3,NEXUS_5,1.0,en]","ui_S_t[f.securebackup.impl.setup.views_RecoveryKeyView_null_RecoveryKeyView-Night-7_9_null_3,NEXUS_5,1.0,en]",19860,],
+["ui_S_t[f.securebackup.impl.setup.views_RecoveryKeyView_null_RecoveryKeyView-Day-7_8_null_4,NEXUS_5,1.0,en]","ui_S_t[f.securebackup.impl.setup.views_RecoveryKeyView_null_RecoveryKeyView-Night-7_9_null_4,NEXUS_5,1.0,en]",19860,],
+["ui_S_t[f.securebackup.impl.setup.views_RecoveryKeyView_null_RecoveryKeyView-Day-7_8_null_5,NEXUS_5,1.0,en]","ui_S_t[f.securebackup.impl.setup.views_RecoveryKeyView_null_RecoveryKeyView-Night-7_9_null_5,NEXUS_5,1.0,en]",19860,],
+["ui_S_t[f.securebackup.impl.setup.views_RecoveryKeyView_null_RecoveryKeyView-Day-7_8_null_6,NEXUS_5,1.0,en]","ui_S_t[f.securebackup.impl.setup.views_RecoveryKeyView_null_RecoveryKeyView-Night-7_9_null_6,NEXUS_5,1.0,en]",19860,],
+["ui_S_t[f.securebackup.impl.setup.views_RecoveryKeyView_null_RecoveryKeyView-Day-7_8_null_7,NEXUS_5,1.0,en]","ui_S_t[f.securebackup.impl.setup.views_RecoveryKeyView_null_RecoveryKeyView-Night-7_9_null_7,NEXUS_5,1.0,en]",19860,],
+["ui_S_t[f.securebackup.impl.setup.views_RecoveryKeyView_null_RecoveryKeyView-Day-7_8_null_8,NEXUS_5,1.0,en]","ui_S_t[f.securebackup.impl.setup.views_RecoveryKeyView_null_RecoveryKeyView-Night-7_9_null_8,NEXUS_5,1.0,en]",19860,],
+["ui_S_t[f.securebackup.impl.setup.views_RecoveryKeyView_null_RecoveryKeyView-Day-7_8_null_9,NEXUS_5,1.0,en]","ui_S_t[f.securebackup.impl.setup.views_RecoveryKeyView_null_RecoveryKeyView-Night-7_9_null_9,NEXUS_5,1.0,en]",19860,],
["ui_S_t[l.designsystem.atomic.atoms_RedIndicatorAtom_null_RedIndicatorAtom-Day_0_null,NEXUS_5,1.0,en]","ui_S_t[l.designsystem.atomic.atoms_RedIndicatorAtom_null_RedIndicatorAtom-Night_1_null,NEXUS_5,1.0,en]",0,],
["ui_S_t[f.messages.impl.timeline.components_ReplySwipeIndicator_null_ReplySwipeIndicator-Day-15_15_null,NEXUS_5,1.0,en]","ui_S_t[f.messages.impl.timeline.components_ReplySwipeIndicator_null_ReplySwipeIndicator-Night-15_16_null,NEXUS_5,1.0,en]",0,],
-["ui_S_t[f.messages.impl.report_ReportMessageView_null_ReportMessageView-Day-7_7_null_0,NEXUS_5,1.0,en]","ui_S_t[f.messages.impl.report_ReportMessageView_null_ReportMessageView-Night-7_8_null_0,NEXUS_5,1.0,en]",19846,],
-["ui_S_t[f.messages.impl.report_ReportMessageView_null_ReportMessageView-Day-7_7_null_1,NEXUS_5,1.0,en]","ui_S_t[f.messages.impl.report_ReportMessageView_null_ReportMessageView-Night-7_8_null_1,NEXUS_5,1.0,en]",19846,],
-["ui_S_t[f.messages.impl.report_ReportMessageView_null_ReportMessageView-Day-7_7_null_2,NEXUS_5,1.0,en]","ui_S_t[f.messages.impl.report_ReportMessageView_null_ReportMessageView-Night-7_8_null_2,NEXUS_5,1.0,en]",19846,],
-["ui_S_t[f.messages.impl.report_ReportMessageView_null_ReportMessageView-Day-7_7_null_3,NEXUS_5,1.0,en]","ui_S_t[f.messages.impl.report_ReportMessageView_null_ReportMessageView-Night-7_8_null_3,NEXUS_5,1.0,en]",19846,],
-["ui_S_t[f.messages.impl.report_ReportMessageView_null_ReportMessageView-Day-7_7_null_4,NEXUS_5,1.0,en]","ui_S_t[f.messages.impl.report_ReportMessageView_null_ReportMessageView-Night-7_8_null_4,NEXUS_5,1.0,en]",19846,],
-["ui_S_t[f.messages.impl.report_ReportMessageView_null_ReportMessageView-Day-7_7_null_5,NEXUS_5,1.0,en]","ui_S_t[f.messages.impl.report_ReportMessageView_null_ReportMessageView-Night-7_8_null_5,NEXUS_5,1.0,en]",19846,],
-["ui_S_t[l.designsystem.components.dialogs_RetryDialogContent_null_Dialogs_RetryDialogContent_0_null,NEXUS_5,1.0,en]","",19846,],
-["ui_S_t[l.designsystem.components.dialogs_RetryDialog_null_RetryDialog-Day_0_null,NEXUS_5,1.0,en]","ui_S_t[l.designsystem.components.dialogs_RetryDialog_null_RetryDialog-Night_1_null,NEXUS_5,1.0,en]",19846,],
+["ui_S_t[f.messages.impl.report_ReportMessageView_null_ReportMessageView-Day-7_7_null_0,NEXUS_5,1.0,en]","ui_S_t[f.messages.impl.report_ReportMessageView_null_ReportMessageView-Night-7_8_null_0,NEXUS_5,1.0,en]",19860,],
+["ui_S_t[f.messages.impl.report_ReportMessageView_null_ReportMessageView-Day-7_7_null_1,NEXUS_5,1.0,en]","ui_S_t[f.messages.impl.report_ReportMessageView_null_ReportMessageView-Night-7_8_null_1,NEXUS_5,1.0,en]",19860,],
+["ui_S_t[f.messages.impl.report_ReportMessageView_null_ReportMessageView-Day-7_7_null_2,NEXUS_5,1.0,en]","ui_S_t[f.messages.impl.report_ReportMessageView_null_ReportMessageView-Night-7_8_null_2,NEXUS_5,1.0,en]",19860,],
+["ui_S_t[f.messages.impl.report_ReportMessageView_null_ReportMessageView-Day-7_7_null_3,NEXUS_5,1.0,en]","ui_S_t[f.messages.impl.report_ReportMessageView_null_ReportMessageView-Night-7_8_null_3,NEXUS_5,1.0,en]",19860,],
+["ui_S_t[f.messages.impl.report_ReportMessageView_null_ReportMessageView-Day-7_7_null_4,NEXUS_5,1.0,en]","ui_S_t[f.messages.impl.report_ReportMessageView_null_ReportMessageView-Night-7_8_null_4,NEXUS_5,1.0,en]",19860,],
+["ui_S_t[f.messages.impl.report_ReportMessageView_null_ReportMessageView-Day-7_7_null_5,NEXUS_5,1.0,en]","ui_S_t[f.messages.impl.report_ReportMessageView_null_ReportMessageView-Night-7_8_null_5,NEXUS_5,1.0,en]",19860,],
+["ui_S_t[l.designsystem.components.dialogs_RetryDialogContent_null_Dialogs_RetryDialogContent_0_null,NEXUS_5,1.0,en]","",19860,],
+["ui_S_t[l.designsystem.components.dialogs_RetryDialog_null_RetryDialog-Day_0_null,NEXUS_5,1.0,en]","ui_S_t[l.designsystem.components.dialogs_RetryDialog_null_RetryDialog-Night_1_null,NEXUS_5,1.0,en]",19860,],
["ui_S_t[f.messages.impl.timeline.components.retrysendmenu_RetrySendMessageMenu_null_RetrySendMessageMenu-Day-59_59_null_0,NEXUS_5,1.0,en]","ui_S_t[f.messages.impl.timeline.components.retrysendmenu_RetrySendMessageMenu_null_RetrySendMessageMenu-Night-59_60_null_0,NEXUS_5,1.0,en]",0,],
-["ui_S_t[f.messages.impl.timeline.components.retrysendmenu_RetrySendMessageMenu_null_RetrySendMessageMenu-Day-59_59_null_1,NEXUS_5,1.0,en]","ui_S_t[f.messages.impl.timeline.components.retrysendmenu_RetrySendMessageMenu_null_RetrySendMessageMenu-Night-59_60_null_1,NEXUS_5,1.0,en]",19849,],
-["ui_S_t[f.roomdetails.impl.rolesandpermissions_RolesAndPermissionsView_null_RolesAndPermissionsView-Day-8_8_null_0,NEXUS_5,1.0,en]","ui_S_t[f.roomdetails.impl.rolesandpermissions_RolesAndPermissionsView_null_RolesAndPermissionsView-Night-8_9_null_0,NEXUS_5,1.0,en]",19849,],
-["ui_S_t[f.roomdetails.impl.rolesandpermissions_RolesAndPermissionsView_null_RolesAndPermissionsView-Day-8_8_null_1,NEXUS_5,1.0,en]","ui_S_t[f.roomdetails.impl.rolesandpermissions_RolesAndPermissionsView_null_RolesAndPermissionsView-Night-8_9_null_1,NEXUS_5,1.0,en]",19849,],
-["ui_S_t[f.roomdetails.impl.rolesandpermissions_RolesAndPermissionsView_null_RolesAndPermissionsView-Day-8_8_null_2,NEXUS_5,1.0,en]","ui_S_t[f.roomdetails.impl.rolesandpermissions_RolesAndPermissionsView_null_RolesAndPermissionsView-Night-8_9_null_2,NEXUS_5,1.0,en]",19849,],
-["ui_S_t[f.roomdetails.impl.rolesandpermissions_RolesAndPermissionsView_null_RolesAndPermissionsView-Day-8_8_null_3,NEXUS_5,1.0,en]","ui_S_t[f.roomdetails.impl.rolesandpermissions_RolesAndPermissionsView_null_RolesAndPermissionsView-Night-8_9_null_3,NEXUS_5,1.0,en]",19849,],
-["ui_S_t[f.roomdetails.impl.rolesandpermissions_RolesAndPermissionsView_null_RolesAndPermissionsView-Day-8_8_null_4,NEXUS_5,1.0,en]","ui_S_t[f.roomdetails.impl.rolesandpermissions_RolesAndPermissionsView_null_RolesAndPermissionsView-Night-8_9_null_4,NEXUS_5,1.0,en]",19849,],
-["ui_S_t[f.roomdetails.impl.rolesandpermissions_RolesAndPermissionsView_null_RolesAndPermissionsView-Day-8_8_null_5,NEXUS_5,1.0,en]","ui_S_t[f.roomdetails.impl.rolesandpermissions_RolesAndPermissionsView_null_RolesAndPermissionsView-Night-8_9_null_5,NEXUS_5,1.0,en]",19849,],
-["ui_S_t[f.roomdetails.impl.rolesandpermissions_RolesAndPermissionsView_null_RolesAndPermissionsView-Day-8_8_null_6,NEXUS_5,1.0,en]","ui_S_t[f.roomdetails.impl.rolesandpermissions_RolesAndPermissionsView_null_RolesAndPermissionsView-Night-8_9_null_6,NEXUS_5,1.0,en]",19849,],
-["ui_S_t[f.roomdetails.impl.rolesandpermissions_RolesAndPermissionsView_null_RolesAndPermissionsView-Day-8_8_null_7,NEXUS_5,1.0,en]","ui_S_t[f.roomdetails.impl.rolesandpermissions_RolesAndPermissionsView_null_RolesAndPermissionsView-Night-8_9_null_7,NEXUS_5,1.0,en]",19849,],
+["ui_S_t[f.messages.impl.timeline.components.retrysendmenu_RetrySendMessageMenu_null_RetrySendMessageMenu-Day-59_59_null_1,NEXUS_5,1.0,en]","ui_S_t[f.messages.impl.timeline.components.retrysendmenu_RetrySendMessageMenu_null_RetrySendMessageMenu-Night-59_60_null_1,NEXUS_5,1.0,en]",19860,],
+["ui_S_t[f.roomdetails.impl.rolesandpermissions_RolesAndPermissionsView_null_RolesAndPermissionsView-Day-11_11_null_0,NEXUS_5,1.0,en]","ui_S_t[f.roomdetails.impl.rolesandpermissions_RolesAndPermissionsView_null_RolesAndPermissionsView-Night-11_12_null_0,NEXUS_5,1.0,en]",19860,],
+["ui_S_t[f.roomdetails.impl.rolesandpermissions_RolesAndPermissionsView_null_RolesAndPermissionsView-Day-11_11_null_1,NEXUS_5,1.0,en]","ui_S_t[f.roomdetails.impl.rolesandpermissions_RolesAndPermissionsView_null_RolesAndPermissionsView-Night-11_12_null_1,NEXUS_5,1.0,en]",19860,],
+["ui_S_t[f.roomdetails.impl.rolesandpermissions_RolesAndPermissionsView_null_RolesAndPermissionsView-Day-11_11_null_2,NEXUS_5,1.0,en]","ui_S_t[f.roomdetails.impl.rolesandpermissions_RolesAndPermissionsView_null_RolesAndPermissionsView-Night-11_12_null_2,NEXUS_5,1.0,en]",19860,],
+["ui_S_t[f.roomdetails.impl.rolesandpermissions_RolesAndPermissionsView_null_RolesAndPermissionsView-Day-11_11_null_3,NEXUS_5,1.0,en]","ui_S_t[f.roomdetails.impl.rolesandpermissions_RolesAndPermissionsView_null_RolesAndPermissionsView-Night-11_12_null_3,NEXUS_5,1.0,en]",19860,],
+["ui_S_t[f.roomdetails.impl.rolesandpermissions_RolesAndPermissionsView_null_RolesAndPermissionsView-Day-11_11_null_4,NEXUS_5,1.0,en]","ui_S_t[f.roomdetails.impl.rolesandpermissions_RolesAndPermissionsView_null_RolesAndPermissionsView-Night-11_12_null_4,NEXUS_5,1.0,en]",19860,],
+["ui_S_t[f.roomdetails.impl.rolesandpermissions_RolesAndPermissionsView_null_RolesAndPermissionsView-Day-11_11_null_5,NEXUS_5,1.0,en]","ui_S_t[f.roomdetails.impl.rolesandpermissions_RolesAndPermissionsView_null_RolesAndPermissionsView-Night-11_12_null_5,NEXUS_5,1.0,en]",19860,],
+["ui_S_t[f.roomdetails.impl.rolesandpermissions_RolesAndPermissionsView_null_RolesAndPermissionsView-Day-11_11_null_6,NEXUS_5,1.0,en]","ui_S_t[f.roomdetails.impl.rolesandpermissions_RolesAndPermissionsView_null_RolesAndPermissionsView-Night-11_12_null_6,NEXUS_5,1.0,en]",19860,],
+["ui_S_t[f.roomdetails.impl.rolesandpermissions_RolesAndPermissionsView_null_RolesAndPermissionsView-Day-11_11_null_7,NEXUS_5,1.0,en]","ui_S_t[f.roomdetails.impl.rolesandpermissions_RolesAndPermissionsView_null_RolesAndPermissionsView-Night-11_12_null_7,NEXUS_5,1.0,en]",19860,],
["ui_S_t[f.roomaliasresolver.impl_RoomAliasResolverView_null_RoomAliasResolverView-Day-0_1_null_0,NEXUS_5,1.0,en]","ui_S_t[f.roomaliasresolver.impl_RoomAliasResolverView_null_RoomAliasResolverView-Night-0_2_null_0,NEXUS_5,1.0,en]",0,],
["ui_S_t[f.roomaliasresolver.impl_RoomAliasResolverView_null_RoomAliasResolverView-Day-0_1_null_1,NEXUS_5,1.0,en]","ui_S_t[f.roomaliasresolver.impl_RoomAliasResolverView_null_RoomAliasResolverView-Night-0_2_null_1,NEXUS_5,1.0,en]",0,],
-["ui_S_t[f.roomaliasresolver.impl_RoomAliasResolverView_null_RoomAliasResolverView-Day-0_1_null_2,NEXUS_5,1.0,en]","ui_S_t[f.roomaliasresolver.impl_RoomAliasResolverView_null_RoomAliasResolverView-Night-0_2_null_2,NEXUS_5,1.0,en]",19846,],
-["ui_S_t[f.roomdetails.impl_RoomDetailsDark_null_RoomDetailsDark--1_3_null_0,NEXUS_5,1.0,en]","",19849,],
-["ui_S_t[f.roomdetails.impl_RoomDetailsDark_null_RoomDetailsDark--1_3_null_1,NEXUS_5,1.0,en]","",19849,],
-["ui_S_t[f.roomdetails.impl_RoomDetailsDark_null_RoomDetailsDark--1_3_null_2,NEXUS_5,1.0,en]","",19849,],
-["ui_S_t[f.roomdetails.impl_RoomDetailsDark_null_RoomDetailsDark--1_3_null_3,NEXUS_5,1.0,en]","",19849,],
-["ui_S_t[f.roomdetails.impl_RoomDetailsDark_null_RoomDetailsDark--1_3_null_4,NEXUS_5,1.0,en]","",19849,],
-["ui_S_t[f.roomdetails.impl_RoomDetailsDark_null_RoomDetailsDark--1_3_null_5,NEXUS_5,1.0,en]","",19849,],
-["ui_S_t[f.roomdetails.impl_RoomDetailsDark_null_RoomDetailsDark--1_3_null_6,NEXUS_5,1.0,en]","",19849,],
-["ui_S_t[f.roomdetails.impl_RoomDetailsDark_null_RoomDetailsDark--1_3_null_7,NEXUS_5,1.0,en]","",19849,],
-["ui_S_t[f.roomdetails.impl_RoomDetailsDark_null_RoomDetailsDark--1_3_null_8,NEXUS_5,1.0,en]","",19849,],
-["ui_S_t[f.roomdetails.impl_RoomDetailsDark_null_RoomDetailsDark--1_3_null_9,NEXUS_5,1.0,en]","",19849,],
-["ui_S_t[f.roomdetails.impl.edit_RoomDetailsEditView_null_RoomDetailsEditView-Day-0_0_null_0,NEXUS_5,1.0,en]","ui_S_t[f.roomdetails.impl.edit_RoomDetailsEditView_null_RoomDetailsEditView-Night-0_1_null_0,NEXUS_5,1.0,en]",19849,],
-["ui_S_t[f.roomdetails.impl.edit_RoomDetailsEditView_null_RoomDetailsEditView-Day-0_0_null_1,NEXUS_5,1.0,en]","ui_S_t[f.roomdetails.impl.edit_RoomDetailsEditView_null_RoomDetailsEditView-Night-0_1_null_1,NEXUS_5,1.0,en]",19849,],
-["ui_S_t[f.roomdetails.impl.edit_RoomDetailsEditView_null_RoomDetailsEditView-Day-0_0_null_2,NEXUS_5,1.0,en]","ui_S_t[f.roomdetails.impl.edit_RoomDetailsEditView_null_RoomDetailsEditView-Night-0_1_null_2,NEXUS_5,1.0,en]",19849,],
-["ui_S_t[f.roomdetails.impl.edit_RoomDetailsEditView_null_RoomDetailsEditView-Day-0_0_null_3,NEXUS_5,1.0,en]","ui_S_t[f.roomdetails.impl.edit_RoomDetailsEditView_null_RoomDetailsEditView-Night-0_1_null_3,NEXUS_5,1.0,en]",19849,],
-["ui_S_t[f.roomdetails.impl.edit_RoomDetailsEditView_null_RoomDetailsEditView-Day-0_0_null_4,NEXUS_5,1.0,en]","ui_S_t[f.roomdetails.impl.edit_RoomDetailsEditView_null_RoomDetailsEditView-Night-0_1_null_4,NEXUS_5,1.0,en]",19849,],
-["ui_S_t[f.roomdetails.impl.edit_RoomDetailsEditView_null_RoomDetailsEditView-Day-0_0_null_5,NEXUS_5,1.0,en]","ui_S_t[f.roomdetails.impl.edit_RoomDetailsEditView_null_RoomDetailsEditView-Night-0_1_null_5,NEXUS_5,1.0,en]",19849,],
-["ui_S_t[f.roomdetails.impl.edit_RoomDetailsEditView_null_RoomDetailsEditView-Day-0_0_null_6,NEXUS_5,1.0,en]","ui_S_t[f.roomdetails.impl.edit_RoomDetailsEditView_null_RoomDetailsEditView-Night-0_1_null_6,NEXUS_5,1.0,en]",19849,],
-["ui_S_t[f.roomdetails.impl_RoomDetails_null_RoomDetails--0_2_null_0,NEXUS_5,1.0,en]","",19849,],
-["ui_S_t[f.roomdetails.impl_RoomDetails_null_RoomDetails--0_2_null_1,NEXUS_5,1.0,en]","",19849,],
-["ui_S_t[f.roomdetails.impl_RoomDetails_null_RoomDetails--0_2_null_2,NEXUS_5,1.0,en]","",19849,],
-["ui_S_t[f.roomdetails.impl_RoomDetails_null_RoomDetails--0_2_null_3,NEXUS_5,1.0,en]","",19849,],
-["ui_S_t[f.roomdetails.impl_RoomDetails_null_RoomDetails--0_2_null_4,NEXUS_5,1.0,en]","",19849,],
-["ui_S_t[f.roomdetails.impl_RoomDetails_null_RoomDetails--0_2_null_5,NEXUS_5,1.0,en]","",19849,],
-["ui_S_t[f.roomdetails.impl_RoomDetails_null_RoomDetails--0_2_null_6,NEXUS_5,1.0,en]","",19849,],
-["ui_S_t[f.roomdetails.impl_RoomDetails_null_RoomDetails--0_2_null_7,NEXUS_5,1.0,en]","",19849,],
-["ui_S_t[f.roomdetails.impl_RoomDetails_null_RoomDetails--0_2_null_8,NEXUS_5,1.0,en]","",19849,],
-["ui_S_t[f.roomdetails.impl_RoomDetails_null_RoomDetails--0_2_null_9,NEXUS_5,1.0,en]","",19849,],
-["ui_S_t[f.roomdirectory.impl.root_RoomDirectoryView_null_RoomDirectoryView-Day-0_1_null_0,NEXUS_5,1.0,en]","ui_S_t[f.roomdirectory.impl.root_RoomDirectoryView_null_RoomDirectoryView-Night-0_2_null_0,NEXUS_5,1.0,en]",19846,],
-["ui_S_t[f.roomdirectory.impl.root_RoomDirectoryView_null_RoomDirectoryView-Day-0_1_null_1,NEXUS_5,1.0,en]","ui_S_t[f.roomdirectory.impl.root_RoomDirectoryView_null_RoomDirectoryView-Night-0_2_null_1,NEXUS_5,1.0,en]",19846,],
-["ui_S_t[f.roomdirectory.impl.root_RoomDirectoryView_null_RoomDirectoryView-Day-0_1_null_2,NEXUS_5,1.0,en]","ui_S_t[f.roomdirectory.impl.root_RoomDirectoryView_null_RoomDirectoryView-Night-0_2_null_2,NEXUS_5,1.0,en]",19846,],
-["ui_S_t[f.roomdirectory.impl.root_RoomDirectoryView_null_RoomDirectoryView-Day-0_1_null_3,NEXUS_5,1.0,en]","ui_S_t[f.roomdirectory.impl.root_RoomDirectoryView_null_RoomDirectoryView-Night-0_2_null_3,NEXUS_5,1.0,en]",19846,],
-["ui_S_t[f.roomdirectory.impl.root_RoomDirectoryView_null_RoomDirectoryView-Day-0_1_null_4,NEXUS_5,1.0,en]","ui_S_t[f.roomdirectory.impl.root_RoomDirectoryView_null_RoomDirectoryView-Night-0_2_null_4,NEXUS_5,1.0,en]",19846,],
-["ui_S_t[f.roomdetails.impl.invite_RoomInviteMembersView_null_RoomInviteMembersView-Day-1_1_null_0,NEXUS_5,1.0,en]","ui_S_t[f.roomdetails.impl.invite_RoomInviteMembersView_null_RoomInviteMembersView-Night-1_2_null_0,NEXUS_5,1.0,en]",19849,],
-["ui_S_t[f.roomdetails.impl.invite_RoomInviteMembersView_null_RoomInviteMembersView-Day-1_1_null_1,NEXUS_5,1.0,en]","ui_S_t[f.roomdetails.impl.invite_RoomInviteMembersView_null_RoomInviteMembersView-Night-1_2_null_1,NEXUS_5,1.0,en]",19849,],
-["ui_S_t[f.roomdetails.impl.invite_RoomInviteMembersView_null_RoomInviteMembersView-Day-1_1_null_2,NEXUS_5,1.0,en]","ui_S_t[f.roomdetails.impl.invite_RoomInviteMembersView_null_RoomInviteMembersView-Night-1_2_null_2,NEXUS_5,1.0,en]",19849,],
-["ui_S_t[f.roomdetails.impl.invite_RoomInviteMembersView_null_RoomInviteMembersView-Day-1_1_null_3,NEXUS_5,1.0,en]","ui_S_t[f.roomdetails.impl.invite_RoomInviteMembersView_null_RoomInviteMembersView-Night-1_2_null_3,NEXUS_5,1.0,en]",19849,],
-["ui_S_t[f.roomdetails.impl.invite_RoomInviteMembersView_null_RoomInviteMembersView-Day-1_1_null_4,NEXUS_5,1.0,en]","ui_S_t[f.roomdetails.impl.invite_RoomInviteMembersView_null_RoomInviteMembersView-Night-1_2_null_4,NEXUS_5,1.0,en]",19849,],
-["ui_S_t[f.roomdetails.impl.invite_RoomInviteMembersView_null_RoomInviteMembersView-Day-1_1_null_5,NEXUS_5,1.0,en]","ui_S_t[f.roomdetails.impl.invite_RoomInviteMembersView_null_RoomInviteMembersView-Night-1_2_null_5,NEXUS_5,1.0,en]",19849,],
-["ui_S_t[f.roomdetails.impl.invite_RoomInviteMembersView_null_RoomInviteMembersView-Day-1_1_null_6,NEXUS_5,1.0,en]","ui_S_t[f.roomdetails.impl.invite_RoomInviteMembersView_null_RoomInviteMembersView-Night-1_2_null_6,NEXUS_5,1.0,en]",19849,],
-["ui_S_t[f.roomdetails.impl.invite_RoomInviteMembersView_null_RoomInviteMembersView-Day-1_1_null_7,NEXUS_5,1.0,en]","ui_S_t[f.roomdetails.impl.invite_RoomInviteMembersView_null_RoomInviteMembersView-Night-1_2_null_7,NEXUS_5,1.0,en]",19849,],
-["ui_S_t[f.roomlist.impl.components_RoomListContentView_null_RoomListContentView-Day-3_4_null_0,NEXUS_5,1.0,en]","ui_S_t[f.roomlist.impl.components_RoomListContentView_null_RoomListContentView-Night-3_5_null_0,NEXUS_5,1.0,en]",19846,],
-["ui_S_t[f.roomlist.impl.components_RoomListContentView_null_RoomListContentView-Day-3_4_null_1,NEXUS_5,1.0,en]","ui_S_t[f.roomlist.impl.components_RoomListContentView_null_RoomListContentView-Night-3_5_null_1,NEXUS_5,1.0,en]",19846,],
+["ui_S_t[f.roomaliasresolver.impl_RoomAliasResolverView_null_RoomAliasResolverView-Day-0_1_null_2,NEXUS_5,1.0,en]","ui_S_t[f.roomaliasresolver.impl_RoomAliasResolverView_null_RoomAliasResolverView-Night-0_2_null_2,NEXUS_5,1.0,en]",19860,],
+["ui_S_t[f.roomdetails.impl.components_RoomBadgeNegative_null_RoomBadgeNegative-Day-2_2_null,NEXUS_5,1.0,en]","ui_S_t[f.roomdetails.impl.components_RoomBadgeNegative_null_RoomBadgeNegative-Night-2_3_null,NEXUS_5,1.0,en]",0,],
+["ui_S_t[f.roomdetails.impl.components_RoomBadgeNeutral_null_RoomBadgeNeutral-Day-1_1_null,NEXUS_5,1.0,en]","ui_S_t[f.roomdetails.impl.components_RoomBadgeNeutral_null_RoomBadgeNeutral-Night-1_2_null,NEXUS_5,1.0,en]",0,],
+["ui_S_t[f.roomdetails.impl.components_RoomBadgePositive_null_RoomBadgePositive-Day-0_0_null,NEXUS_5,1.0,en]","ui_S_t[f.roomdetails.impl.components_RoomBadgePositive_null_RoomBadgePositive-Night-0_1_null,NEXUS_5,1.0,en]",0,],
+["ui_S_t[f.roomdetails.impl_RoomDetailsDark_null_RoomDetailsDark--1_3_null_0,NEXUS_5,1.0,en]","",19860,],
+["ui_S_t[f.roomdetails.impl_RoomDetailsDark_null_RoomDetailsDark--1_3_null_1,NEXUS_5,1.0,en]","",19860,],
+["ui_S_t[f.roomdetails.impl_RoomDetailsDark_null_RoomDetailsDark--1_3_null_10,NEXUS_5,1.0,en]","",19860,],
+["ui_S_t[f.roomdetails.impl_RoomDetailsDark_null_RoomDetailsDark--1_3_null_11,NEXUS_5,1.0,en]","",19860,],
+["ui_S_t[f.roomdetails.impl_RoomDetailsDark_null_RoomDetailsDark--1_3_null_2,NEXUS_5,1.0,en]","",19860,],
+["ui_S_t[f.roomdetails.impl_RoomDetailsDark_null_RoomDetailsDark--1_3_null_3,NEXUS_5,1.0,en]","",19860,],
+["ui_S_t[f.roomdetails.impl_RoomDetailsDark_null_RoomDetailsDark--1_3_null_4,NEXUS_5,1.0,en]","",19860,],
+["ui_S_t[f.roomdetails.impl_RoomDetailsDark_null_RoomDetailsDark--1_3_null_5,NEXUS_5,1.0,en]","",19860,],
+["ui_S_t[f.roomdetails.impl_RoomDetailsDark_null_RoomDetailsDark--1_3_null_6,NEXUS_5,1.0,en]","",19860,],
+["ui_S_t[f.roomdetails.impl_RoomDetailsDark_null_RoomDetailsDark--1_3_null_7,NEXUS_5,1.0,en]","",19860,],
+["ui_S_t[f.roomdetails.impl_RoomDetailsDark_null_RoomDetailsDark--1_3_null_8,NEXUS_5,1.0,en]","",19860,],
+["ui_S_t[f.roomdetails.impl_RoomDetailsDark_null_RoomDetailsDark--1_3_null_9,NEXUS_5,1.0,en]","",19860,],
+["ui_S_t[f.roomdetails.impl.edit_RoomDetailsEditView_null_RoomDetailsEditView-Day-3_3_null_0,NEXUS_5,1.0,en]","ui_S_t[f.roomdetails.impl.edit_RoomDetailsEditView_null_RoomDetailsEditView-Night-3_4_null_0,NEXUS_5,1.0,en]",19860,],
+["ui_S_t[f.roomdetails.impl.edit_RoomDetailsEditView_null_RoomDetailsEditView-Day-3_3_null_1,NEXUS_5,1.0,en]","ui_S_t[f.roomdetails.impl.edit_RoomDetailsEditView_null_RoomDetailsEditView-Night-3_4_null_1,NEXUS_5,1.0,en]",19860,],
+["ui_S_t[f.roomdetails.impl.edit_RoomDetailsEditView_null_RoomDetailsEditView-Day-3_3_null_2,NEXUS_5,1.0,en]","ui_S_t[f.roomdetails.impl.edit_RoomDetailsEditView_null_RoomDetailsEditView-Night-3_4_null_2,NEXUS_5,1.0,en]",19860,],
+["ui_S_t[f.roomdetails.impl.edit_RoomDetailsEditView_null_RoomDetailsEditView-Day-3_3_null_3,NEXUS_5,1.0,en]","ui_S_t[f.roomdetails.impl.edit_RoomDetailsEditView_null_RoomDetailsEditView-Night-3_4_null_3,NEXUS_5,1.0,en]",19860,],
+["ui_S_t[f.roomdetails.impl.edit_RoomDetailsEditView_null_RoomDetailsEditView-Day-3_3_null_4,NEXUS_5,1.0,en]","ui_S_t[f.roomdetails.impl.edit_RoomDetailsEditView_null_RoomDetailsEditView-Night-3_4_null_4,NEXUS_5,1.0,en]",19860,],
+["ui_S_t[f.roomdetails.impl.edit_RoomDetailsEditView_null_RoomDetailsEditView-Day-3_3_null_5,NEXUS_5,1.0,en]","ui_S_t[f.roomdetails.impl.edit_RoomDetailsEditView_null_RoomDetailsEditView-Night-3_4_null_5,NEXUS_5,1.0,en]",19860,],
+["ui_S_t[f.roomdetails.impl.edit_RoomDetailsEditView_null_RoomDetailsEditView-Day-3_3_null_6,NEXUS_5,1.0,en]","ui_S_t[f.roomdetails.impl.edit_RoomDetailsEditView_null_RoomDetailsEditView-Night-3_4_null_6,NEXUS_5,1.0,en]",19860,],
+["ui_S_t[f.roomdetails.impl.edit_RoomDetailsEditView_null_RoomDetailsEditView-Day-3_3_null_7,NEXUS_5,1.0,en]","ui_S_t[f.roomdetails.impl.edit_RoomDetailsEditView_null_RoomDetailsEditView-Night-3_4_null_7,NEXUS_5,1.0,en]",19863,],
+["ui_S_t[f.roomdetails.impl_RoomDetails_null_RoomDetails--0_2_null_0,NEXUS_5,1.0,en]","",19860,],
+["ui_S_t[f.roomdetails.impl_RoomDetails_null_RoomDetails--0_2_null_1,NEXUS_5,1.0,en]","",19860,],
+["ui_S_t[f.roomdetails.impl_RoomDetails_null_RoomDetails--0_2_null_10,NEXUS_5,1.0,en]","",19860,],
+["ui_S_t[f.roomdetails.impl_RoomDetails_null_RoomDetails--0_2_null_11,NEXUS_5,1.0,en]","",19860,],
+["ui_S_t[f.roomdetails.impl_RoomDetails_null_RoomDetails--0_2_null_2,NEXUS_5,1.0,en]","",19860,],
+["ui_S_t[f.roomdetails.impl_RoomDetails_null_RoomDetails--0_2_null_3,NEXUS_5,1.0,en]","",19860,],
+["ui_S_t[f.roomdetails.impl_RoomDetails_null_RoomDetails--0_2_null_4,NEXUS_5,1.0,en]","",19860,],
+["ui_S_t[f.roomdetails.impl_RoomDetails_null_RoomDetails--0_2_null_5,NEXUS_5,1.0,en]","",19860,],
+["ui_S_t[f.roomdetails.impl_RoomDetails_null_RoomDetails--0_2_null_6,NEXUS_5,1.0,en]","",19860,],
+["ui_S_t[f.roomdetails.impl_RoomDetails_null_RoomDetails--0_2_null_7,NEXUS_5,1.0,en]","",19860,],
+["ui_S_t[f.roomdetails.impl_RoomDetails_null_RoomDetails--0_2_null_8,NEXUS_5,1.0,en]","",19860,],
+["ui_S_t[f.roomdetails.impl_RoomDetails_null_RoomDetails--0_2_null_9,NEXUS_5,1.0,en]","",19860,],
+["ui_S_t[f.roomdirectory.impl.root_RoomDirectoryView_null_RoomDirectoryView-Day-0_1_null_0,NEXUS_5,1.0,en]","ui_S_t[f.roomdirectory.impl.root_RoomDirectoryView_null_RoomDirectoryView-Night-0_2_null_0,NEXUS_5,1.0,en]",19860,],
+["ui_S_t[f.roomdirectory.impl.root_RoomDirectoryView_null_RoomDirectoryView-Day-0_1_null_1,NEXUS_5,1.0,en]","ui_S_t[f.roomdirectory.impl.root_RoomDirectoryView_null_RoomDirectoryView-Night-0_2_null_1,NEXUS_5,1.0,en]",19860,],
+["ui_S_t[f.roomdirectory.impl.root_RoomDirectoryView_null_RoomDirectoryView-Day-0_1_null_2,NEXUS_5,1.0,en]","ui_S_t[f.roomdirectory.impl.root_RoomDirectoryView_null_RoomDirectoryView-Night-0_2_null_2,NEXUS_5,1.0,en]",19860,],
+["ui_S_t[f.roomdetails.impl.invite_RoomInviteMembersView_null_RoomInviteMembersView-Day-4_4_null_0,NEXUS_5,1.0,en]","ui_S_t[f.roomdetails.impl.invite_RoomInviteMembersView_null_RoomInviteMembersView-Night-4_5_null_0,NEXUS_5,1.0,en]",19860,],
+["ui_S_t[f.roomdetails.impl.invite_RoomInviteMembersView_null_RoomInviteMembersView-Day-4_4_null_1,NEXUS_5,1.0,en]","ui_S_t[f.roomdetails.impl.invite_RoomInviteMembersView_null_RoomInviteMembersView-Night-4_5_null_1,NEXUS_5,1.0,en]",19860,],
+["ui_S_t[f.roomdetails.impl.invite_RoomInviteMembersView_null_RoomInviteMembersView-Day-4_4_null_2,NEXUS_5,1.0,en]","ui_S_t[f.roomdetails.impl.invite_RoomInviteMembersView_null_RoomInviteMembersView-Night-4_5_null_2,NEXUS_5,1.0,en]",19860,],
+["ui_S_t[f.roomdetails.impl.invite_RoomInviteMembersView_null_RoomInviteMembersView-Day-4_4_null_3,NEXUS_5,1.0,en]","ui_S_t[f.roomdetails.impl.invite_RoomInviteMembersView_null_RoomInviteMembersView-Night-4_5_null_3,NEXUS_5,1.0,en]",19860,],
+["ui_S_t[f.roomdetails.impl.invite_RoomInviteMembersView_null_RoomInviteMembersView-Day-4_4_null_4,NEXUS_5,1.0,en]","ui_S_t[f.roomdetails.impl.invite_RoomInviteMembersView_null_RoomInviteMembersView-Night-4_5_null_4,NEXUS_5,1.0,en]",19860,],
+["ui_S_t[f.roomdetails.impl.invite_RoomInviteMembersView_null_RoomInviteMembersView-Day-4_4_null_5,NEXUS_5,1.0,en]","ui_S_t[f.roomdetails.impl.invite_RoomInviteMembersView_null_RoomInviteMembersView-Night-4_5_null_5,NEXUS_5,1.0,en]",19860,],
+["ui_S_t[f.roomdetails.impl.invite_RoomInviteMembersView_null_RoomInviteMembersView-Day-4_4_null_6,NEXUS_5,1.0,en]","ui_S_t[f.roomdetails.impl.invite_RoomInviteMembersView_null_RoomInviteMembersView-Night-4_5_null_6,NEXUS_5,1.0,en]",19860,],
+["ui_S_t[f.roomdetails.impl.invite_RoomInviteMembersView_null_RoomInviteMembersView-Day-4_4_null_7,NEXUS_5,1.0,en]","ui_S_t[f.roomdetails.impl.invite_RoomInviteMembersView_null_RoomInviteMembersView-Night-4_5_null_7,NEXUS_5,1.0,en]",19860,],
+["ui_S_t[f.roomlist.impl.components_RoomListContentView_null_RoomListContentView-Day-3_4_null_0,NEXUS_5,1.0,en]","ui_S_t[f.roomlist.impl.components_RoomListContentView_null_RoomListContentView-Night-3_5_null_0,NEXUS_5,1.0,en]",19860,],
+["ui_S_t[f.roomlist.impl.components_RoomListContentView_null_RoomListContentView-Day-3_4_null_1,NEXUS_5,1.0,en]","ui_S_t[f.roomlist.impl.components_RoomListContentView_null_RoomListContentView-Night-3_5_null_1,NEXUS_5,1.0,en]",19860,],
["ui_S_t[f.roomlist.impl.components_RoomListContentView_null_RoomListContentView-Day-3_4_null_2,NEXUS_5,1.0,en]","ui_S_t[f.roomlist.impl.components_RoomListContentView_null_RoomListContentView-Night-3_5_null_2,NEXUS_5,1.0,en]",0,],
-["ui_S_t[f.roomlist.impl.components_RoomListContentView_null_RoomListContentView-Day-3_4_null_3,NEXUS_5,1.0,en]","ui_S_t[f.roomlist.impl.components_RoomListContentView_null_RoomListContentView-Night-3_5_null_3,NEXUS_5,1.0,en]",19846,],
-["ui_S_t[f.roomlist.impl.components_RoomListContentView_null_RoomListContentView-Day-3_4_null_4,NEXUS_5,1.0,en]","ui_S_t[f.roomlist.impl.components_RoomListContentView_null_RoomListContentView-Night-3_5_null_4,NEXUS_5,1.0,en]",19846,],
-["ui_S_t[f.roomlist.impl.filters_RoomListFiltersView_null_RoomListFiltersView-Day-8_9_null_0,NEXUS_5,1.0,en]","ui_S_t[f.roomlist.impl.filters_RoomListFiltersView_null_RoomListFiltersView-Night-8_10_null_0,NEXUS_5,1.0,en]",19846,],
-["ui_S_t[f.roomlist.impl.filters_RoomListFiltersView_null_RoomListFiltersView-Day-8_9_null_1,NEXUS_5,1.0,en]","ui_S_t[f.roomlist.impl.filters_RoomListFiltersView_null_RoomListFiltersView-Night-8_10_null_1,NEXUS_5,1.0,en]",19846,],
-["ui_S_t[f.roomlist.impl_RoomListModalBottomSheetContent_null_RoomListModalBottomSheetContent-Day-0_1_null_0,NEXUS_5,1.0,en]","ui_S_t[f.roomlist.impl_RoomListModalBottomSheetContent_null_RoomListModalBottomSheetContent-Night-0_2_null_0,NEXUS_5,1.0,en]",19846,],
-["ui_S_t[f.roomlist.impl_RoomListModalBottomSheetContent_null_RoomListModalBottomSheetContent-Day-0_1_null_1,NEXUS_5,1.0,en]","ui_S_t[f.roomlist.impl_RoomListModalBottomSheetContent_null_RoomListModalBottomSheetContent-Night-0_2_null_1,NEXUS_5,1.0,en]",19846,],
-["ui_S_t[f.roomlist.impl_RoomListModalBottomSheetContent_null_RoomListModalBottomSheetContent-Day-0_1_null_2,NEXUS_5,1.0,en]","ui_S_t[f.roomlist.impl_RoomListModalBottomSheetContent_null_RoomListModalBottomSheetContent-Night-0_2_null_2,NEXUS_5,1.0,en]",19846,],
+["ui_S_t[f.roomlist.impl.components_RoomListContentView_null_RoomListContentView-Day-3_4_null_3,NEXUS_5,1.0,en]","ui_S_t[f.roomlist.impl.components_RoomListContentView_null_RoomListContentView-Night-3_5_null_3,NEXUS_5,1.0,en]",19860,],
+["ui_S_t[f.roomlist.impl.components_RoomListContentView_null_RoomListContentView-Day-3_4_null_4,NEXUS_5,1.0,en]","ui_S_t[f.roomlist.impl.components_RoomListContentView_null_RoomListContentView-Night-3_5_null_4,NEXUS_5,1.0,en]",19860,],
+["ui_S_t[f.roomlist.impl.filters_RoomListFiltersView_null_RoomListFiltersView-Day-8_9_null_0,NEXUS_5,1.0,en]","ui_S_t[f.roomlist.impl.filters_RoomListFiltersView_null_RoomListFiltersView-Night-8_10_null_0,NEXUS_5,1.0,en]",19860,],
+["ui_S_t[f.roomlist.impl.filters_RoomListFiltersView_null_RoomListFiltersView-Day-8_9_null_1,NEXUS_5,1.0,en]","ui_S_t[f.roomlist.impl.filters_RoomListFiltersView_null_RoomListFiltersView-Night-8_10_null_1,NEXUS_5,1.0,en]",19860,],
+["ui_S_t[f.roomlist.impl_RoomListModalBottomSheetContent_null_RoomListModalBottomSheetContent-Day-0_1_null_0,NEXUS_5,1.0,en]","ui_S_t[f.roomlist.impl_RoomListModalBottomSheetContent_null_RoomListModalBottomSheetContent-Night-0_2_null_0,NEXUS_5,1.0,en]",19860,],
+["ui_S_t[f.roomlist.impl_RoomListModalBottomSheetContent_null_RoomListModalBottomSheetContent-Day-0_1_null_1,NEXUS_5,1.0,en]","ui_S_t[f.roomlist.impl_RoomListModalBottomSheetContent_null_RoomListModalBottomSheetContent-Night-0_2_null_1,NEXUS_5,1.0,en]",19860,],
+["ui_S_t[f.roomlist.impl_RoomListModalBottomSheetContent_null_RoomListModalBottomSheetContent-Day-0_1_null_2,NEXUS_5,1.0,en]","ui_S_t[f.roomlist.impl_RoomListModalBottomSheetContent_null_RoomListModalBottomSheetContent-Night-0_2_null_2,NEXUS_5,1.0,en]",19860,],
["ui_S_t[f.roomlist.impl.search_RoomListSearchContent_null_RoomListSearchContent-Day-10_11_null_0,NEXUS_5,1.0,en]","ui_S_t[f.roomlist.impl.search_RoomListSearchContent_null_RoomListSearchContent-Night-10_12_null_0,NEXUS_5,1.0,en]",0,],
-["ui_S_t[f.roomlist.impl.search_RoomListSearchContent_null_RoomListSearchContent-Day-10_11_null_1,NEXUS_5,1.0,en]","ui_S_t[f.roomlist.impl.search_RoomListSearchContent_null_RoomListSearchContent-Night-10_12_null_1,NEXUS_5,1.0,en]",19846,],
-["ui_S_t[f.roomlist.impl.search_RoomListSearchContent_null_RoomListSearchContent-Day-10_11_null_2,NEXUS_5,1.0,en]","ui_S_t[f.roomlist.impl.search_RoomListSearchContent_null_RoomListSearchContent-Night-10_12_null_2,NEXUS_5,1.0,en]",19846,],
-["ui_S_t[f.roomlist.impl_RoomListView_null_RoomListView-Day-1_2_null_0,NEXUS_5,1.0,en]","ui_S_t[f.roomlist.impl_RoomListView_null_RoomListView-Night-1_3_null_0,NEXUS_5,1.0,en]",19846,],
-["ui_S_t[f.roomlist.impl_RoomListView_null_RoomListView-Day-1_2_null_1,NEXUS_5,1.0,en]","ui_S_t[f.roomlist.impl_RoomListView_null_RoomListView-Night-1_3_null_1,NEXUS_5,1.0,en]",19846,],
+["ui_S_t[f.roomlist.impl.search_RoomListSearchContent_null_RoomListSearchContent-Day-10_11_null_1,NEXUS_5,1.0,en]","ui_S_t[f.roomlist.impl.search_RoomListSearchContent_null_RoomListSearchContent-Night-10_12_null_1,NEXUS_5,1.0,en]",19860,],
+["ui_S_t[f.roomlist.impl.search_RoomListSearchContent_null_RoomListSearchContent-Day-10_11_null_2,NEXUS_5,1.0,en]","ui_S_t[f.roomlist.impl.search_RoomListSearchContent_null_RoomListSearchContent-Night-10_12_null_2,NEXUS_5,1.0,en]",19860,],
+["ui_S_t[f.roomlist.impl_RoomListView_null_RoomListView-Day-1_2_null_0,NEXUS_5,1.0,en]","ui_S_t[f.roomlist.impl_RoomListView_null_RoomListView-Night-1_3_null_0,NEXUS_5,1.0,en]",19860,],
+["ui_S_t[f.roomlist.impl_RoomListView_null_RoomListView-Day-1_2_null_1,NEXUS_5,1.0,en]","ui_S_t[f.roomlist.impl_RoomListView_null_RoomListView-Night-1_3_null_1,NEXUS_5,1.0,en]",19860,],
["ui_S_t[f.roomlist.impl_RoomListView_null_RoomListView-Day-1_2_null_10,NEXUS_5,1.0,en]","ui_S_t[f.roomlist.impl_RoomListView_null_RoomListView-Night-1_3_null_10,NEXUS_5,1.0,en]",0,],
-["ui_S_t[f.roomlist.impl_RoomListView_null_RoomListView-Day-1_2_null_2,NEXUS_5,1.0,en]","ui_S_t[f.roomlist.impl_RoomListView_null_RoomListView-Night-1_3_null_2,NEXUS_5,1.0,en]",19846,],
-["ui_S_t[f.roomlist.impl_RoomListView_null_RoomListView-Day-1_2_null_3,NEXUS_5,1.0,en]","ui_S_t[f.roomlist.impl_RoomListView_null_RoomListView-Night-1_3_null_3,NEXUS_5,1.0,en]",19846,],
-["ui_S_t[f.roomlist.impl_RoomListView_null_RoomListView-Day-1_2_null_4,NEXUS_5,1.0,en]","ui_S_t[f.roomlist.impl_RoomListView_null_RoomListView-Night-1_3_null_4,NEXUS_5,1.0,en]",19846,],
-["ui_S_t[f.roomlist.impl_RoomListView_null_RoomListView-Day-1_2_null_5,NEXUS_5,1.0,en]","ui_S_t[f.roomlist.impl_RoomListView_null_RoomListView-Night-1_3_null_5,NEXUS_5,1.0,en]",19846,],
-["ui_S_t[f.roomlist.impl_RoomListView_null_RoomListView-Day-1_2_null_6,NEXUS_5,1.0,en]","ui_S_t[f.roomlist.impl_RoomListView_null_RoomListView-Night-1_3_null_6,NEXUS_5,1.0,en]",19846,],
-["ui_S_t[f.roomlist.impl_RoomListView_null_RoomListView-Day-1_2_null_7,NEXUS_5,1.0,en]","ui_S_t[f.roomlist.impl_RoomListView_null_RoomListView-Night-1_3_null_7,NEXUS_5,1.0,en]",19846,],
+["ui_S_t[f.roomlist.impl_RoomListView_null_RoomListView-Day-1_2_null_2,NEXUS_5,1.0,en]","ui_S_t[f.roomlist.impl_RoomListView_null_RoomListView-Night-1_3_null_2,NEXUS_5,1.0,en]",19860,],
+["ui_S_t[f.roomlist.impl_RoomListView_null_RoomListView-Day-1_2_null_3,NEXUS_5,1.0,en]","ui_S_t[f.roomlist.impl_RoomListView_null_RoomListView-Night-1_3_null_3,NEXUS_5,1.0,en]",19860,],
+["ui_S_t[f.roomlist.impl_RoomListView_null_RoomListView-Day-1_2_null_4,NEXUS_5,1.0,en]","ui_S_t[f.roomlist.impl_RoomListView_null_RoomListView-Night-1_3_null_4,NEXUS_5,1.0,en]",19860,],
+["ui_S_t[f.roomlist.impl_RoomListView_null_RoomListView-Day-1_2_null_5,NEXUS_5,1.0,en]","ui_S_t[f.roomlist.impl_RoomListView_null_RoomListView-Night-1_3_null_5,NEXUS_5,1.0,en]",19860,],
+["ui_S_t[f.roomlist.impl_RoomListView_null_RoomListView-Day-1_2_null_6,NEXUS_5,1.0,en]","ui_S_t[f.roomlist.impl_RoomListView_null_RoomListView-Night-1_3_null_6,NEXUS_5,1.0,en]",19860,],
+["ui_S_t[f.roomlist.impl_RoomListView_null_RoomListView-Day-1_2_null_7,NEXUS_5,1.0,en]","ui_S_t[f.roomlist.impl_RoomListView_null_RoomListView-Night-1_3_null_7,NEXUS_5,1.0,en]",19860,],
["ui_S_t[f.roomlist.impl_RoomListView_null_RoomListView-Day-1_2_null_8,NEXUS_5,1.0,en]","ui_S_t[f.roomlist.impl_RoomListView_null_RoomListView-Night-1_3_null_8,NEXUS_5,1.0,en]",0,],
-["ui_S_t[f.roomlist.impl_RoomListView_null_RoomListView-Day-1_2_null_9,NEXUS_5,1.0,en]","ui_S_t[f.roomlist.impl_RoomListView_null_RoomListView-Night-1_3_null_9,NEXUS_5,1.0,en]",19846,],
-["ui_S_t[f.roomdetails.impl.members_RoomMemberListViewBanned_null_RoomMemberListViewBanned-Day-3_3_null_0,NEXUS_5,1.0,en]","ui_S_t[f.roomdetails.impl.members_RoomMemberListViewBanned_null_RoomMemberListViewBanned-Night-3_4_null_0,NEXUS_5,1.0,en]",19849,],
-["ui_S_t[f.roomdetails.impl.members_RoomMemberListViewBanned_null_RoomMemberListViewBanned-Day-3_3_null_1,NEXUS_5,1.0,en]","ui_S_t[f.roomdetails.impl.members_RoomMemberListViewBanned_null_RoomMemberListViewBanned-Night-3_4_null_1,NEXUS_5,1.0,en]",19849,],
-["ui_S_t[f.roomdetails.impl.members_RoomMemberListViewBanned_null_RoomMemberListViewBanned-Day-3_3_null_2,NEXUS_5,1.0,en]","ui_S_t[f.roomdetails.impl.members_RoomMemberListViewBanned_null_RoomMemberListViewBanned-Night-3_4_null_2,NEXUS_5,1.0,en]",19849,],
-["ui_S_t[f.roomdetails.impl.members_RoomMemberListView_null_RoomMemberListView-Day-2_2_null_0,NEXUS_5,1.0,en]","ui_S_t[f.roomdetails.impl.members_RoomMemberListView_null_RoomMemberListView-Night-2_3_null_0,NEXUS_5,1.0,en]",19849,],
-["ui_S_t[f.roomdetails.impl.members_RoomMemberListView_null_RoomMemberListView-Day-2_2_null_1,NEXUS_5,1.0,en]","ui_S_t[f.roomdetails.impl.members_RoomMemberListView_null_RoomMemberListView-Night-2_3_null_1,NEXUS_5,1.0,en]",19849,],
-["ui_S_t[f.roomdetails.impl.members_RoomMemberListView_null_RoomMemberListView-Day-2_2_null_2,NEXUS_5,1.0,en]","ui_S_t[f.roomdetails.impl.members_RoomMemberListView_null_RoomMemberListView-Night-2_3_null_2,NEXUS_5,1.0,en]",19849,],
-["ui_S_t[f.roomdetails.impl.members_RoomMemberListView_null_RoomMemberListView-Day-2_2_null_3,NEXUS_5,1.0,en]","ui_S_t[f.roomdetails.impl.members_RoomMemberListView_null_RoomMemberListView-Night-2_3_null_3,NEXUS_5,1.0,en]",19849,],
-["ui_S_t[f.roomdetails.impl.members_RoomMemberListView_null_RoomMemberListView-Day-2_2_null_4,NEXUS_5,1.0,en]","ui_S_t[f.roomdetails.impl.members_RoomMemberListView_null_RoomMemberListView-Night-2_3_null_4,NEXUS_5,1.0,en]",19849,],
-["ui_S_t[f.roomdetails.impl.members_RoomMemberListView_null_RoomMemberListView-Day-2_2_null_5,NEXUS_5,1.0,en]","ui_S_t[f.roomdetails.impl.members_RoomMemberListView_null_RoomMemberListView-Night-2_3_null_5,NEXUS_5,1.0,en]",0,],
-["ui_S_t[f.roomdetails.impl.members_RoomMemberListView_null_RoomMemberListView-Day-2_2_null_6,NEXUS_5,1.0,en]","ui_S_t[f.roomdetails.impl.members_RoomMemberListView_null_RoomMemberListView-Night-2_3_null_6,NEXUS_5,1.0,en]",19849,],
-["ui_S_t[f.roomdetails.impl.members_RoomMemberListView_null_RoomMemberListView-Day-2_2_null_7,NEXUS_5,1.0,en]","ui_S_t[f.roomdetails.impl.members_RoomMemberListView_null_RoomMemberListView-Night-2_3_null_7,NEXUS_5,1.0,en]",19849,],
-["ui_S_t[f.roomdetails.impl.members.moderation_RoomMembersModerationView_null_RoomMembersModerationView-Day-4_4_null_0,NEXUS_5,1.0,en]","ui_S_t[f.roomdetails.impl.members.moderation_RoomMembersModerationView_null_RoomMembersModerationView-Night-4_5_null_0,NEXUS_5,1.0,en]",19849,],
-["ui_S_t[f.roomdetails.impl.members.moderation_RoomMembersModerationView_null_RoomMembersModerationView-Day-4_4_null_1,NEXUS_5,1.0,en]","ui_S_t[f.roomdetails.impl.members.moderation_RoomMembersModerationView_null_RoomMembersModerationView-Night-4_5_null_1,NEXUS_5,1.0,en]",19849,],
-["ui_S_t[f.roomdetails.impl.members.moderation_RoomMembersModerationView_null_RoomMembersModerationView-Day-4_4_null_2,NEXUS_5,1.0,en]","ui_S_t[f.roomdetails.impl.members.moderation_RoomMembersModerationView_null_RoomMembersModerationView-Night-4_5_null_2,NEXUS_5,1.0,en]",19849,],
-["ui_S_t[f.roomdetails.impl.members.moderation_RoomMembersModerationView_null_RoomMembersModerationView-Day-4_4_null_3,NEXUS_5,1.0,en]","ui_S_t[f.roomdetails.impl.members.moderation_RoomMembersModerationView_null_RoomMembersModerationView-Night-4_5_null_3,NEXUS_5,1.0,en]",19849,],
-["ui_S_t[f.roomdetails.impl.members.moderation_RoomMembersModerationView_null_RoomMembersModerationView-Day-4_4_null_4,NEXUS_5,1.0,en]","ui_S_t[f.roomdetails.impl.members.moderation_RoomMembersModerationView_null_RoomMembersModerationView-Night-4_5_null_4,NEXUS_5,1.0,en]",19849,],
-["ui_S_t[f.roomdetails.impl.members.moderation_RoomMembersModerationView_null_RoomMembersModerationView-Day-4_4_null_5,NEXUS_5,1.0,en]","ui_S_t[f.roomdetails.impl.members.moderation_RoomMembersModerationView_null_RoomMembersModerationView-Night-4_5_null_5,NEXUS_5,1.0,en]",19849,],
-["ui_S_t[f.roomdetails.impl.members.moderation_RoomMembersModerationView_null_RoomMembersModerationView-Day-4_4_null_6,NEXUS_5,1.0,en]","ui_S_t[f.roomdetails.impl.members.moderation_RoomMembersModerationView_null_RoomMembersModerationView-Night-4_5_null_6,NEXUS_5,1.0,en]",19849,],
-["ui_S_t[f.roomdetails.impl.members.moderation_RoomMembersModerationView_null_RoomMembersModerationView-Day-4_4_null_7,NEXUS_5,1.0,en]","ui_S_t[f.roomdetails.impl.members.moderation_RoomMembersModerationView_null_RoomMembersModerationView-Night-4_5_null_7,NEXUS_5,1.0,en]",19849,],
-["ui_S_t[f.roomdetails.impl.members.moderation_RoomMembersModerationView_null_RoomMembersModerationView-Day-4_4_null_8,NEXUS_5,1.0,en]","ui_S_t[f.roomdetails.impl.members.moderation_RoomMembersModerationView_null_RoomMembersModerationView-Night-4_5_null_8,NEXUS_5,1.0,en]",19849,],
-["ui_S_t[f.roomdetails.impl.members.moderation_RoomMembersModerationView_null_RoomMembersModerationView-Day-4_4_null_9,NEXUS_5,1.0,en]","ui_S_t[f.roomdetails.impl.members.moderation_RoomMembersModerationView_null_RoomMembersModerationView-Night-4_5_null_9,NEXUS_5,1.0,en]",0,],
-["ui_S_t[f.roomdetails.impl.notificationsettings_RoomNotificationSettingsOption_null_RoomNotificationSettingsOption-Day-5_5_null,NEXUS_5,1.0,en]","ui_S_t[f.roomdetails.impl.notificationsettings_RoomNotificationSettingsOption_null_RoomNotificationSettingsOption-Night-5_6_null,NEXUS_5,1.0,en]",19849,],
-["ui_S_t[f.roomdetails.impl.notificationsettings_RoomNotificationSettingsView_null_RoomNotificationSettingsView-Day-6_6_null_0,NEXUS_5,1.0,en]","ui_S_t[f.roomdetails.impl.notificationsettings_RoomNotificationSettingsView_null_RoomNotificationSettingsView-Night-6_7_null_0,NEXUS_5,1.0,en]",19849,],
-["ui_S_t[f.roomdetails.impl.notificationsettings_RoomNotificationSettingsView_null_RoomNotificationSettingsView-Day-6_6_null_1,NEXUS_5,1.0,en]","ui_S_t[f.roomdetails.impl.notificationsettings_RoomNotificationSettingsView_null_RoomNotificationSettingsView-Night-6_7_null_1,NEXUS_5,1.0,en]",19849,],
-["ui_S_t[f.roomdetails.impl.notificationsettings_RoomNotificationSettingsView_null_RoomNotificationSettingsView-Day-6_6_null_2,NEXUS_5,1.0,en]","ui_S_t[f.roomdetails.impl.notificationsettings_RoomNotificationSettingsView_null_RoomNotificationSettingsView-Night-6_7_null_2,NEXUS_5,1.0,en]",19849,],
-["ui_S_t[f.roomdetails.impl.notificationsettings_RoomNotificationSettingsView_null_RoomNotificationSettingsView-Day-6_6_null_3,NEXUS_5,1.0,en]","ui_S_t[f.roomdetails.impl.notificationsettings_RoomNotificationSettingsView_null_RoomNotificationSettingsView-Night-6_7_null_3,NEXUS_5,1.0,en]",19849,],
-["ui_S_t[f.roomdetails.impl.notificationsettings_RoomNotificationSettingsView_null_RoomNotificationSettingsView-Day-6_6_null_4,NEXUS_5,1.0,en]","ui_S_t[f.roomdetails.impl.notificationsettings_RoomNotificationSettingsView_null_RoomNotificationSettingsView-Night-6_7_null_4,NEXUS_5,1.0,en]",19849,],
-["ui_S_t[f.roomdetails.impl.notificationsettings_RoomNotificationSettingsView_null_RoomNotificationSettingsView-Day-6_6_null_5,NEXUS_5,1.0,en]","ui_S_t[f.roomdetails.impl.notificationsettings_RoomNotificationSettingsView_null_RoomNotificationSettingsView-Night-6_7_null_5,NEXUS_5,1.0,en]",19849,],
-["ui_S_t[f.roomdetails.impl.notificationsettings_RoomNotificationSettingsView_null_RoomNotificationSettingsView-Day-6_6_null_6,NEXUS_5,1.0,en]","ui_S_t[f.roomdetails.impl.notificationsettings_RoomNotificationSettingsView_null_RoomNotificationSettingsView-Night-6_7_null_6,NEXUS_5,1.0,en]",19849,],
+["ui_S_t[f.roomlist.impl_RoomListView_null_RoomListView-Day-1_2_null_9,NEXUS_5,1.0,en]","ui_S_t[f.roomlist.impl_RoomListView_null_RoomListView-Night-1_3_null_9,NEXUS_5,1.0,en]",19860,],
+["ui_S_t[f.roomdetails.impl.members_RoomMemberListViewBanned_null_RoomMemberListViewBanned-Day-6_6_null_0,NEXUS_5,1.0,en]","ui_S_t[f.roomdetails.impl.members_RoomMemberListViewBanned_null_RoomMemberListViewBanned-Night-6_7_null_0,NEXUS_5,1.0,en]",19860,],
+["ui_S_t[f.roomdetails.impl.members_RoomMemberListViewBanned_null_RoomMemberListViewBanned-Day-6_6_null_1,NEXUS_5,1.0,en]","ui_S_t[f.roomdetails.impl.members_RoomMemberListViewBanned_null_RoomMemberListViewBanned-Night-6_7_null_1,NEXUS_5,1.0,en]",19860,],
+["ui_S_t[f.roomdetails.impl.members_RoomMemberListViewBanned_null_RoomMemberListViewBanned-Day-6_6_null_2,NEXUS_5,1.0,en]","ui_S_t[f.roomdetails.impl.members_RoomMemberListViewBanned_null_RoomMemberListViewBanned-Night-6_7_null_2,NEXUS_5,1.0,en]",19860,],
+["ui_S_t[f.roomdetails.impl.members_RoomMemberListView_null_RoomMemberListView-Day-5_5_null_0,NEXUS_5,1.0,en]","ui_S_t[f.roomdetails.impl.members_RoomMemberListView_null_RoomMemberListView-Night-5_6_null_0,NEXUS_5,1.0,en]",19860,],
+["ui_S_t[f.roomdetails.impl.members_RoomMemberListView_null_RoomMemberListView-Day-5_5_null_1,NEXUS_5,1.0,en]","ui_S_t[f.roomdetails.impl.members_RoomMemberListView_null_RoomMemberListView-Night-5_6_null_1,NEXUS_5,1.0,en]",19860,],
+["ui_S_t[f.roomdetails.impl.members_RoomMemberListView_null_RoomMemberListView-Day-5_5_null_2,NEXUS_5,1.0,en]","ui_S_t[f.roomdetails.impl.members_RoomMemberListView_null_RoomMemberListView-Night-5_6_null_2,NEXUS_5,1.0,en]",19860,],
+["ui_S_t[f.roomdetails.impl.members_RoomMemberListView_null_RoomMemberListView-Day-5_5_null_3,NEXUS_5,1.0,en]","ui_S_t[f.roomdetails.impl.members_RoomMemberListView_null_RoomMemberListView-Night-5_6_null_3,NEXUS_5,1.0,en]",19860,],
+["ui_S_t[f.roomdetails.impl.members_RoomMemberListView_null_RoomMemberListView-Day-5_5_null_4,NEXUS_5,1.0,en]","ui_S_t[f.roomdetails.impl.members_RoomMemberListView_null_RoomMemberListView-Night-5_6_null_4,NEXUS_5,1.0,en]",19860,],
+["ui_S_t[f.roomdetails.impl.members_RoomMemberListView_null_RoomMemberListView-Day-5_5_null_5,NEXUS_5,1.0,en]","ui_S_t[f.roomdetails.impl.members_RoomMemberListView_null_RoomMemberListView-Night-5_6_null_5,NEXUS_5,1.0,en]",0,],
+["ui_S_t[f.roomdetails.impl.members_RoomMemberListView_null_RoomMemberListView-Day-5_5_null_6,NEXUS_5,1.0,en]","ui_S_t[f.roomdetails.impl.members_RoomMemberListView_null_RoomMemberListView-Night-5_6_null_6,NEXUS_5,1.0,en]",19860,],
+["ui_S_t[f.roomdetails.impl.members_RoomMemberListView_null_RoomMemberListView-Day-5_5_null_7,NEXUS_5,1.0,en]","ui_S_t[f.roomdetails.impl.members_RoomMemberListView_null_RoomMemberListView-Night-5_6_null_7,NEXUS_5,1.0,en]",19860,],
+["ui_S_t[f.roomdetails.impl.members.moderation_RoomMembersModerationView_null_RoomMembersModerationView-Day-7_7_null_0,NEXUS_5,1.0,en]","ui_S_t[f.roomdetails.impl.members.moderation_RoomMembersModerationView_null_RoomMembersModerationView-Night-7_8_null_0,NEXUS_5,1.0,en]",19860,],
+["ui_S_t[f.roomdetails.impl.members.moderation_RoomMembersModerationView_null_RoomMembersModerationView-Day-7_7_null_1,NEXUS_5,1.0,en]","ui_S_t[f.roomdetails.impl.members.moderation_RoomMembersModerationView_null_RoomMembersModerationView-Night-7_8_null_1,NEXUS_5,1.0,en]",19860,],
+["ui_S_t[f.roomdetails.impl.members.moderation_RoomMembersModerationView_null_RoomMembersModerationView-Day-7_7_null_2,NEXUS_5,1.0,en]","ui_S_t[f.roomdetails.impl.members.moderation_RoomMembersModerationView_null_RoomMembersModerationView-Night-7_8_null_2,NEXUS_5,1.0,en]",19860,],
+["ui_S_t[f.roomdetails.impl.members.moderation_RoomMembersModerationView_null_RoomMembersModerationView-Day-7_7_null_3,NEXUS_5,1.0,en]","ui_S_t[f.roomdetails.impl.members.moderation_RoomMembersModerationView_null_RoomMembersModerationView-Night-7_8_null_3,NEXUS_5,1.0,en]",19860,],
+["ui_S_t[f.roomdetails.impl.members.moderation_RoomMembersModerationView_null_RoomMembersModerationView-Day-7_7_null_4,NEXUS_5,1.0,en]","ui_S_t[f.roomdetails.impl.members.moderation_RoomMembersModerationView_null_RoomMembersModerationView-Night-7_8_null_4,NEXUS_5,1.0,en]",19860,],
+["ui_S_t[f.roomdetails.impl.members.moderation_RoomMembersModerationView_null_RoomMembersModerationView-Day-7_7_null_5,NEXUS_5,1.0,en]","ui_S_t[f.roomdetails.impl.members.moderation_RoomMembersModerationView_null_RoomMembersModerationView-Night-7_8_null_5,NEXUS_5,1.0,en]",19860,],
+["ui_S_t[f.roomdetails.impl.members.moderation_RoomMembersModerationView_null_RoomMembersModerationView-Day-7_7_null_6,NEXUS_5,1.0,en]","ui_S_t[f.roomdetails.impl.members.moderation_RoomMembersModerationView_null_RoomMembersModerationView-Night-7_8_null_6,NEXUS_5,1.0,en]",19860,],
+["ui_S_t[f.roomdetails.impl.members.moderation_RoomMembersModerationView_null_RoomMembersModerationView-Day-7_7_null_7,NEXUS_5,1.0,en]","ui_S_t[f.roomdetails.impl.members.moderation_RoomMembersModerationView_null_RoomMembersModerationView-Night-7_8_null_7,NEXUS_5,1.0,en]",19860,],
+["ui_S_t[f.roomdetails.impl.members.moderation_RoomMembersModerationView_null_RoomMembersModerationView-Day-7_7_null_8,NEXUS_5,1.0,en]","ui_S_t[f.roomdetails.impl.members.moderation_RoomMembersModerationView_null_RoomMembersModerationView-Night-7_8_null_8,NEXUS_5,1.0,en]",19860,],
+["ui_S_t[f.roomdetails.impl.members.moderation_RoomMembersModerationView_null_RoomMembersModerationView-Day-7_7_null_9,NEXUS_5,1.0,en]","ui_S_t[f.roomdetails.impl.members.moderation_RoomMembersModerationView_null_RoomMembersModerationView-Night-7_8_null_9,NEXUS_5,1.0,en]",0,],
+["ui_S_t[f.roomdetails.impl.notificationsettings_RoomNotificationSettingsOption_null_RoomNotificationSettingsOption-Day-8_8_null,NEXUS_5,1.0,en]","ui_S_t[f.roomdetails.impl.notificationsettings_RoomNotificationSettingsOption_null_RoomNotificationSettingsOption-Night-8_9_null,NEXUS_5,1.0,en]",19860,],
+["ui_S_t[f.roomdetails.impl.notificationsettings_RoomNotificationSettingsView_null_RoomNotificationSettingsView-Day-9_9_null_0,NEXUS_5,1.0,en]","ui_S_t[f.roomdetails.impl.notificationsettings_RoomNotificationSettingsView_null_RoomNotificationSettingsView-Night-9_10_null_0,NEXUS_5,1.0,en]",19860,],
+["ui_S_t[f.roomdetails.impl.notificationsettings_RoomNotificationSettingsView_null_RoomNotificationSettingsView-Day-9_9_null_1,NEXUS_5,1.0,en]","ui_S_t[f.roomdetails.impl.notificationsettings_RoomNotificationSettingsView_null_RoomNotificationSettingsView-Night-9_10_null_1,NEXUS_5,1.0,en]",19860,],
+["ui_S_t[f.roomdetails.impl.notificationsettings_RoomNotificationSettingsView_null_RoomNotificationSettingsView-Day-9_9_null_2,NEXUS_5,1.0,en]","ui_S_t[f.roomdetails.impl.notificationsettings_RoomNotificationSettingsView_null_RoomNotificationSettingsView-Night-9_10_null_2,NEXUS_5,1.0,en]",19860,],
+["ui_S_t[f.roomdetails.impl.notificationsettings_RoomNotificationSettingsView_null_RoomNotificationSettingsView-Day-9_9_null_3,NEXUS_5,1.0,en]","ui_S_t[f.roomdetails.impl.notificationsettings_RoomNotificationSettingsView_null_RoomNotificationSettingsView-Night-9_10_null_3,NEXUS_5,1.0,en]",19860,],
+["ui_S_t[f.roomdetails.impl.notificationsettings_RoomNotificationSettingsView_null_RoomNotificationSettingsView-Day-9_9_null_4,NEXUS_5,1.0,en]","ui_S_t[f.roomdetails.impl.notificationsettings_RoomNotificationSettingsView_null_RoomNotificationSettingsView-Night-9_10_null_4,NEXUS_5,1.0,en]",19860,],
+["ui_S_t[f.roomdetails.impl.notificationsettings_RoomNotificationSettingsView_null_RoomNotificationSettingsView-Day-9_9_null_5,NEXUS_5,1.0,en]","ui_S_t[f.roomdetails.impl.notificationsettings_RoomNotificationSettingsView_null_RoomNotificationSettingsView-Night-9_10_null_5,NEXUS_5,1.0,en]",19860,],
+["ui_S_t[f.roomdetails.impl.notificationsettings_RoomNotificationSettingsView_null_RoomNotificationSettingsView-Day-9_9_null_6,NEXUS_5,1.0,en]","ui_S_t[f.roomdetails.impl.notificationsettings_RoomNotificationSettingsView_null_RoomNotificationSettingsView-Night-9_10_null_6,NEXUS_5,1.0,en]",19860,],
["ui_S_t[l.designsystem.atomic.molecules_RoomPreviewMembersCountMolecule_null_RoomPreviewMembersCountMolecule-Day_0_null,NEXUS_5,1.0,en]","ui_S_t[l.designsystem.atomic.molecules_RoomPreviewMembersCountMolecule_null_RoomPreviewMembersCountMolecule-Night_1_null,NEXUS_5,1.0,en]",0,],
-["ui_S_t[f.createroom.impl.components_RoomPrivacyOption_null_RoomPrivacyOption-Day-1_2_null,NEXUS_5,1.0,en]","ui_S_t[f.createroom.impl.components_RoomPrivacyOption_null_RoomPrivacyOption-Night-1_3_null,NEXUS_5,1.0,en]",19846,],
-["ui_S_t[l.roomselect.impl_RoomSelectView_null_RoomSelectView-Day-0_1_null_0,NEXUS_5,1.0,en]","ui_S_t[l.roomselect.impl_RoomSelectView_null_RoomSelectView-Night-0_2_null_0,NEXUS_5,1.0,en]",19846,],
-["ui_S_t[l.roomselect.impl_RoomSelectView_null_RoomSelectView-Day-0_1_null_1,NEXUS_5,1.0,en]","ui_S_t[l.roomselect.impl_RoomSelectView_null_RoomSelectView-Night-0_2_null_1,NEXUS_5,1.0,en]",19846,],
-["ui_S_t[l.roomselect.impl_RoomSelectView_null_RoomSelectView-Day-0_1_null_2,NEXUS_5,1.0,en]","ui_S_t[l.roomselect.impl_RoomSelectView_null_RoomSelectView-Night-0_2_null_2,NEXUS_5,1.0,en]",19846,],
-["ui_S_t[l.roomselect.impl_RoomSelectView_null_RoomSelectView-Day-0_1_null_3,NEXUS_5,1.0,en]","ui_S_t[l.roomselect.impl_RoomSelectView_null_RoomSelectView-Night-0_2_null_3,NEXUS_5,1.0,en]",19846,],
-["ui_S_t[l.roomselect.impl_RoomSelectView_null_RoomSelectView-Day-0_1_null_4,NEXUS_5,1.0,en]","ui_S_t[l.roomselect.impl_RoomSelectView_null_RoomSelectView-Night-0_2_null_4,NEXUS_5,1.0,en]",19846,],
+["ui_S_t[f.createroom.impl.components_RoomPrivacyOption_null_RoomPrivacyOption-Day-1_2_null,NEXUS_5,1.0,en]","ui_S_t[f.createroom.impl.components_RoomPrivacyOption_null_RoomPrivacyOption-Night-1_3_null,NEXUS_5,1.0,en]",19860,],
+["ui_S_t[l.roomselect.impl_RoomSelectView_null_RoomSelectView-Day-0_1_null_0,NEXUS_5,1.0,en]","ui_S_t[l.roomselect.impl_RoomSelectView_null_RoomSelectView-Night-0_2_null_0,NEXUS_5,1.0,en]",19860,],
+["ui_S_t[l.roomselect.impl_RoomSelectView_null_RoomSelectView-Day-0_1_null_1,NEXUS_5,1.0,en]","ui_S_t[l.roomselect.impl_RoomSelectView_null_RoomSelectView-Night-0_2_null_1,NEXUS_5,1.0,en]",19860,],
+["ui_S_t[l.roomselect.impl_RoomSelectView_null_RoomSelectView-Day-0_1_null_2,NEXUS_5,1.0,en]","ui_S_t[l.roomselect.impl_RoomSelectView_null_RoomSelectView-Night-0_2_null_2,NEXUS_5,1.0,en]",19860,],
+["ui_S_t[l.roomselect.impl_RoomSelectView_null_RoomSelectView-Day-0_1_null_3,NEXUS_5,1.0,en]","ui_S_t[l.roomselect.impl_RoomSelectView_null_RoomSelectView-Night-0_2_null_3,NEXUS_5,1.0,en]",19860,],
+["ui_S_t[l.roomselect.impl_RoomSelectView_null_RoomSelectView-Day-0_1_null_4,NEXUS_5,1.0,en]","ui_S_t[l.roomselect.impl_RoomSelectView_null_RoomSelectView-Night-0_2_null_4,NEXUS_5,1.0,en]",19860,],
["ui_S_t[f.roomlist.impl.components_RoomSummaryPlaceholderRow_null_RoomSummaryPlaceholderRow-Day-6_7_null,NEXUS_5,1.0,en]","ui_S_t[f.roomlist.impl.components_RoomSummaryPlaceholderRow_null_RoomSummaryPlaceholderRow-Night-6_8_null,NEXUS_5,1.0,en]",0,],
["ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Day-7_8_null_0,NEXUS_5,1.0,en]","ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Night-7_9_null_0,NEXUS_5,1.0,en]",0,],
["ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Day-7_8_null_1,NEXUS_5,1.0,en]","ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Night-7_9_null_1,NEXUS_5,1.0,en]",0,],
@@ -685,7 +693,7 @@ export const screenshots = [
["ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Day-7_8_null_17,NEXUS_5,1.0,en]","ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Night-7_9_null_17,NEXUS_5,1.0,en]",0,],
["ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Day-7_8_null_18,NEXUS_5,1.0,en]","ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Night-7_9_null_18,NEXUS_5,1.0,en]",0,],
["ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Day-7_8_null_19,NEXUS_5,1.0,en]","ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Night-7_9_null_19,NEXUS_5,1.0,en]",0,],
-["ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Day-7_8_null_2,NEXUS_5,1.0,en]","ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Night-7_9_null_2,NEXUS_5,1.0,en]",19846,],
+["ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Day-7_8_null_2,NEXUS_5,1.0,en]","ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Night-7_9_null_2,NEXUS_5,1.0,en]",19860,],
["ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Day-7_8_null_20,NEXUS_5,1.0,en]","ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Night-7_9_null_20,NEXUS_5,1.0,en]",0,],
["ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Day-7_8_null_21,NEXUS_5,1.0,en]","ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Night-7_9_null_21,NEXUS_5,1.0,en]",0,],
["ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Day-7_8_null_22,NEXUS_5,1.0,en]","ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Night-7_9_null_22,NEXUS_5,1.0,en]",0,],
@@ -695,72 +703,72 @@ export const screenshots = [
["ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Day-7_8_null_26,NEXUS_5,1.0,en]","ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Night-7_9_null_26,NEXUS_5,1.0,en]",0,],
["ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Day-7_8_null_27,NEXUS_5,1.0,en]","ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Night-7_9_null_27,NEXUS_5,1.0,en]",0,],
["ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Day-7_8_null_28,NEXUS_5,1.0,en]","ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Night-7_9_null_28,NEXUS_5,1.0,en]",0,],
-["ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Day-7_8_null_29,NEXUS_5,1.0,en]","ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Night-7_9_null_29,NEXUS_5,1.0,en]",19846,],
+["ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Day-7_8_null_29,NEXUS_5,1.0,en]","ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Night-7_9_null_29,NEXUS_5,1.0,en]",19860,],
["ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Day-7_8_null_3,NEXUS_5,1.0,en]","ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Night-7_9_null_3,NEXUS_5,1.0,en]",0,],
-["ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Day-7_8_null_30,NEXUS_5,1.0,en]","ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Night-7_9_null_30,NEXUS_5,1.0,en]",19846,],
-["ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Day-7_8_null_31,NEXUS_5,1.0,en]","ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Night-7_9_null_31,NEXUS_5,1.0,en]",19846,],
+["ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Day-7_8_null_30,NEXUS_5,1.0,en]","ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Night-7_9_null_30,NEXUS_5,1.0,en]",19860,],
+["ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Day-7_8_null_31,NEXUS_5,1.0,en]","ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Night-7_9_null_31,NEXUS_5,1.0,en]",19860,],
["ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Day-7_8_null_4,NEXUS_5,1.0,en]","ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Night-7_9_null_4,NEXUS_5,1.0,en]",0,],
["ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Day-7_8_null_5,NEXUS_5,1.0,en]","ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Night-7_9_null_5,NEXUS_5,1.0,en]",0,],
["ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Day-7_8_null_6,NEXUS_5,1.0,en]","ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Night-7_9_null_6,NEXUS_5,1.0,en]",0,],
["ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Day-7_8_null_7,NEXUS_5,1.0,en]","ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Night-7_9_null_7,NEXUS_5,1.0,en]",0,],
["ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Day-7_8_null_8,NEXUS_5,1.0,en]","ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Night-7_9_null_8,NEXUS_5,1.0,en]",0,],
["ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Day-7_8_null_9,NEXUS_5,1.0,en]","ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Night-7_9_null_9,NEXUS_5,1.0,en]",0,],
-["ui_S_t[appnav.root_RootView_null_RootView-Day-3_3_null_0,NEXUS_5,1.0,en]","ui_S_t[appnav.root_RootView_null_RootView-Night-3_4_null_0,NEXUS_5,1.0,en]",19846,],
-["ui_S_t[appnav.root_RootView_null_RootView-Day-3_3_null_1,NEXUS_5,1.0,en]","ui_S_t[appnav.root_RootView_null_RootView-Night-3_4_null_1,NEXUS_5,1.0,en]",19846,],
-["ui_S_t[appnav.root_RootView_null_RootView-Day-3_3_null_2,NEXUS_5,1.0,en]","ui_S_t[appnav.root_RootView_null_RootView-Night-3_4_null_2,NEXUS_5,1.0,en]",19846,],
+["ui_S_t[appnav.root_RootView_null_RootView-Day-3_3_null_0,NEXUS_5,1.0,en]","ui_S_t[appnav.root_RootView_null_RootView-Night-3_4_null_0,NEXUS_5,1.0,en]",19860,],
+["ui_S_t[appnav.root_RootView_null_RootView-Day-3_3_null_1,NEXUS_5,1.0,en]","ui_S_t[appnav.root_RootView_null_RootView-Night-3_4_null_1,NEXUS_5,1.0,en]",19860,],
+["ui_S_t[appnav.root_RootView_null_RootView-Day-3_3_null_2,NEXUS_5,1.0,en]","ui_S_t[appnav.root_RootView_null_RootView-Night-3_4_null_2,NEXUS_5,1.0,en]",19860,],
["ui_S_t[l.designsystem.atomic.atoms_RoundedIconAtom_null_RoundedIconAtom-Day_0_null,NEXUS_5,1.0,en]","ui_S_t[l.designsystem.atomic.atoms_RoundedIconAtom_null_RoundedIconAtom-Night_1_null,NEXUS_5,1.0,en]",0,],
-["ui_S_t[f.verifysession.impl.emoji_SasEmojis_null_SasEmojis-Day-1_2_null,NEXUS_5,1.0,en]","ui_S_t[f.verifysession.impl.emoji_SasEmojis_null_SasEmojis-Night-1_3_null,NEXUS_5,1.0,en]",19846,],
-["ui_S_t[f.login.impl.screens.searchaccountprovider_SearchAccountProviderView_null_SearchAccountProviderView-Day-7_8_null_0,NEXUS_5,1.0,en]","ui_S_t[f.login.impl.screens.searchaccountprovider_SearchAccountProviderView_null_SearchAccountProviderView-Night-7_9_null_0,NEXUS_5,1.0,en]",19846,],
-["ui_S_t[f.login.impl.screens.searchaccountprovider_SearchAccountProviderView_null_SearchAccountProviderView-Day-7_8_null_1,NEXUS_5,1.0,en]","ui_S_t[f.login.impl.screens.searchaccountprovider_SearchAccountProviderView_null_SearchAccountProviderView-Night-7_9_null_1,NEXUS_5,1.0,en]",19846,],
+["ui_S_t[f.verifysession.impl.emoji_SasEmojis_null_SasEmojis-Day-1_2_null,NEXUS_5,1.0,en]","ui_S_t[f.verifysession.impl.emoji_SasEmojis_null_SasEmojis-Night-1_3_null,NEXUS_5,1.0,en]",19860,],
+["ui_S_t[f.login.impl.screens.searchaccountprovider_SearchAccountProviderView_null_SearchAccountProviderView-Day-7_8_null_0,NEXUS_5,1.0,en]","ui_S_t[f.login.impl.screens.searchaccountprovider_SearchAccountProviderView_null_SearchAccountProviderView-Night-7_9_null_0,NEXUS_5,1.0,en]",19860,],
+["ui_S_t[f.login.impl.screens.searchaccountprovider_SearchAccountProviderView_null_SearchAccountProviderView-Day-7_8_null_1,NEXUS_5,1.0,en]","ui_S_t[f.login.impl.screens.searchaccountprovider_SearchAccountProviderView_null_SearchAccountProviderView-Night-7_9_null_1,NEXUS_5,1.0,en]",19860,],
["ui_S_t[l.designsystem.theme.components_SearchBarActiveNoneQuery_null_Searchviews_SearchBarActiveNoneQuery_0_null,NEXUS_5,1.0,en]","",0,],
["ui_S_t[l.designsystem.theme.components_SearchBarActiveWithContent_null_Searchviews_SearchBarActiveWithContent_0_null,NEXUS_5,1.0,en]","",0,],
-["ui_S_t[l.designsystem.theme.components_SearchBarActiveWithNoResults_null_Searchviews_SearchBarActiveWithNoResults_0_null,NEXUS_5,1.0,en]","",19846,],
+["ui_S_t[l.designsystem.theme.components_SearchBarActiveWithNoResults_null_Searchviews_SearchBarActiveWithNoResults_0_null,NEXUS_5,1.0,en]","",19860,],
["ui_S_t[l.designsystem.theme.components_SearchBarActiveWithQueryNoBackButton_null_Searchviews_SearchBarActiveWithQueryNoBackButton_0_null,NEXUS_5,1.0,en]","",0,],
["ui_S_t[l.designsystem.theme.components_SearchBarActiveWithQuery_null_Searchviews_SearchBarActiveWithQuery_0_null,NEXUS_5,1.0,en]","",0,],
["ui_S_t[l.designsystem.theme.components_SearchBarInactive_null_Searchviews_SearchBarInactive_0_null,NEXUS_5,1.0,en]","",0,],
-["ui_S_t[f.createroom.impl.components_SearchMultipleUsersResultItem_null_SearchMultipleUsersResultItem_0_null,NEXUS_5,1.0,en]","",19846,],
-["ui_S_t[f.createroom.impl.components_SearchSingleUserResultItem_null_SearchSingleUserResultItem_0_null,NEXUS_5,1.0,en]","",19846,],
-["ui_S_t[f.securebackup.impl.disable_SecureBackupDisableView_null_SecureBackupDisableView-Day-1_2_null_0,NEXUS_5,1.0,en]","ui_S_t[f.securebackup.impl.disable_SecureBackupDisableView_null_SecureBackupDisableView-Night-1_3_null_0,NEXUS_5,1.0,en]",19846,],
-["ui_S_t[f.securebackup.impl.disable_SecureBackupDisableView_null_SecureBackupDisableView-Day-1_2_null_1,NEXUS_5,1.0,en]","ui_S_t[f.securebackup.impl.disable_SecureBackupDisableView_null_SecureBackupDisableView-Night-1_3_null_1,NEXUS_5,1.0,en]",19846,],
-["ui_S_t[f.securebackup.impl.disable_SecureBackupDisableView_null_SecureBackupDisableView-Day-1_2_null_2,NEXUS_5,1.0,en]","ui_S_t[f.securebackup.impl.disable_SecureBackupDisableView_null_SecureBackupDisableView-Night-1_3_null_2,NEXUS_5,1.0,en]",19846,],
-["ui_S_t[f.securebackup.impl.disable_SecureBackupDisableView_null_SecureBackupDisableView-Day-1_2_null_3,NEXUS_5,1.0,en]","ui_S_t[f.securebackup.impl.disable_SecureBackupDisableView_null_SecureBackupDisableView-Night-1_3_null_3,NEXUS_5,1.0,en]",19846,],
-["ui_S_t[f.securebackup.impl.enable_SecureBackupEnableView_null_SecureBackupEnableView-Day-2_3_null_0,NEXUS_5,1.0,en]","ui_S_t[f.securebackup.impl.enable_SecureBackupEnableView_null_SecureBackupEnableView-Night-2_4_null_0,NEXUS_5,1.0,en]",19846,],
-["ui_S_t[f.securebackup.impl.enable_SecureBackupEnableView_null_SecureBackupEnableView-Day-2_3_null_1,NEXUS_5,1.0,en]","ui_S_t[f.securebackup.impl.enable_SecureBackupEnableView_null_SecureBackupEnableView-Night-2_4_null_1,NEXUS_5,1.0,en]",19846,],
-["ui_S_t[f.securebackup.impl.enable_SecureBackupEnableView_null_SecureBackupEnableView-Day-2_3_null_2,NEXUS_5,1.0,en]","ui_S_t[f.securebackup.impl.enable_SecureBackupEnableView_null_SecureBackupEnableView-Night-2_4_null_2,NEXUS_5,1.0,en]",19846,],
-["ui_S_t[f.securebackup.impl.enter_SecureBackupEnterRecoveryKeyView_null_SecureBackupEnterRecoveryKeyView-Day-3_4_null_0,NEXUS_5,1.0,en]","ui_S_t[f.securebackup.impl.enter_SecureBackupEnterRecoveryKeyView_null_SecureBackupEnterRecoveryKeyView-Night-3_5_null_0,NEXUS_5,1.0,en]",19846,],
-["ui_S_t[f.securebackup.impl.enter_SecureBackupEnterRecoveryKeyView_null_SecureBackupEnterRecoveryKeyView-Day-3_4_null_1,NEXUS_5,1.0,en]","ui_S_t[f.securebackup.impl.enter_SecureBackupEnterRecoveryKeyView_null_SecureBackupEnterRecoveryKeyView-Night-3_5_null_1,NEXUS_5,1.0,en]",19846,],
-["ui_S_t[f.securebackup.impl.enter_SecureBackupEnterRecoveryKeyView_null_SecureBackupEnterRecoveryKeyView-Day-3_4_null_2,NEXUS_5,1.0,en]","ui_S_t[f.securebackup.impl.enter_SecureBackupEnterRecoveryKeyView_null_SecureBackupEnterRecoveryKeyView-Night-3_5_null_2,NEXUS_5,1.0,en]",19846,],
-["ui_S_t[f.securebackup.impl.enter_SecureBackupEnterRecoveryKeyView_null_SecureBackupEnterRecoveryKeyView-Day-3_4_null_3,NEXUS_5,1.0,en]","ui_S_t[f.securebackup.impl.enter_SecureBackupEnterRecoveryKeyView_null_SecureBackupEnterRecoveryKeyView-Night-3_5_null_3,NEXUS_5,1.0,en]",19846,],
-["ui_S_t[f.securebackup.impl.root_SecureBackupRootView_null_SecureBackupRootView-Day-4_5_null_0,NEXUS_5,1.0,en]","ui_S_t[f.securebackup.impl.root_SecureBackupRootView_null_SecureBackupRootView-Night-4_6_null_0,NEXUS_5,1.0,en]",19846,],
-["ui_S_t[f.securebackup.impl.root_SecureBackupRootView_null_SecureBackupRootView-Day-4_5_null_1,NEXUS_5,1.0,en]","ui_S_t[f.securebackup.impl.root_SecureBackupRootView_null_SecureBackupRootView-Night-4_6_null_1,NEXUS_5,1.0,en]",19846,],
-["ui_S_t[f.securebackup.impl.root_SecureBackupRootView_null_SecureBackupRootView-Day-4_5_null_2,NEXUS_5,1.0,en]","ui_S_t[f.securebackup.impl.root_SecureBackupRootView_null_SecureBackupRootView-Night-4_6_null_2,NEXUS_5,1.0,en]",19846,],
-["ui_S_t[f.securebackup.impl.root_SecureBackupRootView_null_SecureBackupRootView-Day-4_5_null_3,NEXUS_5,1.0,en]","ui_S_t[f.securebackup.impl.root_SecureBackupRootView_null_SecureBackupRootView-Night-4_6_null_3,NEXUS_5,1.0,en]",19846,],
-["ui_S_t[f.securebackup.impl.root_SecureBackupRootView_null_SecureBackupRootView-Day-4_5_null_4,NEXUS_5,1.0,en]","ui_S_t[f.securebackup.impl.root_SecureBackupRootView_null_SecureBackupRootView-Night-4_6_null_4,NEXUS_5,1.0,en]",19846,],
-["ui_S_t[f.securebackup.impl.root_SecureBackupRootView_null_SecureBackupRootView-Day-4_5_null_5,NEXUS_5,1.0,en]","ui_S_t[f.securebackup.impl.root_SecureBackupRootView_null_SecureBackupRootView-Night-4_6_null_5,NEXUS_5,1.0,en]",19846,],
-["ui_S_t[f.securebackup.impl.root_SecureBackupRootView_null_SecureBackupRootView-Day-4_5_null_6,NEXUS_5,1.0,en]","ui_S_t[f.securebackup.impl.root_SecureBackupRootView_null_SecureBackupRootView-Night-4_6_null_6,NEXUS_5,1.0,en]",19846,],
-["ui_S_t[f.securebackup.impl.root_SecureBackupRootView_null_SecureBackupRootView-Day-4_5_null_7,NEXUS_5,1.0,en]","ui_S_t[f.securebackup.impl.root_SecureBackupRootView_null_SecureBackupRootView-Night-4_6_null_7,NEXUS_5,1.0,en]",19846,],
-["ui_S_t[f.securebackup.impl.root_SecureBackupRootView_null_SecureBackupRootView-Day-4_5_null_8,NEXUS_5,1.0,en]","ui_S_t[f.securebackup.impl.root_SecureBackupRootView_null_SecureBackupRootView-Night-4_6_null_8,NEXUS_5,1.0,en]",19846,],
-["ui_S_t[f.securebackup.impl.setup_SecureBackupSetupViewChange_null_SecureBackupSetupViewChange-Day-6_7_null_0,NEXUS_5,1.0,en]","ui_S_t[f.securebackup.impl.setup_SecureBackupSetupViewChange_null_SecureBackupSetupViewChange-Night-6_8_null_0,NEXUS_5,1.0,en]",19846,],
-["ui_S_t[f.securebackup.impl.setup_SecureBackupSetupViewChange_null_SecureBackupSetupViewChange-Day-6_7_null_1,NEXUS_5,1.0,en]","ui_S_t[f.securebackup.impl.setup_SecureBackupSetupViewChange_null_SecureBackupSetupViewChange-Night-6_8_null_1,NEXUS_5,1.0,en]",19846,],
-["ui_S_t[f.securebackup.impl.setup_SecureBackupSetupViewChange_null_SecureBackupSetupViewChange-Day-6_7_null_2,NEXUS_5,1.0,en]","ui_S_t[f.securebackup.impl.setup_SecureBackupSetupViewChange_null_SecureBackupSetupViewChange-Night-6_8_null_2,NEXUS_5,1.0,en]",19846,],
-["ui_S_t[f.securebackup.impl.setup_SecureBackupSetupViewChange_null_SecureBackupSetupViewChange-Day-6_7_null_3,NEXUS_5,1.0,en]","ui_S_t[f.securebackup.impl.setup_SecureBackupSetupViewChange_null_SecureBackupSetupViewChange-Night-6_8_null_3,NEXUS_5,1.0,en]",19846,],
-["ui_S_t[f.securebackup.impl.setup_SecureBackupSetupViewChange_null_SecureBackupSetupViewChange-Day-6_7_null_4,NEXUS_5,1.0,en]","ui_S_t[f.securebackup.impl.setup_SecureBackupSetupViewChange_null_SecureBackupSetupViewChange-Night-6_8_null_4,NEXUS_5,1.0,en]",19846,],
-["ui_S_t[f.securebackup.impl.setup_SecureBackupSetupView_null_SecureBackupSetupView-Day-5_6_null_0,NEXUS_5,1.0,en]","ui_S_t[f.securebackup.impl.setup_SecureBackupSetupView_null_SecureBackupSetupView-Night-5_7_null_0,NEXUS_5,1.0,en]",19846,],
-["ui_S_t[f.securebackup.impl.setup_SecureBackupSetupView_null_SecureBackupSetupView-Day-5_6_null_1,NEXUS_5,1.0,en]","ui_S_t[f.securebackup.impl.setup_SecureBackupSetupView_null_SecureBackupSetupView-Night-5_7_null_1,NEXUS_5,1.0,en]",19846,],
-["ui_S_t[f.securebackup.impl.setup_SecureBackupSetupView_null_SecureBackupSetupView-Day-5_6_null_2,NEXUS_5,1.0,en]","ui_S_t[f.securebackup.impl.setup_SecureBackupSetupView_null_SecureBackupSetupView-Night-5_7_null_2,NEXUS_5,1.0,en]",19846,],
-["ui_S_t[f.securebackup.impl.setup_SecureBackupSetupView_null_SecureBackupSetupView-Day-5_6_null_3,NEXUS_5,1.0,en]","ui_S_t[f.securebackup.impl.setup_SecureBackupSetupView_null_SecureBackupSetupView-Night-5_7_null_3,NEXUS_5,1.0,en]",19846,],
-["ui_S_t[f.securebackup.impl.setup_SecureBackupSetupView_null_SecureBackupSetupView-Day-5_6_null_4,NEXUS_5,1.0,en]","ui_S_t[f.securebackup.impl.setup_SecureBackupSetupView_null_SecureBackupSetupView-Night-5_7_null_4,NEXUS_5,1.0,en]",19846,],
-["ui_S_t[l.matrix.ui.components_SelectedRoom_null_SelectedRoom-Day-6_7_null_0,NEXUS_5,1.0,en]","ui_S_t[l.matrix.ui.components_SelectedRoom_null_SelectedRoom-Night-6_8_null_0,NEXUS_5,1.0,en]",0,],
-["ui_S_t[l.matrix.ui.components_SelectedRoom_null_SelectedRoom-Day-6_7_null_1,NEXUS_5,1.0,en]","ui_S_t[l.matrix.ui.components_SelectedRoom_null_SelectedRoom-Night-6_8_null_1,NEXUS_5,1.0,en]",0,],
-["ui_S_t[l.matrix.ui.components_SelectedUserCannotRemove_null_SelectedUserCannotRemove-Day-8_9_null,NEXUS_5,1.0,en]","ui_S_t[l.matrix.ui.components_SelectedUserCannotRemove_null_SelectedUserCannotRemove-Night-8_10_null,NEXUS_5,1.0,en]",0,],
-["ui_S_t[l.matrix.ui.components_SelectedUser_null_SelectedUser-Day-7_8_null,NEXUS_5,1.0,en]","ui_S_t[l.matrix.ui.components_SelectedUser_null_SelectedUser-Night-7_9_null,NEXUS_5,1.0,en]",0,],
-["ui_S_t[l.matrix.ui.components_SelectedUsersRowList_null_SelectedUsersRowList-Day-9_10_null,NEXUS_5,1.0,en]","ui_S_t[l.matrix.ui.components_SelectedUsersRowList_null_SelectedUsersRowList-Night-9_11_null,NEXUS_5,1.0,en]",0,],
+["ui_S_t[f.createroom.impl.components_SearchMultipleUsersResultItem_null_SearchMultipleUsersResultItem_0_null,NEXUS_5,1.0,en]","",19860,],
+["ui_S_t[f.createroom.impl.components_SearchSingleUserResultItem_null_SearchSingleUserResultItem_0_null,NEXUS_5,1.0,en]","",19860,],
+["ui_S_t[f.securebackup.impl.disable_SecureBackupDisableView_null_SecureBackupDisableView-Day-1_2_null_0,NEXUS_5,1.0,en]","ui_S_t[f.securebackup.impl.disable_SecureBackupDisableView_null_SecureBackupDisableView-Night-1_3_null_0,NEXUS_5,1.0,en]",19860,],
+["ui_S_t[f.securebackup.impl.disable_SecureBackupDisableView_null_SecureBackupDisableView-Day-1_2_null_1,NEXUS_5,1.0,en]","ui_S_t[f.securebackup.impl.disable_SecureBackupDisableView_null_SecureBackupDisableView-Night-1_3_null_1,NEXUS_5,1.0,en]",19860,],
+["ui_S_t[f.securebackup.impl.disable_SecureBackupDisableView_null_SecureBackupDisableView-Day-1_2_null_2,NEXUS_5,1.0,en]","ui_S_t[f.securebackup.impl.disable_SecureBackupDisableView_null_SecureBackupDisableView-Night-1_3_null_2,NEXUS_5,1.0,en]",19860,],
+["ui_S_t[f.securebackup.impl.disable_SecureBackupDisableView_null_SecureBackupDisableView-Day-1_2_null_3,NEXUS_5,1.0,en]","ui_S_t[f.securebackup.impl.disable_SecureBackupDisableView_null_SecureBackupDisableView-Night-1_3_null_3,NEXUS_5,1.0,en]",19860,],
+["ui_S_t[f.securebackup.impl.enable_SecureBackupEnableView_null_SecureBackupEnableView-Day-2_3_null_0,NEXUS_5,1.0,en]","ui_S_t[f.securebackup.impl.enable_SecureBackupEnableView_null_SecureBackupEnableView-Night-2_4_null_0,NEXUS_5,1.0,en]",19860,],
+["ui_S_t[f.securebackup.impl.enable_SecureBackupEnableView_null_SecureBackupEnableView-Day-2_3_null_1,NEXUS_5,1.0,en]","ui_S_t[f.securebackup.impl.enable_SecureBackupEnableView_null_SecureBackupEnableView-Night-2_4_null_1,NEXUS_5,1.0,en]",19860,],
+["ui_S_t[f.securebackup.impl.enable_SecureBackupEnableView_null_SecureBackupEnableView-Day-2_3_null_2,NEXUS_5,1.0,en]","ui_S_t[f.securebackup.impl.enable_SecureBackupEnableView_null_SecureBackupEnableView-Night-2_4_null_2,NEXUS_5,1.0,en]",19860,],
+["ui_S_t[f.securebackup.impl.enter_SecureBackupEnterRecoveryKeyView_null_SecureBackupEnterRecoveryKeyView-Day-3_4_null_0,NEXUS_5,1.0,en]","ui_S_t[f.securebackup.impl.enter_SecureBackupEnterRecoveryKeyView_null_SecureBackupEnterRecoveryKeyView-Night-3_5_null_0,NEXUS_5,1.0,en]",19860,],
+["ui_S_t[f.securebackup.impl.enter_SecureBackupEnterRecoveryKeyView_null_SecureBackupEnterRecoveryKeyView-Day-3_4_null_1,NEXUS_5,1.0,en]","ui_S_t[f.securebackup.impl.enter_SecureBackupEnterRecoveryKeyView_null_SecureBackupEnterRecoveryKeyView-Night-3_5_null_1,NEXUS_5,1.0,en]",19860,],
+["ui_S_t[f.securebackup.impl.enter_SecureBackupEnterRecoveryKeyView_null_SecureBackupEnterRecoveryKeyView-Day-3_4_null_2,NEXUS_5,1.0,en]","ui_S_t[f.securebackup.impl.enter_SecureBackupEnterRecoveryKeyView_null_SecureBackupEnterRecoveryKeyView-Night-3_5_null_2,NEXUS_5,1.0,en]",19860,],
+["ui_S_t[f.securebackup.impl.enter_SecureBackupEnterRecoveryKeyView_null_SecureBackupEnterRecoveryKeyView-Day-3_4_null_3,NEXUS_5,1.0,en]","ui_S_t[f.securebackup.impl.enter_SecureBackupEnterRecoveryKeyView_null_SecureBackupEnterRecoveryKeyView-Night-3_5_null_3,NEXUS_5,1.0,en]",19860,],
+["ui_S_t[f.securebackup.impl.root_SecureBackupRootView_null_SecureBackupRootView-Day-4_5_null_0,NEXUS_5,1.0,en]","ui_S_t[f.securebackup.impl.root_SecureBackupRootView_null_SecureBackupRootView-Night-4_6_null_0,NEXUS_5,1.0,en]",19860,],
+["ui_S_t[f.securebackup.impl.root_SecureBackupRootView_null_SecureBackupRootView-Day-4_5_null_1,NEXUS_5,1.0,en]","ui_S_t[f.securebackup.impl.root_SecureBackupRootView_null_SecureBackupRootView-Night-4_6_null_1,NEXUS_5,1.0,en]",19860,],
+["ui_S_t[f.securebackup.impl.root_SecureBackupRootView_null_SecureBackupRootView-Day-4_5_null_2,NEXUS_5,1.0,en]","ui_S_t[f.securebackup.impl.root_SecureBackupRootView_null_SecureBackupRootView-Night-4_6_null_2,NEXUS_5,1.0,en]",19860,],
+["ui_S_t[f.securebackup.impl.root_SecureBackupRootView_null_SecureBackupRootView-Day-4_5_null_3,NEXUS_5,1.0,en]","ui_S_t[f.securebackup.impl.root_SecureBackupRootView_null_SecureBackupRootView-Night-4_6_null_3,NEXUS_5,1.0,en]",19860,],
+["ui_S_t[f.securebackup.impl.root_SecureBackupRootView_null_SecureBackupRootView-Day-4_5_null_4,NEXUS_5,1.0,en]","ui_S_t[f.securebackup.impl.root_SecureBackupRootView_null_SecureBackupRootView-Night-4_6_null_4,NEXUS_5,1.0,en]",19860,],
+["ui_S_t[f.securebackup.impl.root_SecureBackupRootView_null_SecureBackupRootView-Day-4_5_null_5,NEXUS_5,1.0,en]","ui_S_t[f.securebackup.impl.root_SecureBackupRootView_null_SecureBackupRootView-Night-4_6_null_5,NEXUS_5,1.0,en]",19860,],
+["ui_S_t[f.securebackup.impl.root_SecureBackupRootView_null_SecureBackupRootView-Day-4_5_null_6,NEXUS_5,1.0,en]","ui_S_t[f.securebackup.impl.root_SecureBackupRootView_null_SecureBackupRootView-Night-4_6_null_6,NEXUS_5,1.0,en]",19860,],
+["ui_S_t[f.securebackup.impl.root_SecureBackupRootView_null_SecureBackupRootView-Day-4_5_null_7,NEXUS_5,1.0,en]","ui_S_t[f.securebackup.impl.root_SecureBackupRootView_null_SecureBackupRootView-Night-4_6_null_7,NEXUS_5,1.0,en]",19860,],
+["ui_S_t[f.securebackup.impl.root_SecureBackupRootView_null_SecureBackupRootView-Day-4_5_null_8,NEXUS_5,1.0,en]","ui_S_t[f.securebackup.impl.root_SecureBackupRootView_null_SecureBackupRootView-Night-4_6_null_8,NEXUS_5,1.0,en]",19860,],
+["ui_S_t[f.securebackup.impl.setup_SecureBackupSetupViewChange_null_SecureBackupSetupViewChange-Day-6_7_null_0,NEXUS_5,1.0,en]","ui_S_t[f.securebackup.impl.setup_SecureBackupSetupViewChange_null_SecureBackupSetupViewChange-Night-6_8_null_0,NEXUS_5,1.0,en]",19860,],
+["ui_S_t[f.securebackup.impl.setup_SecureBackupSetupViewChange_null_SecureBackupSetupViewChange-Day-6_7_null_1,NEXUS_5,1.0,en]","ui_S_t[f.securebackup.impl.setup_SecureBackupSetupViewChange_null_SecureBackupSetupViewChange-Night-6_8_null_1,NEXUS_5,1.0,en]",19860,],
+["ui_S_t[f.securebackup.impl.setup_SecureBackupSetupViewChange_null_SecureBackupSetupViewChange-Day-6_7_null_2,NEXUS_5,1.0,en]","ui_S_t[f.securebackup.impl.setup_SecureBackupSetupViewChange_null_SecureBackupSetupViewChange-Night-6_8_null_2,NEXUS_5,1.0,en]",19860,],
+["ui_S_t[f.securebackup.impl.setup_SecureBackupSetupViewChange_null_SecureBackupSetupViewChange-Day-6_7_null_3,NEXUS_5,1.0,en]","ui_S_t[f.securebackup.impl.setup_SecureBackupSetupViewChange_null_SecureBackupSetupViewChange-Night-6_8_null_3,NEXUS_5,1.0,en]",19860,],
+["ui_S_t[f.securebackup.impl.setup_SecureBackupSetupViewChange_null_SecureBackupSetupViewChange-Day-6_7_null_4,NEXUS_5,1.0,en]","ui_S_t[f.securebackup.impl.setup_SecureBackupSetupViewChange_null_SecureBackupSetupViewChange-Night-6_8_null_4,NEXUS_5,1.0,en]",19860,],
+["ui_S_t[f.securebackup.impl.setup_SecureBackupSetupView_null_SecureBackupSetupView-Day-5_6_null_0,NEXUS_5,1.0,en]","ui_S_t[f.securebackup.impl.setup_SecureBackupSetupView_null_SecureBackupSetupView-Night-5_7_null_0,NEXUS_5,1.0,en]",19860,],
+["ui_S_t[f.securebackup.impl.setup_SecureBackupSetupView_null_SecureBackupSetupView-Day-5_6_null_1,NEXUS_5,1.0,en]","ui_S_t[f.securebackup.impl.setup_SecureBackupSetupView_null_SecureBackupSetupView-Night-5_7_null_1,NEXUS_5,1.0,en]",19860,],
+["ui_S_t[f.securebackup.impl.setup_SecureBackupSetupView_null_SecureBackupSetupView-Day-5_6_null_2,NEXUS_5,1.0,en]","ui_S_t[f.securebackup.impl.setup_SecureBackupSetupView_null_SecureBackupSetupView-Night-5_7_null_2,NEXUS_5,1.0,en]",19860,],
+["ui_S_t[f.securebackup.impl.setup_SecureBackupSetupView_null_SecureBackupSetupView-Day-5_6_null_3,NEXUS_5,1.0,en]","ui_S_t[f.securebackup.impl.setup_SecureBackupSetupView_null_SecureBackupSetupView-Night-5_7_null_3,NEXUS_5,1.0,en]",19860,],
+["ui_S_t[f.securebackup.impl.setup_SecureBackupSetupView_null_SecureBackupSetupView-Day-5_6_null_4,NEXUS_5,1.0,en]","ui_S_t[f.securebackup.impl.setup_SecureBackupSetupView_null_SecureBackupSetupView-Night-5_7_null_4,NEXUS_5,1.0,en]",19860,],
+["ui_S_t[l.matrix.ui.components_SelectedRoom_null_SelectedRoom-Day-7_8_null_0,NEXUS_5,1.0,en]","ui_S_t[l.matrix.ui.components_SelectedRoom_null_SelectedRoom-Night-7_9_null_0,NEXUS_5,1.0,en]",0,],
+["ui_S_t[l.matrix.ui.components_SelectedRoom_null_SelectedRoom-Day-7_8_null_1,NEXUS_5,1.0,en]","ui_S_t[l.matrix.ui.components_SelectedRoom_null_SelectedRoom-Night-7_9_null_1,NEXUS_5,1.0,en]",0,],
+["ui_S_t[l.matrix.ui.components_SelectedUserCannotRemove_null_SelectedUserCannotRemove-Day-9_10_null,NEXUS_5,1.0,en]","ui_S_t[l.matrix.ui.components_SelectedUserCannotRemove_null_SelectedUserCannotRemove-Night-9_11_null,NEXUS_5,1.0,en]",0,],
+["ui_S_t[l.matrix.ui.components_SelectedUser_null_SelectedUser-Day-8_9_null,NEXUS_5,1.0,en]","ui_S_t[l.matrix.ui.components_SelectedUser_null_SelectedUser-Night-8_10_null,NEXUS_5,1.0,en]",0,],
+["ui_S_t[l.matrix.ui.components_SelectedUsersRowList_null_SelectedUsersRowList-Day-10_11_null,NEXUS_5,1.0,en]","ui_S_t[l.matrix.ui.components_SelectedUsersRowList_null_SelectedUsersRowList-Night-10_12_null,NEXUS_5,1.0,en]",0,],
["ui_S_t[l.textcomposer.components_SendButton_null_SendButton-Day-12_13_null,NEXUS_5,1.0,en]","ui_S_t[l.textcomposer.components_SendButton_null_SendButton-Night-12_14_null,NEXUS_5,1.0,en]",0,],
-["ui_S_t[f.location.impl.send_SendLocationView_null_SendLocationView-Day-0_1_null_0,NEXUS_5,1.0,en]","ui_S_t[f.location.impl.send_SendLocationView_null_SendLocationView-Night-0_2_null_0,NEXUS_5,1.0,en]",19846,],
-["ui_S_t[f.location.impl.send_SendLocationView_null_SendLocationView-Day-0_1_null_1,NEXUS_5,1.0,en]","ui_S_t[f.location.impl.send_SendLocationView_null_SendLocationView-Night-0_2_null_1,NEXUS_5,1.0,en]",19846,],
-["ui_S_t[f.location.impl.send_SendLocationView_null_SendLocationView-Day-0_1_null_2,NEXUS_5,1.0,en]","ui_S_t[f.location.impl.send_SendLocationView_null_SendLocationView-Night-0_2_null_2,NEXUS_5,1.0,en]",19846,],
-["ui_S_t[f.location.impl.send_SendLocationView_null_SendLocationView-Day-0_1_null_3,NEXUS_5,1.0,en]","ui_S_t[f.location.impl.send_SendLocationView_null_SendLocationView-Night-0_2_null_3,NEXUS_5,1.0,en]",19846,],
-["ui_S_t[f.location.impl.send_SendLocationView_null_SendLocationView-Day-0_1_null_4,NEXUS_5,1.0,en]","ui_S_t[f.location.impl.send_SendLocationView_null_SendLocationView-Night-0_2_null_4,NEXUS_5,1.0,en]",19846,],
+["ui_S_t[f.location.impl.send_SendLocationView_null_SendLocationView-Day-0_1_null_0,NEXUS_5,1.0,en]","ui_S_t[f.location.impl.send_SendLocationView_null_SendLocationView-Night-0_2_null_0,NEXUS_5,1.0,en]",19860,],
+["ui_S_t[f.location.impl.send_SendLocationView_null_SendLocationView-Day-0_1_null_1,NEXUS_5,1.0,en]","ui_S_t[f.location.impl.send_SendLocationView_null_SendLocationView-Night-0_2_null_1,NEXUS_5,1.0,en]",19860,],
+["ui_S_t[f.location.impl.send_SendLocationView_null_SendLocationView-Day-0_1_null_2,NEXUS_5,1.0,en]","ui_S_t[f.location.impl.send_SendLocationView_null_SendLocationView-Night-0_2_null_2,NEXUS_5,1.0,en]",19860,],
+["ui_S_t[f.location.impl.send_SendLocationView_null_SendLocationView-Day-0_1_null_3,NEXUS_5,1.0,en]","ui_S_t[f.location.impl.send_SendLocationView_null_SendLocationView-Night-0_2_null_3,NEXUS_5,1.0,en]",19860,],
+["ui_S_t[f.location.impl.send_SendLocationView_null_SendLocationView-Day-0_1_null_4,NEXUS_5,1.0,en]","ui_S_t[f.location.impl.send_SendLocationView_null_SendLocationView-Night-0_2_null_4,NEXUS_5,1.0,en]",19860,],
["ui_S_t[f.messages.impl.sender_SenderName_null_SenderName-Day-8_8_null_0,NEXUS_5,1.0,en]","ui_S_t[f.messages.impl.sender_SenderName_null_SenderName-Night-8_9_null_0,NEXUS_5,1.0,en]",0,],
["ui_S_t[f.messages.impl.sender_SenderName_null_SenderName-Day-8_8_null_1,NEXUS_5,1.0,en]","ui_S_t[f.messages.impl.sender_SenderName_null_SenderName-Night-8_9_null_1,NEXUS_5,1.0,en]",0,],
["ui_S_t[f.messages.impl.sender_SenderName_null_SenderName-Day-8_8_null_2,NEXUS_5,1.0,en]","ui_S_t[f.messages.impl.sender_SenderName_null_SenderName-Night-8_9_null_2,NEXUS_5,1.0,en]",0,],
@@ -770,33 +778,33 @@ export const screenshots = [
["ui_S_t[f.messages.impl.sender_SenderName_null_SenderName-Day-8_8_null_6,NEXUS_5,1.0,en]","ui_S_t[f.messages.impl.sender_SenderName_null_SenderName-Night-8_9_null_6,NEXUS_5,1.0,en]",0,],
["ui_S_t[f.messages.impl.sender_SenderName_null_SenderName-Day-8_8_null_7,NEXUS_5,1.0,en]","ui_S_t[f.messages.impl.sender_SenderName_null_SenderName-Night-8_9_null_7,NEXUS_5,1.0,en]",0,],
["ui_S_t[f.messages.impl.sender_SenderName_null_SenderName-Day-8_8_null_8,NEXUS_5,1.0,en]","ui_S_t[f.messages.impl.sender_SenderName_null_SenderName-Night-8_9_null_8,NEXUS_5,1.0,en]",0,],
-["ui_S_t[f.lockscreen.impl.setup.biometric_SetupBiometricView_null_SetupBiometricView-Day-2_3_null_0,NEXUS_5,1.0,en]","ui_S_t[f.lockscreen.impl.setup.biometric_SetupBiometricView_null_SetupBiometricView-Night-2_4_null_0,NEXUS_5,1.0,en]",19846,],
-["ui_S_t[f.lockscreen.impl.setup.pin_SetupPinView_null_SetupPinView-Day-3_4_null_0,NEXUS_5,1.0,en]","ui_S_t[f.lockscreen.impl.setup.pin_SetupPinView_null_SetupPinView-Night-3_5_null_0,NEXUS_5,1.0,en]",19846,],
-["ui_S_t[f.lockscreen.impl.setup.pin_SetupPinView_null_SetupPinView-Day-3_4_null_1,NEXUS_5,1.0,en]","ui_S_t[f.lockscreen.impl.setup.pin_SetupPinView_null_SetupPinView-Night-3_5_null_1,NEXUS_5,1.0,en]",19846,],
-["ui_S_t[f.lockscreen.impl.setup.pin_SetupPinView_null_SetupPinView-Day-3_4_null_2,NEXUS_5,1.0,en]","ui_S_t[f.lockscreen.impl.setup.pin_SetupPinView_null_SetupPinView-Night-3_5_null_2,NEXUS_5,1.0,en]",19846,],
-["ui_S_t[f.lockscreen.impl.setup.pin_SetupPinView_null_SetupPinView-Day-3_4_null_3,NEXUS_5,1.0,en]","ui_S_t[f.lockscreen.impl.setup.pin_SetupPinView_null_SetupPinView-Night-3_5_null_3,NEXUS_5,1.0,en]",19846,],
-["ui_S_t[f.lockscreen.impl.setup.pin_SetupPinView_null_SetupPinView-Day-3_4_null_4,NEXUS_5,1.0,en]","ui_S_t[f.lockscreen.impl.setup.pin_SetupPinView_null_SetupPinView-Night-3_5_null_4,NEXUS_5,1.0,en]",19846,],
+["ui_S_t[f.lockscreen.impl.setup.biometric_SetupBiometricView_null_SetupBiometricView-Day-2_3_null_0,NEXUS_5,1.0,en]","ui_S_t[f.lockscreen.impl.setup.biometric_SetupBiometricView_null_SetupBiometricView-Night-2_4_null_0,NEXUS_5,1.0,en]",19860,],
+["ui_S_t[f.lockscreen.impl.setup.pin_SetupPinView_null_SetupPinView-Day-3_4_null_0,NEXUS_5,1.0,en]","ui_S_t[f.lockscreen.impl.setup.pin_SetupPinView_null_SetupPinView-Night-3_5_null_0,NEXUS_5,1.0,en]",19860,],
+["ui_S_t[f.lockscreen.impl.setup.pin_SetupPinView_null_SetupPinView-Day-3_4_null_1,NEXUS_5,1.0,en]","ui_S_t[f.lockscreen.impl.setup.pin_SetupPinView_null_SetupPinView-Night-3_5_null_1,NEXUS_5,1.0,en]",19860,],
+["ui_S_t[f.lockscreen.impl.setup.pin_SetupPinView_null_SetupPinView-Day-3_4_null_2,NEXUS_5,1.0,en]","ui_S_t[f.lockscreen.impl.setup.pin_SetupPinView_null_SetupPinView-Night-3_5_null_2,NEXUS_5,1.0,en]",19860,],
+["ui_S_t[f.lockscreen.impl.setup.pin_SetupPinView_null_SetupPinView-Day-3_4_null_3,NEXUS_5,1.0,en]","ui_S_t[f.lockscreen.impl.setup.pin_SetupPinView_null_SetupPinView-Night-3_5_null_3,NEXUS_5,1.0,en]",19860,],
+["ui_S_t[f.lockscreen.impl.setup.pin_SetupPinView_null_SetupPinView-Day-3_4_null_4,NEXUS_5,1.0,en]","ui_S_t[f.lockscreen.impl.setup.pin_SetupPinView_null_SetupPinView-Night-3_5_null_4,NEXUS_5,1.0,en]",19860,],
["ui_S_t[f.messages.impl.actionlist_SheetContent_null_SheetContent-Day-1_1_null_0,NEXUS_5,1.0,en]","ui_S_t[f.messages.impl.actionlist_SheetContent_null_SheetContent-Night-1_2_null_0,NEXUS_5,1.0,en]",0,],
["ui_S_t[f.messages.impl.actionlist_SheetContent_null_SheetContent-Day-1_1_null_1,NEXUS_5,1.0,en]","ui_S_t[f.messages.impl.actionlist_SheetContent_null_SheetContent-Night-1_2_null_1,NEXUS_5,1.0,en]",0,],
-["ui_S_t[f.messages.impl.actionlist_SheetContent_null_SheetContent-Day-1_1_null_10,NEXUS_5,1.0,en]","ui_S_t[f.messages.impl.actionlist_SheetContent_null_SheetContent-Night-1_2_null_10,NEXUS_5,1.0,en]",19846,],
-["ui_S_t[f.messages.impl.actionlist_SheetContent_null_SheetContent-Day-1_1_null_2,NEXUS_5,1.0,en]","ui_S_t[f.messages.impl.actionlist_SheetContent_null_SheetContent-Night-1_2_null_2,NEXUS_5,1.0,en]",19846,],
-["ui_S_t[f.messages.impl.actionlist_SheetContent_null_SheetContent-Day-1_1_null_3,NEXUS_5,1.0,en]","ui_S_t[f.messages.impl.actionlist_SheetContent_null_SheetContent-Night-1_2_null_3,NEXUS_5,1.0,en]",19846,],
-["ui_S_t[f.messages.impl.actionlist_SheetContent_null_SheetContent-Day-1_1_null_4,NEXUS_5,1.0,en]","ui_S_t[f.messages.impl.actionlist_SheetContent_null_SheetContent-Night-1_2_null_4,NEXUS_5,1.0,en]",19846,],
-["ui_S_t[f.messages.impl.actionlist_SheetContent_null_SheetContent-Day-1_1_null_5,NEXUS_5,1.0,en]","ui_S_t[f.messages.impl.actionlist_SheetContent_null_SheetContent-Night-1_2_null_5,NEXUS_5,1.0,en]",19846,],
-["ui_S_t[f.messages.impl.actionlist_SheetContent_null_SheetContent-Day-1_1_null_6,NEXUS_5,1.0,en]","ui_S_t[f.messages.impl.actionlist_SheetContent_null_SheetContent-Night-1_2_null_6,NEXUS_5,1.0,en]",19846,],
-["ui_S_t[f.messages.impl.actionlist_SheetContent_null_SheetContent-Day-1_1_null_7,NEXUS_5,1.0,en]","ui_S_t[f.messages.impl.actionlist_SheetContent_null_SheetContent-Night-1_2_null_7,NEXUS_5,1.0,en]",19846,],
-["ui_S_t[f.messages.impl.actionlist_SheetContent_null_SheetContent-Day-1_1_null_8,NEXUS_5,1.0,en]","ui_S_t[f.messages.impl.actionlist_SheetContent_null_SheetContent-Night-1_2_null_8,NEXUS_5,1.0,en]",19846,],
-["ui_S_t[f.messages.impl.actionlist_SheetContent_null_SheetContent-Day-1_1_null_9,NEXUS_5,1.0,en]","ui_S_t[f.messages.impl.actionlist_SheetContent_null_SheetContent-Night-1_2_null_9,NEXUS_5,1.0,en]",19846,],
+["ui_S_t[f.messages.impl.actionlist_SheetContent_null_SheetContent-Day-1_1_null_10,NEXUS_5,1.0,en]","ui_S_t[f.messages.impl.actionlist_SheetContent_null_SheetContent-Night-1_2_null_10,NEXUS_5,1.0,en]",19860,],
+["ui_S_t[f.messages.impl.actionlist_SheetContent_null_SheetContent-Day-1_1_null_2,NEXUS_5,1.0,en]","ui_S_t[f.messages.impl.actionlist_SheetContent_null_SheetContent-Night-1_2_null_2,NEXUS_5,1.0,en]",19860,],
+["ui_S_t[f.messages.impl.actionlist_SheetContent_null_SheetContent-Day-1_1_null_3,NEXUS_5,1.0,en]","ui_S_t[f.messages.impl.actionlist_SheetContent_null_SheetContent-Night-1_2_null_3,NEXUS_5,1.0,en]",19860,],
+["ui_S_t[f.messages.impl.actionlist_SheetContent_null_SheetContent-Day-1_1_null_4,NEXUS_5,1.0,en]","ui_S_t[f.messages.impl.actionlist_SheetContent_null_SheetContent-Night-1_2_null_4,NEXUS_5,1.0,en]",19860,],
+["ui_S_t[f.messages.impl.actionlist_SheetContent_null_SheetContent-Day-1_1_null_5,NEXUS_5,1.0,en]","ui_S_t[f.messages.impl.actionlist_SheetContent_null_SheetContent-Night-1_2_null_5,NEXUS_5,1.0,en]",19860,],
+["ui_S_t[f.messages.impl.actionlist_SheetContent_null_SheetContent-Day-1_1_null_6,NEXUS_5,1.0,en]","ui_S_t[f.messages.impl.actionlist_SheetContent_null_SheetContent-Night-1_2_null_6,NEXUS_5,1.0,en]",19860,],
+["ui_S_t[f.messages.impl.actionlist_SheetContent_null_SheetContent-Day-1_1_null_7,NEXUS_5,1.0,en]","ui_S_t[f.messages.impl.actionlist_SheetContent_null_SheetContent-Night-1_2_null_7,NEXUS_5,1.0,en]",19860,],
+["ui_S_t[f.messages.impl.actionlist_SheetContent_null_SheetContent-Day-1_1_null_8,NEXUS_5,1.0,en]","ui_S_t[f.messages.impl.actionlist_SheetContent_null_SheetContent-Night-1_2_null_8,NEXUS_5,1.0,en]",19860,],
+["ui_S_t[f.messages.impl.actionlist_SheetContent_null_SheetContent-Day-1_1_null_9,NEXUS_5,1.0,en]","ui_S_t[f.messages.impl.actionlist_SheetContent_null_SheetContent-Night-1_2_null_9,NEXUS_5,1.0,en]",19860,],
["ui_S_t[f.messages.impl.timeline.components.reactionsummary_SheetContent_null_SheetContent-Day-56_56_null_0,NEXUS_5,1.0,en]","ui_S_t[f.messages.impl.timeline.components.reactionsummary_SheetContent_null_SheetContent-Night-56_57_null_0,NEXUS_5,1.0,en]",0,],
-["ui_S_t[f.location.impl.show_ShowLocationView_null_ShowLocationView-Day-1_2_null_0,NEXUS_5,1.0,en]","ui_S_t[f.location.impl.show_ShowLocationView_null_ShowLocationView-Night-1_3_null_0,NEXUS_5,1.0,en]",19846,],
-["ui_S_t[f.location.impl.show_ShowLocationView_null_ShowLocationView-Day-1_2_null_1,NEXUS_5,1.0,en]","ui_S_t[f.location.impl.show_ShowLocationView_null_ShowLocationView-Night-1_3_null_1,NEXUS_5,1.0,en]",19846,],
-["ui_S_t[f.location.impl.show_ShowLocationView_null_ShowLocationView-Day-1_2_null_2,NEXUS_5,1.0,en]","ui_S_t[f.location.impl.show_ShowLocationView_null_ShowLocationView-Night-1_3_null_2,NEXUS_5,1.0,en]",19846,],
-["ui_S_t[f.location.impl.show_ShowLocationView_null_ShowLocationView-Day-1_2_null_3,NEXUS_5,1.0,en]","ui_S_t[f.location.impl.show_ShowLocationView_null_ShowLocationView-Night-1_3_null_3,NEXUS_5,1.0,en]",19846,],
-["ui_S_t[f.location.impl.show_ShowLocationView_null_ShowLocationView-Day-1_2_null_4,NEXUS_5,1.0,en]","ui_S_t[f.location.impl.show_ShowLocationView_null_ShowLocationView-Night-1_3_null_4,NEXUS_5,1.0,en]",19846,],
-["ui_S_t[f.location.impl.show_ShowLocationView_null_ShowLocationView-Day-1_2_null_5,NEXUS_5,1.0,en]","ui_S_t[f.location.impl.show_ShowLocationView_null_ShowLocationView-Night-1_3_null_5,NEXUS_5,1.0,en]",19846,],
-["ui_S_t[f.location.impl.show_ShowLocationView_null_ShowLocationView-Day-1_2_null_6,NEXUS_5,1.0,en]","ui_S_t[f.location.impl.show_ShowLocationView_null_ShowLocationView-Night-1_3_null_6,NEXUS_5,1.0,en]",19846,],
-["ui_S_t[f.location.impl.show_ShowLocationView_null_ShowLocationView-Day-1_2_null_7,NEXUS_5,1.0,en]","ui_S_t[f.location.impl.show_ShowLocationView_null_ShowLocationView-Night-1_3_null_7,NEXUS_5,1.0,en]",19846,],
-["ui_S_t[f.signedout.impl_SignedOutView_null_SignedOutView-Day-0_1_null_0,NEXUS_5,1.0,en]","ui_S_t[f.signedout.impl_SignedOutView_null_SignedOutView-Night-0_2_null_0,NEXUS_5,1.0,en]",19846,],
+["ui_S_t[f.location.impl.show_ShowLocationView_null_ShowLocationView-Day-1_2_null_0,NEXUS_5,1.0,en]","ui_S_t[f.location.impl.show_ShowLocationView_null_ShowLocationView-Night-1_3_null_0,NEXUS_5,1.0,en]",19860,],
+["ui_S_t[f.location.impl.show_ShowLocationView_null_ShowLocationView-Day-1_2_null_1,NEXUS_5,1.0,en]","ui_S_t[f.location.impl.show_ShowLocationView_null_ShowLocationView-Night-1_3_null_1,NEXUS_5,1.0,en]",19860,],
+["ui_S_t[f.location.impl.show_ShowLocationView_null_ShowLocationView-Day-1_2_null_2,NEXUS_5,1.0,en]","ui_S_t[f.location.impl.show_ShowLocationView_null_ShowLocationView-Night-1_3_null_2,NEXUS_5,1.0,en]",19860,],
+["ui_S_t[f.location.impl.show_ShowLocationView_null_ShowLocationView-Day-1_2_null_3,NEXUS_5,1.0,en]","ui_S_t[f.location.impl.show_ShowLocationView_null_ShowLocationView-Night-1_3_null_3,NEXUS_5,1.0,en]",19860,],
+["ui_S_t[f.location.impl.show_ShowLocationView_null_ShowLocationView-Day-1_2_null_4,NEXUS_5,1.0,en]","ui_S_t[f.location.impl.show_ShowLocationView_null_ShowLocationView-Night-1_3_null_4,NEXUS_5,1.0,en]",19860,],
+["ui_S_t[f.location.impl.show_ShowLocationView_null_ShowLocationView-Day-1_2_null_5,NEXUS_5,1.0,en]","ui_S_t[f.location.impl.show_ShowLocationView_null_ShowLocationView-Night-1_3_null_5,NEXUS_5,1.0,en]",19860,],
+["ui_S_t[f.location.impl.show_ShowLocationView_null_ShowLocationView-Day-1_2_null_6,NEXUS_5,1.0,en]","ui_S_t[f.location.impl.show_ShowLocationView_null_ShowLocationView-Night-1_3_null_6,NEXUS_5,1.0,en]",19860,],
+["ui_S_t[f.location.impl.show_ShowLocationView_null_ShowLocationView-Day-1_2_null_7,NEXUS_5,1.0,en]","ui_S_t[f.location.impl.show_ShowLocationView_null_ShowLocationView-Night-1_3_null_7,NEXUS_5,1.0,en]",19860,],
+["ui_S_t[f.signedout.impl_SignedOutView_null_SignedOutView-Day-0_1_null_0,NEXUS_5,1.0,en]","ui_S_t[f.signedout.impl_SignedOutView_null_SignedOutView-Night-0_2_null_0,NEXUS_5,1.0,en]",19860,],
["ui_S_t[l.designsystem.components.dialogs_SingleSelectionDialogContent_null_Dialogs_SingleSelectionDialogContent_0_null,NEXUS_5,1.0,en]","",0,],
["ui_S_t[l.designsystem.components.dialogs_SingleSelectionDialog_null_SingleSelectionDialog-Day_0_null,NEXUS_5,1.0,en]","ui_S_t[l.designsystem.components.dialogs_SingleSelectionDialog_null_SingleSelectionDialog-Night_1_null,NEXUS_5,1.0,en]",0,],
["ui_S_t[l.designsystem.components.list_SingleSelectionListItemCustomFormattert_null_Listitems_SingleselectionListitem-customformatter_0_null,NEXUS_5,1.0,en]","",0,],
@@ -805,7 +813,7 @@ export const screenshots = [
["ui_S_t[l.designsystem.components.list_SingleSelectionListItemUnselectedWithSupportingText_null_Listitems_SingleselectionListitem-noselection,supportingtext_0_null,NEXUS_5,1.0,en]","",0,],
["ui_S_t[l.designsystem.components.list_SingleSelectionListItem_null_Listitems_SingleselectionListitem-noselection_0_null,NEXUS_5,1.0,en]","",0,],
["ui_S_t[l.designsystem.theme.components_Sliders_null_Sliders_Sliders_0_null,NEXUS_5,1.0,en]","",0,],
-["ui_S_t[f.login.impl.dialogs_SlidingSyncNotSupportedDialog_null_SlidingSyncNotSupportedDialog-Day-2_3_null,NEXUS_5,1.0,en]","ui_S_t[f.login.impl.dialogs_SlidingSyncNotSupportedDialog_null_SlidingSyncNotSupportedDialog-Night-2_4_null,NEXUS_5,1.0,en]",19846,],
+["ui_S_t[f.login.impl.dialogs_SlidingSyncNotSupportedDialog_null_SlidingSyncNotSupportedDialog-Day-2_3_null,NEXUS_5,1.0,en]","ui_S_t[f.login.impl.dialogs_SlidingSyncNotSupportedDialog_null_SlidingSyncNotSupportedDialog-Night-2_4_null,NEXUS_5,1.0,en]",19860,],
["ui_S_t[l.designsystem.theme.components_SnackbarWithActionAndCloseButton_null_Snackbars_Snackbarwithactionandclosebutton_0_null,NEXUS_5,1.0,en]","",0,],
["ui_S_t[l.designsystem.theme.components_SnackbarWithActionOnNewLineAndCloseButton_null_Snackbars_Snackbarwithactionandclosebuttononnewline_0_null,NEXUS_5,1.0,en]","",0,],
["ui_S_t[l.designsystem.theme.components_SnackbarWithActionOnNewLine_null_Snackbars_Snackbarwithactiononnewline_0_null,NEXUS_5,1.0,en]","",0,],
@@ -815,23 +823,23 @@ export const screenshots = [
["ui_S_t[l.designsystem.modifiers_SquareSizeModifierLargeHeight_null_SquareSizeModifierLargeHeight_0_null,NEXUS_5,1.0,en]","",0,],
["ui_S_t[l.designsystem.modifiers_SquareSizeModifierLargeWidth_null_SquareSizeModifierLargeWidth_0_null,NEXUS_5,1.0,en]","",0,],
["ui_S_t[f.location.api.internal_StaticMapPlaceholder_null_StaticMapPlaceholder-Day-1_2_null_0,NEXUS_5,1.0,en]","ui_S_t[f.location.api.internal_StaticMapPlaceholder_null_StaticMapPlaceholder-Night-1_3_null_0,NEXUS_5,1.0,en]",0,],
-["ui_S_t[f.location.api.internal_StaticMapPlaceholder_null_StaticMapPlaceholder-Day-1_2_null_1,NEXUS_5,1.0,en]","ui_S_t[f.location.api.internal_StaticMapPlaceholder_null_StaticMapPlaceholder-Night-1_3_null_1,NEXUS_5,1.0,en]",19846,],
+["ui_S_t[f.location.api.internal_StaticMapPlaceholder_null_StaticMapPlaceholder-Day-1_2_null_1,NEXUS_5,1.0,en]","ui_S_t[f.location.api.internal_StaticMapPlaceholder_null_StaticMapPlaceholder-Night-1_3_null_1,NEXUS_5,1.0,en]",19860,],
["ui_S_t[f.location.api_StaticMapView_null_StaticMapView-Day-0_1_null,NEXUS_5,1.0,en]","ui_S_t[f.location.api_StaticMapView_null_StaticMapView-Night-0_2_null,NEXUS_5,1.0,en]",0,],
["ui_S_t[l.designsystem.atomic.pages_SunsetPage_null_SunsetPage-Day_0_null,NEXUS_5,1.0,en]","ui_S_t[l.designsystem.atomic.pages_SunsetPage_null_SunsetPage-Night_1_null,NEXUS_5,1.0,en]",0,],
["ui_S_t[l.designsystem.components.button_SuperButton_null_SuperButton-Day_0_null,NEXUS_5,1.0,en]","ui_S_t[l.designsystem.components.button_SuperButton_null_SuperButton-Night_1_null,NEXUS_5,1.0,en]",0,],
["ui_S_t[l.designsystem.theme.components_Surface_null_Surface_0_null,NEXUS_5,1.0,en]","",0,],
["ui_S_t[l.designsystem.theme.components_Switch_null_Toggles_Switch_0_null,NEXUS_5,1.0,en]","",0,],
-["ui_S_t[appnav.loggedin_SyncStateView_null_SyncStateView-Day-1_1_null,NEXUS_5,1.0,en]","ui_S_t[appnav.loggedin_SyncStateView_null_SyncStateView-Night-1_2_null,NEXUS_5,1.0,en]",19846,],
+["ui_S_t[appnav.loggedin_SyncStateView_null_SyncStateView-Day-1_1_null,NEXUS_5,1.0,en]","ui_S_t[appnav.loggedin_SyncStateView_null_SyncStateView-Night-1_2_null,NEXUS_5,1.0,en]",19860,],
["ui_S_t[l.designsystem.theme.components_TextButtonLarge_null_Buttons_TextButtonLarge_0_null,NEXUS_5,1.0,en]","",0,],
["ui_S_t[l.designsystem.theme.components_TextButtonMedium_null_Buttons_TextButtonMedium_0_null,NEXUS_5,1.0,en]","",0,],
["ui_S_t[l.designsystem.theme.components_TextButtonSmall_null_Buttons_TextButtonSmall_0_null,NEXUS_5,1.0,en]","",0,],
-["ui_S_t[l.textcomposer_TextComposerEdit_null_TextComposerEdit-Day-2_3_null,NEXUS_5,1.0,en]","ui_S_t[l.textcomposer_TextComposerEdit_null_TextComposerEdit-Night-2_4_null,NEXUS_5,1.0,en]",19846,],
-["ui_S_t[l.textcomposer_TextComposerFormatting_null_TextComposerFormatting-Day-1_2_null,NEXUS_5,1.0,en]","ui_S_t[l.textcomposer_TextComposerFormatting_null_TextComposerFormatting-Night-1_3_null,NEXUS_5,1.0,en]",19846,],
-["ui_S_t[l.textcomposer_TextComposerLinkDialogCreateLinkWithoutText_null_TextComposerLinkDialogCreateLinkWithoutText-Day-6_7_null,NEXUS_5,1.0,en]","ui_S_t[l.textcomposer_TextComposerLinkDialogCreateLinkWithoutText_null_TextComposerLinkDialogCreateLinkWithoutText-Night-6_8_null,NEXUS_5,1.0,en]",19846,],
-["ui_S_t[l.textcomposer_TextComposerLinkDialogCreateLink_null_TextComposerLinkDialogCreateLink-Day-5_6_null,NEXUS_5,1.0,en]","ui_S_t[l.textcomposer_TextComposerLinkDialogCreateLink_null_TextComposerLinkDialogCreateLink-Night-5_7_null,NEXUS_5,1.0,en]",19846,],
-["ui_S_t[l.textcomposer_TextComposerLinkDialogEditLink_null_TextComposerLinkDialogEditLink-Day-7_8_null,NEXUS_5,1.0,en]","ui_S_t[l.textcomposer_TextComposerLinkDialogEditLink_null_TextComposerLinkDialogEditLink-Night-7_9_null,NEXUS_5,1.0,en]",19846,],
-["ui_S_t[l.textcomposer_TextComposerReply_null_TextComposerReply-Day-3_4_null,NEXUS_5,1.0,en]","ui_S_t[l.textcomposer_TextComposerReply_null_TextComposerReply-Night-3_5_null,NEXUS_5,1.0,en]",19846,],
-["ui_S_t[l.textcomposer_TextComposerSimple_null_TextComposerSimple-Day-0_1_null,NEXUS_5,1.0,en]","ui_S_t[l.textcomposer_TextComposerSimple_null_TextComposerSimple-Night-0_2_null,NEXUS_5,1.0,en]",19846,],
+["ui_S_t[l.textcomposer_TextComposerEdit_null_TextComposerEdit-Day-2_3_null,NEXUS_5,1.0,en]","ui_S_t[l.textcomposer_TextComposerEdit_null_TextComposerEdit-Night-2_4_null,NEXUS_5,1.0,en]",19860,],
+["ui_S_t[l.textcomposer_TextComposerFormatting_null_TextComposerFormatting-Day-1_2_null,NEXUS_5,1.0,en]","ui_S_t[l.textcomposer_TextComposerFormatting_null_TextComposerFormatting-Night-1_3_null,NEXUS_5,1.0,en]",19860,],
+["ui_S_t[l.textcomposer_TextComposerLinkDialogCreateLinkWithoutText_null_TextComposerLinkDialogCreateLinkWithoutText-Day-6_7_null,NEXUS_5,1.0,en]","ui_S_t[l.textcomposer_TextComposerLinkDialogCreateLinkWithoutText_null_TextComposerLinkDialogCreateLinkWithoutText-Night-6_8_null,NEXUS_5,1.0,en]",19860,],
+["ui_S_t[l.textcomposer_TextComposerLinkDialogCreateLink_null_TextComposerLinkDialogCreateLink-Day-5_6_null,NEXUS_5,1.0,en]","ui_S_t[l.textcomposer_TextComposerLinkDialogCreateLink_null_TextComposerLinkDialogCreateLink-Night-5_7_null,NEXUS_5,1.0,en]",19860,],
+["ui_S_t[l.textcomposer_TextComposerLinkDialogEditLink_null_TextComposerLinkDialogEditLink-Day-7_8_null,NEXUS_5,1.0,en]","ui_S_t[l.textcomposer_TextComposerLinkDialogEditLink_null_TextComposerLinkDialogEditLink-Night-7_9_null,NEXUS_5,1.0,en]",19860,],
+["ui_S_t[l.textcomposer_TextComposerReply_null_TextComposerReply-Day-3_4_null,NEXUS_5,1.0,en]","ui_S_t[l.textcomposer_TextComposerReply_null_TextComposerReply-Night-3_5_null,NEXUS_5,1.0,en]",19860,],
+["ui_S_t[l.textcomposer_TextComposerSimple_null_TextComposerSimple-Day-0_1_null,NEXUS_5,1.0,en]","ui_S_t[l.textcomposer_TextComposerSimple_null_TextComposerSimple-Night-0_2_null,NEXUS_5,1.0,en]",19860,],
["ui_S_t[l.textcomposer_TextComposerVoice_null_TextComposerVoice-Day-4_5_null,NEXUS_5,1.0,en]","ui_S_t[l.textcomposer_TextComposerVoice_null_TextComposerVoice-Night-4_6_null,NEXUS_5,1.0,en]",0,],
["ui_S_t[l.designsystem.theme.components_TextDark_null_Text_TextDark_0_null,NEXUS_5,1.0,en]","",0,],
["ui_S_t[l.designsystem.theme.components_TextFieldDark_null_TextFields_TextFieldDark_0_null,NEXUS_5,1.0,en]","",0,],
@@ -843,35 +851,35 @@ export const screenshots = [
["ui_S_t[l.designsystem.theme.components_TextFieldValueTextFieldDark_null_TextFields_TextFieldValueTextFieldDark_0_null,NEXUS_5,1.0,en]","",0,],
["ui_S_t[l.textcomposer.components_TextFormatting_null_TextFormatting-Day-13_14_null,NEXUS_5,1.0,en]","ui_S_t[l.textcomposer.components_TextFormatting_null_TextFormatting-Night-13_15_null,NEXUS_5,1.0,en]",0,],
["ui_S_t[l.designsystem.theme.components_TextLight_null_Text_TextLight_0_null,NEXUS_5,1.0,en]","",0,],
-["ui_S_t[l.designsystem.theme.components.previews_TimePickerHorizontal_null_DateTimepickers_TimePickerHorizontal_0_null,NEXUS_5,1.0,en]","",19846,],
-["ui_S_t[l.designsystem.theme.components.previews_TimePickerVerticalDark_null_DateTimepickers_TimePickerVerticalDark_0_null,NEXUS_5,1.0,en]","",19846,],
-["ui_S_t[l.designsystem.theme.components.previews_TimePickerVerticalLight_null_DateTimepickers_TimePickerVerticalLight_0_null,NEXUS_5,1.0,en]","",19846,],
+["ui_S_t[l.designsystem.theme.components.previews_TimePickerHorizontal_null_DateTimepickers_TimePickerHorizontal_0_null,NEXUS_5,1.0,en]","",19860,],
+["ui_S_t[l.designsystem.theme.components.previews_TimePickerVerticalDark_null_DateTimepickers_TimePickerVerticalDark_0_null,NEXUS_5,1.0,en]","",19860,],
+["ui_S_t[l.designsystem.theme.components.previews_TimePickerVerticalLight_null_DateTimepickers_TimePickerVerticalLight_0_null,NEXUS_5,1.0,en]","",19860,],
["ui_S_t[f.messages.impl.timeline.components_TimelineEventTimestampView_null_TimelineEventTimestampView-Day-16_16_null_0,NEXUS_5,1.0,en]","ui_S_t[f.messages.impl.timeline.components_TimelineEventTimestampView_null_TimelineEventTimestampView-Night-16_17_null_0,NEXUS_5,1.0,en]",0,],
["ui_S_t[f.messages.impl.timeline.components_TimelineEventTimestampView_null_TimelineEventTimestampView-Day-16_16_null_1,NEXUS_5,1.0,en]","ui_S_t[f.messages.impl.timeline.components_TimelineEventTimestampView_null_TimelineEventTimestampView-Night-16_17_null_1,NEXUS_5,1.0,en]",0,],
-["ui_S_t[f.messages.impl.timeline.components_TimelineEventTimestampView_null_TimelineEventTimestampView-Day-16_16_null_2,NEXUS_5,1.0,en]","ui_S_t[f.messages.impl.timeline.components_TimelineEventTimestampView_null_TimelineEventTimestampView-Night-16_17_null_2,NEXUS_5,1.0,en]",19846,],
-["ui_S_t[f.messages.impl.timeline.components_TimelineEventTimestampView_null_TimelineEventTimestampView-Day-16_16_null_3,NEXUS_5,1.0,en]","ui_S_t[f.messages.impl.timeline.components_TimelineEventTimestampView_null_TimelineEventTimestampView-Night-16_17_null_3,NEXUS_5,1.0,en]",19846,],
+["ui_S_t[f.messages.impl.timeline.components_TimelineEventTimestampView_null_TimelineEventTimestampView-Day-16_16_null_2,NEXUS_5,1.0,en]","ui_S_t[f.messages.impl.timeline.components_TimelineEventTimestampView_null_TimelineEventTimestampView-Night-16_17_null_2,NEXUS_5,1.0,en]",19860,],
+["ui_S_t[f.messages.impl.timeline.components_TimelineEventTimestampView_null_TimelineEventTimestampView-Day-16_16_null_3,NEXUS_5,1.0,en]","ui_S_t[f.messages.impl.timeline.components_TimelineEventTimestampView_null_TimelineEventTimestampView-Night-16_17_null_3,NEXUS_5,1.0,en]",19860,],
["ui_S_t[f.messages.impl.timeline.components.event_TimelineImageWithCaptionRow_null_TimelineImageWithCaptionRow-Day-40_40_null,NEXUS_5,1.0,en]","ui_S_t[f.messages.impl.timeline.components.event_TimelineImageWithCaptionRow_null_TimelineImageWithCaptionRow-Night-40_41_null,NEXUS_5,1.0,en]",0,],
["ui_S_t[f.messages.impl.timeline.components.event_TimelineItemAudioView_null_TimelineItemAudioView-Day-36_36_null_0,NEXUS_5,1.0,en]","ui_S_t[f.messages.impl.timeline.components.event_TimelineItemAudioView_null_TimelineItemAudioView-Night-36_37_null_0,NEXUS_5,1.0,en]",0,],
["ui_S_t[f.messages.impl.timeline.components.event_TimelineItemAudioView_null_TimelineItemAudioView-Day-36_36_null_1,NEXUS_5,1.0,en]","ui_S_t[f.messages.impl.timeline.components.event_TimelineItemAudioView_null_TimelineItemAudioView-Night-36_37_null_1,NEXUS_5,1.0,en]",0,],
["ui_S_t[f.messages.impl.timeline.components.event_TimelineItemAudioView_null_TimelineItemAudioView-Day-36_36_null_2,NEXUS_5,1.0,en]","ui_S_t[f.messages.impl.timeline.components.event_TimelineItemAudioView_null_TimelineItemAudioView-Night-36_37_null_2,NEXUS_5,1.0,en]",0,],
["ui_S_t[f.messages.impl.timeline.components.virtual_TimelineItemDaySeparatorView_null_TimelineItemDaySeparatorView-Day-61_61_null_0,NEXUS_5,1.0,en]","ui_S_t[f.messages.impl.timeline.components.virtual_TimelineItemDaySeparatorView_null_TimelineItemDaySeparatorView-Night-61_62_null_0,NEXUS_5,1.0,en]",0,],
["ui_S_t[f.messages.impl.timeline.components.virtual_TimelineItemDaySeparatorView_null_TimelineItemDaySeparatorView-Day-61_61_null_1,NEXUS_5,1.0,en]","ui_S_t[f.messages.impl.timeline.components.virtual_TimelineItemDaySeparatorView_null_TimelineItemDaySeparatorView-Night-61_62_null_1,NEXUS_5,1.0,en]",0,],
-["ui_S_t[f.messages.impl.timeline.components.event_TimelineItemEncryptedView_null_TimelineItemEncryptedView-Day-37_37_null_0,NEXUS_5,1.0,en]","ui_S_t[f.messages.impl.timeline.components.event_TimelineItemEncryptedView_null_TimelineItemEncryptedView-Night-37_38_null_0,NEXUS_5,1.0,en]",19849,],
-["ui_S_t[f.messages.impl.timeline.components.event_TimelineItemEncryptedView_null_TimelineItemEncryptedView-Day-37_37_null_1,NEXUS_5,1.0,en]","ui_S_t[f.messages.impl.timeline.components.event_TimelineItemEncryptedView_null_TimelineItemEncryptedView-Night-37_38_null_1,NEXUS_5,1.0,en]",19849,],
-["ui_S_t[f.messages.impl.timeline.components.event_TimelineItemEncryptedView_null_TimelineItemEncryptedView-Day-37_37_null_2,NEXUS_5,1.0,en]","ui_S_t[f.messages.impl.timeline.components.event_TimelineItemEncryptedView_null_TimelineItemEncryptedView-Night-37_38_null_2,NEXUS_5,1.0,en]",19849,],
+["ui_S_t[f.messages.impl.timeline.components.event_TimelineItemEncryptedView_null_TimelineItemEncryptedView-Day-37_37_null_0,NEXUS_5,1.0,en]","ui_S_t[f.messages.impl.timeline.components.event_TimelineItemEncryptedView_null_TimelineItemEncryptedView-Night-37_38_null_0,NEXUS_5,1.0,en]",19860,],
+["ui_S_t[f.messages.impl.timeline.components.event_TimelineItemEncryptedView_null_TimelineItemEncryptedView-Day-37_37_null_1,NEXUS_5,1.0,en]","ui_S_t[f.messages.impl.timeline.components.event_TimelineItemEncryptedView_null_TimelineItemEncryptedView-Night-37_38_null_1,NEXUS_5,1.0,en]",19860,],
+["ui_S_t[f.messages.impl.timeline.components.event_TimelineItemEncryptedView_null_TimelineItemEncryptedView-Day-37_37_null_2,NEXUS_5,1.0,en]","ui_S_t[f.messages.impl.timeline.components.event_TimelineItemEncryptedView_null_TimelineItemEncryptedView-Night-37_38_null_2,NEXUS_5,1.0,en]",19860,],
["ui_S_t[f.messages.impl.timeline.components_TimelineItemEventRowDisambiguated_null_TimelineItemEventRowDisambiguated-Day-18_18_null_0,NEXUS_5,1.0,en]","ui_S_t[f.messages.impl.timeline.components_TimelineItemEventRowDisambiguated_null_TimelineItemEventRowDisambiguated-Night-18_19_null_0,NEXUS_5,1.0,en]",0,],
["ui_S_t[f.messages.impl.timeline.components_TimelineItemEventRowForDirectRoom_null_TimelineItemEventRowForDirectRoom-Day-19_19_null,NEXUS_5,1.0,en]","ui_S_t[f.messages.impl.timeline.components_TimelineItemEventRowForDirectRoom_null_TimelineItemEventRowForDirectRoom-Night-19_20_null,NEXUS_5,1.0,en]",0,],
["ui_S_t[f.messages.impl.timeline.components_TimelineItemEventRowLongSenderName_null_TimelineItemEventRowLongSenderName_0_null,NEXUS_5,1.0,en]","",0,],
["ui_S_t[f.messages.impl.timeline.components_TimelineItemEventRowTimestamp_null_TimelineItemEventRowTimestamp-Day-20_20_null_0,NEXUS_5,1.0,en]","ui_S_t[f.messages.impl.timeline.components_TimelineItemEventRowTimestamp_null_TimelineItemEventRowTimestamp-Night-20_21_null_0,NEXUS_5,1.0,en]",0,],
["ui_S_t[f.messages.impl.timeline.components_TimelineItemEventRowTimestamp_null_TimelineItemEventRowTimestamp-Day-20_20_null_1,NEXUS_5,1.0,en]","ui_S_t[f.messages.impl.timeline.components_TimelineItemEventRowTimestamp_null_TimelineItemEventRowTimestamp-Night-20_21_null_1,NEXUS_5,1.0,en]",0,],
-["ui_S_t[f.messages.impl.timeline.components_TimelineItemEventRowTimestamp_null_TimelineItemEventRowTimestamp-Day-20_20_null_2,NEXUS_5,1.0,en]","ui_S_t[f.messages.impl.timeline.components_TimelineItemEventRowTimestamp_null_TimelineItemEventRowTimestamp-Night-20_21_null_2,NEXUS_5,1.0,en]",19846,],
-["ui_S_t[f.messages.impl.timeline.components_TimelineItemEventRowTimestamp_null_TimelineItemEventRowTimestamp-Day-20_20_null_3,NEXUS_5,1.0,en]","ui_S_t[f.messages.impl.timeline.components_TimelineItemEventRowTimestamp_null_TimelineItemEventRowTimestamp-Night-20_21_null_3,NEXUS_5,1.0,en]",19846,],
-["ui_S_t[f.messages.impl.timeline.components_TimelineItemEventRowWithManyReactions_null_TimelineItemEventRowWithManyReactions-Day-21_21_null,NEXUS_5,1.0,en]","ui_S_t[f.messages.impl.timeline.components_TimelineItemEventRowWithManyReactions_null_TimelineItemEventRowWithManyReactions-Night-21_22_null,NEXUS_5,1.0,en]",19846,],
+["ui_S_t[f.messages.impl.timeline.components_TimelineItemEventRowTimestamp_null_TimelineItemEventRowTimestamp-Day-20_20_null_2,NEXUS_5,1.0,en]","ui_S_t[f.messages.impl.timeline.components_TimelineItemEventRowTimestamp_null_TimelineItemEventRowTimestamp-Night-20_21_null_2,NEXUS_5,1.0,en]",19860,],
+["ui_S_t[f.messages.impl.timeline.components_TimelineItemEventRowTimestamp_null_TimelineItemEventRowTimestamp-Day-20_20_null_3,NEXUS_5,1.0,en]","ui_S_t[f.messages.impl.timeline.components_TimelineItemEventRowTimestamp_null_TimelineItemEventRowTimestamp-Night-20_21_null_3,NEXUS_5,1.0,en]",19860,],
+["ui_S_t[f.messages.impl.timeline.components_TimelineItemEventRowWithManyReactions_null_TimelineItemEventRowWithManyReactions-Day-21_21_null,NEXUS_5,1.0,en]","ui_S_t[f.messages.impl.timeline.components_TimelineItemEventRowWithManyReactions_null_TimelineItemEventRowWithManyReactions-Night-21_22_null,NEXUS_5,1.0,en]",19860,],
["ui_S_t[f.messages.impl.timeline.components_TimelineItemEventRowWithRR_null_TimelineItemEventRowWithRR-Day-22_22_null_0,NEXUS_5,1.0,en]","ui_S_t[f.messages.impl.timeline.components_TimelineItemEventRowWithRR_null_TimelineItemEventRowWithRR-Night-22_23_null_0,NEXUS_5,1.0,en]",0,],
["ui_S_t[f.messages.impl.timeline.components_TimelineItemEventRowWithRR_null_TimelineItemEventRowWithRR-Day-22_22_null_1,NEXUS_5,1.0,en]","ui_S_t[f.messages.impl.timeline.components_TimelineItemEventRowWithRR_null_TimelineItemEventRowWithRR-Night-22_23_null_1,NEXUS_5,1.0,en]",0,],
["ui_S_t[f.messages.impl.timeline.components_TimelineItemEventRowWithRR_null_TimelineItemEventRowWithRR-Day-22_22_null_2,NEXUS_5,1.0,en]","ui_S_t[f.messages.impl.timeline.components_TimelineItemEventRowWithRR_null_TimelineItemEventRowWithRR-Night-22_23_null_2,NEXUS_5,1.0,en]",0,],
-["ui_S_t[f.messages.impl.timeline.components_TimelineItemEventRowWithReplyInformative_null_TimelineItemEventRowWithReplyInformative-Day-23_23_null_0,NEXUS_5,1.0,en]","ui_S_t[f.messages.impl.timeline.components_TimelineItemEventRowWithReplyInformative_null_TimelineItemEventRowWithReplyInformative-Night-23_24_null_0,NEXUS_5,1.0,en]",19846,],
-["ui_S_t[f.messages.impl.timeline.components_TimelineItemEventRowWithReplyInformative_null_TimelineItemEventRowWithReplyInformative-Day-23_23_null_1,NEXUS_5,1.0,en]","ui_S_t[f.messages.impl.timeline.components_TimelineItemEventRowWithReplyInformative_null_TimelineItemEventRowWithReplyInformative-Night-23_24_null_1,NEXUS_5,1.0,en]",19846,],
+["ui_S_t[f.messages.impl.timeline.components_TimelineItemEventRowWithReplyInformative_null_TimelineItemEventRowWithReplyInformative-Day-23_23_null_0,NEXUS_5,1.0,en]","ui_S_t[f.messages.impl.timeline.components_TimelineItemEventRowWithReplyInformative_null_TimelineItemEventRowWithReplyInformative-Night-23_24_null_0,NEXUS_5,1.0,en]",19860,],
+["ui_S_t[f.messages.impl.timeline.components_TimelineItemEventRowWithReplyInformative_null_TimelineItemEventRowWithReplyInformative-Day-23_23_null_1,NEXUS_5,1.0,en]","ui_S_t[f.messages.impl.timeline.components_TimelineItemEventRowWithReplyInformative_null_TimelineItemEventRowWithReplyInformative-Night-23_24_null_1,NEXUS_5,1.0,en]",19860,],
["ui_S_t[f.messages.impl.timeline.components_TimelineItemEventRowWithReplyOther_null_TimelineItemEventRowWithReplyOther-Day-24_24_null_0,NEXUS_5,1.0,en]","ui_S_t[f.messages.impl.timeline.components_TimelineItemEventRowWithReplyOther_null_TimelineItemEventRowWithReplyOther-Night-24_25_null_0,NEXUS_5,1.0,en]",0,],
["ui_S_t[f.messages.impl.timeline.components_TimelineItemEventRowWithReplyOther_null_TimelineItemEventRowWithReplyOther-Day-24_24_null_1,NEXUS_5,1.0,en]","ui_S_t[f.messages.impl.timeline.components_TimelineItemEventRowWithReplyOther_null_TimelineItemEventRowWithReplyOther-Night-24_25_null_1,NEXUS_5,1.0,en]",0,],
["ui_S_t[f.messages.impl.timeline.components_TimelineItemEventRowWithReply_null_TimelineItemEventRowWithReply-Day-25_25_null_0,NEXUS_5,1.0,en]","ui_S_t[f.messages.impl.timeline.components_TimelineItemEventRowWithReply_null_TimelineItemEventRowWithReply-Night-25_26_null_0,NEXUS_5,1.0,en]",0,],
@@ -880,36 +888,36 @@ export const screenshots = [
["ui_S_t[f.messages.impl.timeline.components_TimelineItemEventRowWithReply_null_TimelineItemEventRowWithReply-Day-25_25_null_11,NEXUS_5,1.0,en]","ui_S_t[f.messages.impl.timeline.components_TimelineItemEventRowWithReply_null_TimelineItemEventRowWithReply-Night-25_26_null_11,NEXUS_5,1.0,en]",0,],
["ui_S_t[f.messages.impl.timeline.components_TimelineItemEventRowWithReply_null_TimelineItemEventRowWithReply-Day-25_25_null_2,NEXUS_5,1.0,en]","ui_S_t[f.messages.impl.timeline.components_TimelineItemEventRowWithReply_null_TimelineItemEventRowWithReply-Night-25_26_null_2,NEXUS_5,1.0,en]",0,],
["ui_S_t[f.messages.impl.timeline.components_TimelineItemEventRowWithReply_null_TimelineItemEventRowWithReply-Day-25_25_null_3,NEXUS_5,1.0,en]","ui_S_t[f.messages.impl.timeline.components_TimelineItemEventRowWithReply_null_TimelineItemEventRowWithReply-Night-25_26_null_3,NEXUS_5,1.0,en]",0,],
-["ui_S_t[f.messages.impl.timeline.components_TimelineItemEventRowWithReply_null_TimelineItemEventRowWithReply-Day-25_25_null_4,NEXUS_5,1.0,en]","ui_S_t[f.messages.impl.timeline.components_TimelineItemEventRowWithReply_null_TimelineItemEventRowWithReply-Night-25_26_null_4,NEXUS_5,1.0,en]",19849,],
+["ui_S_t[f.messages.impl.timeline.components_TimelineItemEventRowWithReply_null_TimelineItemEventRowWithReply-Day-25_25_null_4,NEXUS_5,1.0,en]","ui_S_t[f.messages.impl.timeline.components_TimelineItemEventRowWithReply_null_TimelineItemEventRowWithReply-Night-25_26_null_4,NEXUS_5,1.0,en]",19860,],
["ui_S_t[f.messages.impl.timeline.components_TimelineItemEventRowWithReply_null_TimelineItemEventRowWithReply-Day-25_25_null_5,NEXUS_5,1.0,en]","ui_S_t[f.messages.impl.timeline.components_TimelineItemEventRowWithReply_null_TimelineItemEventRowWithReply-Night-25_26_null_5,NEXUS_5,1.0,en]",0,],
["ui_S_t[f.messages.impl.timeline.components_TimelineItemEventRowWithReply_null_TimelineItemEventRowWithReply-Day-25_25_null_6,NEXUS_5,1.0,en]","ui_S_t[f.messages.impl.timeline.components_TimelineItemEventRowWithReply_null_TimelineItemEventRowWithReply-Night-25_26_null_6,NEXUS_5,1.0,en]",0,],
["ui_S_t[f.messages.impl.timeline.components_TimelineItemEventRowWithReply_null_TimelineItemEventRowWithReply-Day-25_25_null_7,NEXUS_5,1.0,en]","ui_S_t[f.messages.impl.timeline.components_TimelineItemEventRowWithReply_null_TimelineItemEventRowWithReply-Night-25_26_null_7,NEXUS_5,1.0,en]",0,],
-["ui_S_t[f.messages.impl.timeline.components_TimelineItemEventRowWithReply_null_TimelineItemEventRowWithReply-Day-25_25_null_8,NEXUS_5,1.0,en]","ui_S_t[f.messages.impl.timeline.components_TimelineItemEventRowWithReply_null_TimelineItemEventRowWithReply-Night-25_26_null_8,NEXUS_5,1.0,en]",19849,],
+["ui_S_t[f.messages.impl.timeline.components_TimelineItemEventRowWithReply_null_TimelineItemEventRowWithReply-Day-25_25_null_8,NEXUS_5,1.0,en]","ui_S_t[f.messages.impl.timeline.components_TimelineItemEventRowWithReply_null_TimelineItemEventRowWithReply-Night-25_26_null_8,NEXUS_5,1.0,en]",19860,],
["ui_S_t[f.messages.impl.timeline.components_TimelineItemEventRowWithReply_null_TimelineItemEventRowWithReply-Day-25_25_null_9,NEXUS_5,1.0,en]","ui_S_t[f.messages.impl.timeline.components_TimelineItemEventRowWithReply_null_TimelineItemEventRowWithReply-Night-25_26_null_9,NEXUS_5,1.0,en]",0,],
["ui_S_t[f.messages.impl.timeline.components_TimelineItemEventRow_null_TimelineItemEventRow-Day-17_17_null,NEXUS_5,1.0,en]","ui_S_t[f.messages.impl.timeline.components_TimelineItemEventRow_null_TimelineItemEventRow-Night-17_18_null,NEXUS_5,1.0,en]",0,],
-["ui_S_t[f.messages.impl.timeline.components_TimelineItemEventTimestampBelow_null_TimelineItemEventTimestampBelow_0_null,NEXUS_5,1.0,en]","",19846,],
+["ui_S_t[f.messages.impl.timeline.components_TimelineItemEventTimestampBelow_null_TimelineItemEventTimestampBelow_0_null,NEXUS_5,1.0,en]","",19860,],
["ui_S_t[f.messages.impl.timeline.components.event_TimelineItemFileView_null_TimelineItemFileView-Day-38_38_null_0,NEXUS_5,1.0,en]","ui_S_t[f.messages.impl.timeline.components.event_TimelineItemFileView_null_TimelineItemFileView-Night-38_39_null_0,NEXUS_5,1.0,en]",0,],
["ui_S_t[f.messages.impl.timeline.components.event_TimelineItemFileView_null_TimelineItemFileView-Day-38_38_null_1,NEXUS_5,1.0,en]","ui_S_t[f.messages.impl.timeline.components.event_TimelineItemFileView_null_TimelineItemFileView-Night-38_39_null_1,NEXUS_5,1.0,en]",0,],
["ui_S_t[f.messages.impl.timeline.components.event_TimelineItemFileView_null_TimelineItemFileView-Day-38_38_null_2,NEXUS_5,1.0,en]","ui_S_t[f.messages.impl.timeline.components.event_TimelineItemFileView_null_TimelineItemFileView-Night-38_39_null_2,NEXUS_5,1.0,en]",0,],
-["ui_S_t[f.messages.impl.timeline.components_TimelineItemGroupedEventsRowContentCollapse_null_TimelineItemGroupedEventsRowContentCollapse-Day-27_27_null,NEXUS_5,1.0,en]","ui_S_t[f.messages.impl.timeline.components_TimelineItemGroupedEventsRowContentCollapse_null_TimelineItemGroupedEventsRowContentCollapse-Night-27_28_null,NEXUS_5,1.0,en]",19849,],
-["ui_S_t[f.messages.impl.timeline.components_TimelineItemGroupedEventsRowContentExpanded_null_TimelineItemGroupedEventsRowContentExpanded-Day-26_26_null,NEXUS_5,1.0,en]","ui_S_t[f.messages.impl.timeline.components_TimelineItemGroupedEventsRowContentExpanded_null_TimelineItemGroupedEventsRowContentExpanded-Night-26_27_null,NEXUS_5,1.0,en]",19849,],
+["ui_S_t[f.messages.impl.timeline.components_TimelineItemGroupedEventsRowContentCollapse_null_TimelineItemGroupedEventsRowContentCollapse-Day-27_27_null,NEXUS_5,1.0,en]","ui_S_t[f.messages.impl.timeline.components_TimelineItemGroupedEventsRowContentCollapse_null_TimelineItemGroupedEventsRowContentCollapse-Night-27_28_null,NEXUS_5,1.0,en]",19860,],
+["ui_S_t[f.messages.impl.timeline.components_TimelineItemGroupedEventsRowContentExpanded_null_TimelineItemGroupedEventsRowContentExpanded-Day-26_26_null,NEXUS_5,1.0,en]","ui_S_t[f.messages.impl.timeline.components_TimelineItemGroupedEventsRowContentExpanded_null_TimelineItemGroupedEventsRowContentExpanded-Night-26_27_null,NEXUS_5,1.0,en]",19860,],
["ui_S_t[f.messages.impl.timeline.components.event_TimelineItemImageView_null_TimelineItemImageView-Day-39_39_null_0,NEXUS_5,1.0,en]","ui_S_t[f.messages.impl.timeline.components.event_TimelineItemImageView_null_TimelineItemImageView-Night-39_40_null_0,NEXUS_5,1.0,en]",0,],
["ui_S_t[f.messages.impl.timeline.components.event_TimelineItemImageView_null_TimelineItemImageView-Day-39_39_null_1,NEXUS_5,1.0,en]","ui_S_t[f.messages.impl.timeline.components.event_TimelineItemImageView_null_TimelineItemImageView-Night-39_40_null_1,NEXUS_5,1.0,en]",0,],
["ui_S_t[f.messages.impl.timeline.components.event_TimelineItemImageView_null_TimelineItemImageView-Day-39_39_null_2,NEXUS_5,1.0,en]","ui_S_t[f.messages.impl.timeline.components.event_TimelineItemImageView_null_TimelineItemImageView-Night-39_40_null_2,NEXUS_5,1.0,en]",0,],
["ui_S_t[f.messages.impl.timeline.components.event_TimelineItemInformativeView_null_TimelineItemInformativeView-Day-41_41_null,NEXUS_5,1.0,en]","ui_S_t[f.messages.impl.timeline.components.event_TimelineItemInformativeView_null_TimelineItemInformativeView-Night-41_42_null,NEXUS_5,1.0,en]",0,],
-["ui_S_t[f.messages.impl.timeline.components.event_TimelineItemLegacyCallInviteView_null_TimelineItemLegacyCallInviteView-Day-42_42_null,NEXUS_5,1.0,en]","ui_S_t[f.messages.impl.timeline.components.event_TimelineItemLegacyCallInviteView_null_TimelineItemLegacyCallInviteView-Night-42_43_null,NEXUS_5,1.0,en]",19849,],
+["ui_S_t[f.messages.impl.timeline.components.event_TimelineItemLegacyCallInviteView_null_TimelineItemLegacyCallInviteView-Day-42_42_null,NEXUS_5,1.0,en]","ui_S_t[f.messages.impl.timeline.components.event_TimelineItemLegacyCallInviteView_null_TimelineItemLegacyCallInviteView-Night-42_43_null,NEXUS_5,1.0,en]",19860,],
["ui_S_t[f.messages.impl.timeline.components.event_TimelineItemLocationView_null_TimelineItemLocationView-Day-43_43_null_0,NEXUS_5,1.0,en]","ui_S_t[f.messages.impl.timeline.components.event_TimelineItemLocationView_null_TimelineItemLocationView-Night-43_44_null_0,NEXUS_5,1.0,en]",0,],
["ui_S_t[f.messages.impl.timeline.components.event_TimelineItemLocationView_null_TimelineItemLocationView-Day-43_43_null_1,NEXUS_5,1.0,en]","ui_S_t[f.messages.impl.timeline.components.event_TimelineItemLocationView_null_TimelineItemLocationView-Night-43_44_null_1,NEXUS_5,1.0,en]",0,],
-["ui_S_t[f.messages.impl.timeline.components.event_TimelineItemPollView_null_TimelineItemPollView-Day-44_44_null_0,NEXUS_5,1.0,en]","ui_S_t[f.messages.impl.timeline.components.event_TimelineItemPollView_null_TimelineItemPollView-Night-44_45_null_0,NEXUS_5,1.0,en]",19849,],
-["ui_S_t[f.messages.impl.timeline.components.event_TimelineItemPollView_null_TimelineItemPollView-Day-44_44_null_1,NEXUS_5,1.0,en]","ui_S_t[f.messages.impl.timeline.components.event_TimelineItemPollView_null_TimelineItemPollView-Night-44_45_null_1,NEXUS_5,1.0,en]",19849,],
-["ui_S_t[f.messages.impl.timeline.components.event_TimelineItemPollView_null_TimelineItemPollView-Day-44_44_null_2,NEXUS_5,1.0,en]","ui_S_t[f.messages.impl.timeline.components.event_TimelineItemPollView_null_TimelineItemPollView-Night-44_45_null_2,NEXUS_5,1.0,en]",19849,],
-["ui_S_t[f.messages.impl.timeline.components.event_TimelineItemPollView_null_TimelineItemPollView-Day-44_44_null_3,NEXUS_5,1.0,en]","ui_S_t[f.messages.impl.timeline.components.event_TimelineItemPollView_null_TimelineItemPollView-Night-44_45_null_3,NEXUS_5,1.0,en]",19849,],
-["ui_S_t[f.messages.impl.timeline.components_TimelineItemReactionsLayout_null_TimelineItemReactionsLayout-Day-28_28_null,NEXUS_5,1.0,en]","ui_S_t[f.messages.impl.timeline.components_TimelineItemReactionsLayout_null_TimelineItemReactionsLayout-Night-28_29_null,NEXUS_5,1.0,en]",19849,],
+["ui_S_t[f.messages.impl.timeline.components.event_TimelineItemPollView_null_TimelineItemPollView-Day-44_44_null_0,NEXUS_5,1.0,en]","ui_S_t[f.messages.impl.timeline.components.event_TimelineItemPollView_null_TimelineItemPollView-Night-44_45_null_0,NEXUS_5,1.0,en]",19860,],
+["ui_S_t[f.messages.impl.timeline.components.event_TimelineItemPollView_null_TimelineItemPollView-Day-44_44_null_1,NEXUS_5,1.0,en]","ui_S_t[f.messages.impl.timeline.components.event_TimelineItemPollView_null_TimelineItemPollView-Night-44_45_null_1,NEXUS_5,1.0,en]",19860,],
+["ui_S_t[f.messages.impl.timeline.components.event_TimelineItemPollView_null_TimelineItemPollView-Day-44_44_null_2,NEXUS_5,1.0,en]","ui_S_t[f.messages.impl.timeline.components.event_TimelineItemPollView_null_TimelineItemPollView-Night-44_45_null_2,NEXUS_5,1.0,en]",19860,],
+["ui_S_t[f.messages.impl.timeline.components.event_TimelineItemPollView_null_TimelineItemPollView-Day-44_44_null_3,NEXUS_5,1.0,en]","ui_S_t[f.messages.impl.timeline.components.event_TimelineItemPollView_null_TimelineItemPollView-Night-44_45_null_3,NEXUS_5,1.0,en]",19860,],
+["ui_S_t[f.messages.impl.timeline.components_TimelineItemReactionsLayout_null_TimelineItemReactionsLayout-Day-28_28_null,NEXUS_5,1.0,en]","ui_S_t[f.messages.impl.timeline.components_TimelineItemReactionsLayout_null_TimelineItemReactionsLayout-Night-28_29_null,NEXUS_5,1.0,en]",19860,],
["ui_S_t[f.messages.impl.timeline.components_TimelineItemReactionsViewFew_null_TimelineItemReactionsViewFew-Day-30_30_null,NEXUS_5,1.0,en]","ui_S_t[f.messages.impl.timeline.components_TimelineItemReactionsViewFew_null_TimelineItemReactionsViewFew-Night-30_31_null,NEXUS_5,1.0,en]",0,],
-["ui_S_t[f.messages.impl.timeline.components_TimelineItemReactionsViewIncoming_null_TimelineItemReactionsViewIncoming-Day-31_31_null,NEXUS_5,1.0,en]","ui_S_t[f.messages.impl.timeline.components_TimelineItemReactionsViewIncoming_null_TimelineItemReactionsViewIncoming-Night-31_32_null,NEXUS_5,1.0,en]",19849,],
-["ui_S_t[f.messages.impl.timeline.components_TimelineItemReactionsViewOutgoing_null_TimelineItemReactionsViewOutgoing-Day-32_32_null,NEXUS_5,1.0,en]","ui_S_t[f.messages.impl.timeline.components_TimelineItemReactionsViewOutgoing_null_TimelineItemReactionsViewOutgoing-Night-32_33_null,NEXUS_5,1.0,en]",19849,],
+["ui_S_t[f.messages.impl.timeline.components_TimelineItemReactionsViewIncoming_null_TimelineItemReactionsViewIncoming-Day-31_31_null,NEXUS_5,1.0,en]","ui_S_t[f.messages.impl.timeline.components_TimelineItemReactionsViewIncoming_null_TimelineItemReactionsViewIncoming-Night-31_32_null,NEXUS_5,1.0,en]",19860,],
+["ui_S_t[f.messages.impl.timeline.components_TimelineItemReactionsViewOutgoing_null_TimelineItemReactionsViewOutgoing-Day-32_32_null,NEXUS_5,1.0,en]","ui_S_t[f.messages.impl.timeline.components_TimelineItemReactionsViewOutgoing_null_TimelineItemReactionsViewOutgoing-Night-32_33_null,NEXUS_5,1.0,en]",19860,],
["ui_S_t[f.messages.impl.timeline.components_TimelineItemReactionsView_null_TimelineItemReactionsView-Day-29_29_null,NEXUS_5,1.0,en]","ui_S_t[f.messages.impl.timeline.components_TimelineItemReactionsView_null_TimelineItemReactionsView-Night-29_30_null,NEXUS_5,1.0,en]",0,],
-["ui_S_t[f.messages.impl.timeline.components.virtual_TimelineItemReadMarkerView_null_TimelineItemReadMarkerView-Day-62_62_null,NEXUS_5,1.0,en]","ui_S_t[f.messages.impl.timeline.components.virtual_TimelineItemReadMarkerView_null_TimelineItemReadMarkerView-Night-62_63_null,NEXUS_5,1.0,en]",19849,],
+["ui_S_t[f.messages.impl.timeline.components.virtual_TimelineItemReadMarkerView_null_TimelineItemReadMarkerView-Day-62_62_null,NEXUS_5,1.0,en]","ui_S_t[f.messages.impl.timeline.components.virtual_TimelineItemReadMarkerView_null_TimelineItemReadMarkerView-Night-62_63_null,NEXUS_5,1.0,en]",19860,],
["ui_S_t[f.messages.impl.timeline.components.receipt_TimelineItemReadReceiptView_null_TimelineItemReadReceiptView-Day-57_57_null_0,NEXUS_5,1.0,en]","ui_S_t[f.messages.impl.timeline.components.receipt_TimelineItemReadReceiptView_null_TimelineItemReadReceiptView-Night-57_58_null_0,NEXUS_5,1.0,en]",0,],
["ui_S_t[f.messages.impl.timeline.components.receipt_TimelineItemReadReceiptView_null_TimelineItemReadReceiptView-Day-57_57_null_1,NEXUS_5,1.0,en]","ui_S_t[f.messages.impl.timeline.components.receipt_TimelineItemReadReceiptView_null_TimelineItemReadReceiptView-Night-57_58_null_1,NEXUS_5,1.0,en]",0,],
["ui_S_t[f.messages.impl.timeline.components.receipt_TimelineItemReadReceiptView_null_TimelineItemReadReceiptView-Day-57_57_null_2,NEXUS_5,1.0,en]","ui_S_t[f.messages.impl.timeline.components.receipt_TimelineItemReadReceiptView_null_TimelineItemReadReceiptView-Night-57_58_null_2,NEXUS_5,1.0,en]",0,],
@@ -918,8 +926,8 @@ export const screenshots = [
["ui_S_t[f.messages.impl.timeline.components.receipt_TimelineItemReadReceiptView_null_TimelineItemReadReceiptView-Day-57_57_null_5,NEXUS_5,1.0,en]","ui_S_t[f.messages.impl.timeline.components.receipt_TimelineItemReadReceiptView_null_TimelineItemReadReceiptView-Night-57_58_null_5,NEXUS_5,1.0,en]",0,],
["ui_S_t[f.messages.impl.timeline.components.receipt_TimelineItemReadReceiptView_null_TimelineItemReadReceiptView-Day-57_57_null_6,NEXUS_5,1.0,en]","ui_S_t[f.messages.impl.timeline.components.receipt_TimelineItemReadReceiptView_null_TimelineItemReadReceiptView-Night-57_58_null_6,NEXUS_5,1.0,en]",0,],
["ui_S_t[f.messages.impl.timeline.components.receipt_TimelineItemReadReceiptView_null_TimelineItemReadReceiptView-Day-57_57_null_7,NEXUS_5,1.0,en]","ui_S_t[f.messages.impl.timeline.components.receipt_TimelineItemReadReceiptView_null_TimelineItemReadReceiptView-Night-57_58_null_7,NEXUS_5,1.0,en]",0,],
-["ui_S_t[f.messages.impl.timeline.components.event_TimelineItemRedactedView_null_TimelineItemRedactedView-Day-45_45_null,NEXUS_5,1.0,en]","ui_S_t[f.messages.impl.timeline.components.event_TimelineItemRedactedView_null_TimelineItemRedactedView-Night-45_46_null,NEXUS_5,1.0,en]",19849,],
-["ui_S_t[f.messages.impl.timeline.components.virtual_TimelineItemRoomBeginningView_null_TimelineItemRoomBeginningView-Day-63_63_null,NEXUS_5,1.0,en]","ui_S_t[f.messages.impl.timeline.components.virtual_TimelineItemRoomBeginningView_null_TimelineItemRoomBeginningView-Night-63_64_null,NEXUS_5,1.0,en]",19849,],
+["ui_S_t[f.messages.impl.timeline.components.event_TimelineItemRedactedView_null_TimelineItemRedactedView-Day-45_45_null,NEXUS_5,1.0,en]","ui_S_t[f.messages.impl.timeline.components.event_TimelineItemRedactedView_null_TimelineItemRedactedView-Night-45_46_null,NEXUS_5,1.0,en]",19860,],
+["ui_S_t[f.messages.impl.timeline.components.virtual_TimelineItemRoomBeginningView_null_TimelineItemRoomBeginningView-Day-63_63_null,NEXUS_5,1.0,en]","ui_S_t[f.messages.impl.timeline.components.virtual_TimelineItemRoomBeginningView_null_TimelineItemRoomBeginningView-Night-63_64_null,NEXUS_5,1.0,en]",19860,],
["ui_S_t[f.messages.impl.timeline.components_TimelineItemStateEventRow_null_TimelineItemStateEventRow-Day-33_33_null,NEXUS_5,1.0,en]","ui_S_t[f.messages.impl.timeline.components_TimelineItemStateEventRow_null_TimelineItemStateEventRow-Night-33_34_null,NEXUS_5,1.0,en]",0,],
["ui_S_t[f.messages.impl.timeline.components.event_TimelineItemStateView_null_TimelineItemStateView-Day-46_46_null,NEXUS_5,1.0,en]","ui_S_t[f.messages.impl.timeline.components.event_TimelineItemStateView_null_TimelineItemStateView-Night-46_47_null,NEXUS_5,1.0,en]",0,],
["ui_S_t[f.messages.impl.timeline.components.event_TimelineItemStickerView_null_TimelineItemStickerView-Day-47_47_null_0,NEXUS_5,1.0,en]","ui_S_t[f.messages.impl.timeline.components.event_TimelineItemStickerView_null_TimelineItemStickerView-Night-47_48_null_0,NEXUS_5,1.0,en]",0,],
@@ -931,7 +939,7 @@ export const screenshots = [
["ui_S_t[f.messages.impl.timeline.components.event_TimelineItemTextView_null_TimelineItemTextView-Day-48_48_null_3,NEXUS_5,1.0,en]","ui_S_t[f.messages.impl.timeline.components.event_TimelineItemTextView_null_TimelineItemTextView-Night-48_49_null_3,NEXUS_5,1.0,en]",0,],
["ui_S_t[f.messages.impl.timeline.components.event_TimelineItemTextView_null_TimelineItemTextView-Day-48_48_null_4,NEXUS_5,1.0,en]","ui_S_t[f.messages.impl.timeline.components.event_TimelineItemTextView_null_TimelineItemTextView-Night-48_49_null_4,NEXUS_5,1.0,en]",0,],
["ui_S_t[f.messages.impl.timeline.components.event_TimelineItemTextView_null_TimelineItemTextView-Day-48_48_null_5,NEXUS_5,1.0,en]","ui_S_t[f.messages.impl.timeline.components.event_TimelineItemTextView_null_TimelineItemTextView-Night-48_49_null_5,NEXUS_5,1.0,en]",0,],
-["ui_S_t[f.messages.impl.timeline.components.event_TimelineItemUnknownView_null_TimelineItemUnknownView-Day-49_49_null,NEXUS_5,1.0,en]","ui_S_t[f.messages.impl.timeline.components.event_TimelineItemUnknownView_null_TimelineItemUnknownView-Night-49_50_null,NEXUS_5,1.0,en]",19849,],
+["ui_S_t[f.messages.impl.timeline.components.event_TimelineItemUnknownView_null_TimelineItemUnknownView-Day-49_49_null,NEXUS_5,1.0,en]","ui_S_t[f.messages.impl.timeline.components.event_TimelineItemUnknownView_null_TimelineItemUnknownView-Night-49_50_null,NEXUS_5,1.0,en]",19860,],
["ui_S_t[f.messages.impl.timeline.components.event_TimelineItemVideoView_null_TimelineItemVideoView-Day-50_50_null_0,NEXUS_5,1.0,en]","ui_S_t[f.messages.impl.timeline.components.event_TimelineItemVideoView_null_TimelineItemVideoView-Night-50_51_null_0,NEXUS_5,1.0,en]",0,],
["ui_S_t[f.messages.impl.timeline.components.event_TimelineItemVideoView_null_TimelineItemVideoView-Day-50_50_null_1,NEXUS_5,1.0,en]","ui_S_t[f.messages.impl.timeline.components.event_TimelineItemVideoView_null_TimelineItemVideoView-Night-50_51_null_1,NEXUS_5,1.0,en]",0,],
["ui_S_t[f.messages.impl.timeline.components.event_TimelineItemVideoView_null_TimelineItemVideoView-Day-50_50_null_2,NEXUS_5,1.0,en]","ui_S_t[f.messages.impl.timeline.components.event_TimelineItemVideoView_null_TimelineItemVideoView-Night-50_51_null_2,NEXUS_5,1.0,en]",0,],
@@ -953,76 +961,78 @@ export const screenshots = [
["ui_S_t[f.messages.impl.timeline.components.event_TimelineItemVoiceView_null_TimelineItemVoiceView-Day-52_52_null_9,NEXUS_5,1.0,en]","ui_S_t[f.messages.impl.timeline.components.event_TimelineItemVoiceView_null_TimelineItemVoiceView-Night-52_53_null_9,NEXUS_5,1.0,en]",0,],
["ui_S_t[f.messages.impl.timeline.components.virtual_TimelineLoadingMoreIndicator_null_TimelineLoadingMoreIndicator-Day-64_64_null,NEXUS_5,1.0,en]","ui_S_t[f.messages.impl.timeline.components.virtual_TimelineLoadingMoreIndicator_null_TimelineLoadingMoreIndicator-Night-64_65_null,NEXUS_5,1.0,en]",0,],
["ui_S_t[f.messages.impl.timeline.components.event_TimelineVideoWithCaptionRow_null_TimelineVideoWithCaptionRow-Day-51_51_null,NEXUS_5,1.0,en]","ui_S_t[f.messages.impl.timeline.components.event_TimelineVideoWithCaptionRow_null_TimelineVideoWithCaptionRow-Night-51_52_null,NEXUS_5,1.0,en]",0,],
-["ui_S_t[f.messages.impl.timeline_TimelineView_null_TimelineView-Day-9_9_null_0,NEXUS_5,1.0,en]","ui_S_t[f.messages.impl.timeline_TimelineView_null_TimelineView-Night-9_10_null_0,NEXUS_5,1.0,en]",19846,],
-["ui_S_t[f.messages.impl.timeline_TimelineView_null_TimelineView-Day-9_9_null_1,NEXUS_5,1.0,en]","ui_S_t[f.messages.impl.timeline_TimelineView_null_TimelineView-Night-9_10_null_1,NEXUS_5,1.0,en]",19846,],
+["ui_S_t[f.messages.impl.timeline_TimelineView_null_TimelineView-Day-9_9_null_0,NEXUS_5,1.0,en]","ui_S_t[f.messages.impl.timeline_TimelineView_null_TimelineView-Night-9_10_null_0,NEXUS_5,1.0,en]",19860,],
+["ui_S_t[f.messages.impl.timeline_TimelineView_null_TimelineView-Day-9_9_null_1,NEXUS_5,1.0,en]","ui_S_t[f.messages.impl.timeline_TimelineView_null_TimelineView-Night-9_10_null_1,NEXUS_5,1.0,en]",19860,],
["ui_S_t[f.messages.impl.timeline_TimelineView_null_TimelineView-Day-9_9_null_10,NEXUS_5,1.0,en]","ui_S_t[f.messages.impl.timeline_TimelineView_null_TimelineView-Night-9_10_null_10,NEXUS_5,1.0,en]",0,],
-["ui_S_t[f.messages.impl.timeline_TimelineView_null_TimelineView-Day-9_9_null_11,NEXUS_5,1.0,en]","ui_S_t[f.messages.impl.timeline_TimelineView_null_TimelineView-Night-9_10_null_11,NEXUS_5,1.0,en]",19846,],
-["ui_S_t[f.messages.impl.timeline_TimelineView_null_TimelineView-Day-9_9_null_12,NEXUS_5,1.0,en]","ui_S_t[f.messages.impl.timeline_TimelineView_null_TimelineView-Night-9_10_null_12,NEXUS_5,1.0,en]",19846,],
-["ui_S_t[f.messages.impl.timeline_TimelineView_null_TimelineView-Day-9_9_null_13,NEXUS_5,1.0,en]","ui_S_t[f.messages.impl.timeline_TimelineView_null_TimelineView-Night-9_10_null_13,NEXUS_5,1.0,en]",19846,],
-["ui_S_t[f.messages.impl.timeline_TimelineView_null_TimelineView-Day-9_9_null_14,NEXUS_5,1.0,en]","ui_S_t[f.messages.impl.timeline_TimelineView_null_TimelineView-Night-9_10_null_14,NEXUS_5,1.0,en]",19846,],
-["ui_S_t[f.messages.impl.timeline_TimelineView_null_TimelineView-Day-9_9_null_15,NEXUS_5,1.0,en]","ui_S_t[f.messages.impl.timeline_TimelineView_null_TimelineView-Night-9_10_null_15,NEXUS_5,1.0,en]",19846,],
-["ui_S_t[f.messages.impl.timeline_TimelineView_null_TimelineView-Day-9_9_null_16,NEXUS_5,1.0,en]","ui_S_t[f.messages.impl.timeline_TimelineView_null_TimelineView-Night-9_10_null_16,NEXUS_5,1.0,en]",19846,],
+["ui_S_t[f.messages.impl.timeline_TimelineView_null_TimelineView-Day-9_9_null_11,NEXUS_5,1.0,en]","ui_S_t[f.messages.impl.timeline_TimelineView_null_TimelineView-Night-9_10_null_11,NEXUS_5,1.0,en]",19860,],
+["ui_S_t[f.messages.impl.timeline_TimelineView_null_TimelineView-Day-9_9_null_12,NEXUS_5,1.0,en]","ui_S_t[f.messages.impl.timeline_TimelineView_null_TimelineView-Night-9_10_null_12,NEXUS_5,1.0,en]",19860,],
+["ui_S_t[f.messages.impl.timeline_TimelineView_null_TimelineView-Day-9_9_null_13,NEXUS_5,1.0,en]","ui_S_t[f.messages.impl.timeline_TimelineView_null_TimelineView-Night-9_10_null_13,NEXUS_5,1.0,en]",19860,],
+["ui_S_t[f.messages.impl.timeline_TimelineView_null_TimelineView-Day-9_9_null_14,NEXUS_5,1.0,en]","ui_S_t[f.messages.impl.timeline_TimelineView_null_TimelineView-Night-9_10_null_14,NEXUS_5,1.0,en]",19860,],
+["ui_S_t[f.messages.impl.timeline_TimelineView_null_TimelineView-Day-9_9_null_15,NEXUS_5,1.0,en]","ui_S_t[f.messages.impl.timeline_TimelineView_null_TimelineView-Night-9_10_null_15,NEXUS_5,1.0,en]",19860,],
+["ui_S_t[f.messages.impl.timeline_TimelineView_null_TimelineView-Day-9_9_null_16,NEXUS_5,1.0,en]","ui_S_t[f.messages.impl.timeline_TimelineView_null_TimelineView-Night-9_10_null_16,NEXUS_5,1.0,en]",19860,],
["ui_S_t[f.messages.impl.timeline_TimelineView_null_TimelineView-Day-9_9_null_2,NEXUS_5,1.0,en]","ui_S_t[f.messages.impl.timeline_TimelineView_null_TimelineView-Night-9_10_null_2,NEXUS_5,1.0,en]",0,],
["ui_S_t[f.messages.impl.timeline_TimelineView_null_TimelineView-Day-9_9_null_3,NEXUS_5,1.0,en]","ui_S_t[f.messages.impl.timeline_TimelineView_null_TimelineView-Night-9_10_null_3,NEXUS_5,1.0,en]",0,],
-["ui_S_t[f.messages.impl.timeline_TimelineView_null_TimelineView-Day-9_9_null_4,NEXUS_5,1.0,en]","ui_S_t[f.messages.impl.timeline_TimelineView_null_TimelineView-Night-9_10_null_4,NEXUS_5,1.0,en]",19846,],
+["ui_S_t[f.messages.impl.timeline_TimelineView_null_TimelineView-Day-9_9_null_4,NEXUS_5,1.0,en]","ui_S_t[f.messages.impl.timeline_TimelineView_null_TimelineView-Night-9_10_null_4,NEXUS_5,1.0,en]",19860,],
["ui_S_t[f.messages.impl.timeline_TimelineView_null_TimelineView-Day-9_9_null_5,NEXUS_5,1.0,en]","ui_S_t[f.messages.impl.timeline_TimelineView_null_TimelineView-Night-9_10_null_5,NEXUS_5,1.0,en]",0,],
-["ui_S_t[f.messages.impl.timeline_TimelineView_null_TimelineView-Day-9_9_null_6,NEXUS_5,1.0,en]","ui_S_t[f.messages.impl.timeline_TimelineView_null_TimelineView-Night-9_10_null_6,NEXUS_5,1.0,en]",19846,],
+["ui_S_t[f.messages.impl.timeline_TimelineView_null_TimelineView-Day-9_9_null_6,NEXUS_5,1.0,en]","ui_S_t[f.messages.impl.timeline_TimelineView_null_TimelineView-Night-9_10_null_6,NEXUS_5,1.0,en]",19860,],
["ui_S_t[f.messages.impl.timeline_TimelineView_null_TimelineView-Day-9_9_null_7,NEXUS_5,1.0,en]","ui_S_t[f.messages.impl.timeline_TimelineView_null_TimelineView-Night-9_10_null_7,NEXUS_5,1.0,en]",0,],
-["ui_S_t[f.messages.impl.timeline_TimelineView_null_TimelineView-Day-9_9_null_8,NEXUS_5,1.0,en]","ui_S_t[f.messages.impl.timeline_TimelineView_null_TimelineView-Night-9_10_null_8,NEXUS_5,1.0,en]",19846,],
+["ui_S_t[f.messages.impl.timeline_TimelineView_null_TimelineView-Day-9_9_null_8,NEXUS_5,1.0,en]","ui_S_t[f.messages.impl.timeline_TimelineView_null_TimelineView-Night-9_10_null_8,NEXUS_5,1.0,en]",19860,],
["ui_S_t[f.messages.impl.timeline_TimelineView_null_TimelineView-Day-9_9_null_9,NEXUS_5,1.0,en]","ui_S_t[f.messages.impl.timeline_TimelineView_null_TimelineView-Night-9_10_null_9,NEXUS_5,1.0,en]",0,],
["ui_S_t[l.designsystem.theme.components_TopAppBar_null_AppBars_TopAppBar_0_null,NEXUS_5,1.0,en]","",0,],
-["ui_S_t[l.troubleshoot.impl_TroubleshootNotificationsView_null_TroubleshootNotificationsView-Day-0_1_null_0,NEXUS_5,1.0,en]","ui_S_t[l.troubleshoot.impl_TroubleshootNotificationsView_null_TroubleshootNotificationsView-Night-0_2_null_0,NEXUS_5,1.0,en]",19846,],
-["ui_S_t[l.troubleshoot.impl_TroubleshootNotificationsView_null_TroubleshootNotificationsView-Day-0_1_null_1,NEXUS_5,1.0,en]","ui_S_t[l.troubleshoot.impl_TroubleshootNotificationsView_null_TroubleshootNotificationsView-Night-0_2_null_1,NEXUS_5,1.0,en]",19846,],
-["ui_S_t[l.troubleshoot.impl_TroubleshootNotificationsView_null_TroubleshootNotificationsView-Day-0_1_null_2,NEXUS_5,1.0,en]","ui_S_t[l.troubleshoot.impl_TroubleshootNotificationsView_null_TroubleshootNotificationsView-Night-0_2_null_2,NEXUS_5,1.0,en]",19846,],
-["ui_S_t[l.troubleshoot.impl_TroubleshootNotificationsView_null_TroubleshootNotificationsView-Day-0_1_null_3,NEXUS_5,1.0,en]","ui_S_t[l.troubleshoot.impl_TroubleshootNotificationsView_null_TroubleshootNotificationsView-Night-0_2_null_3,NEXUS_5,1.0,en]",19846,],
-["ui_S_t[l.troubleshoot.impl_TroubleshootNotificationsView_null_TroubleshootNotificationsView-Day-0_1_null_4,NEXUS_5,1.0,en]","ui_S_t[l.troubleshoot.impl_TroubleshootNotificationsView_null_TroubleshootNotificationsView-Night-0_2_null_4,NEXUS_5,1.0,en]",19846,],
-["ui_S_t[l.troubleshoot.impl_TroubleshootNotificationsView_null_TroubleshootNotificationsView-Day-0_1_null_5,NEXUS_5,1.0,en]","ui_S_t[l.troubleshoot.impl_TroubleshootNotificationsView_null_TroubleshootNotificationsView-Night-0_2_null_5,NEXUS_5,1.0,en]",19846,],
-["ui_S_t[l.troubleshoot.impl_TroubleshootNotificationsView_null_TroubleshootNotificationsView-Day-0_1_null_6,NEXUS_5,1.0,en]","ui_S_t[l.troubleshoot.impl_TroubleshootNotificationsView_null_TroubleshootNotificationsView-Night-0_2_null_6,NEXUS_5,1.0,en]",19846,],
-["ui_S_t[l.troubleshoot.impl_TroubleshootNotificationsView_null_TroubleshootNotificationsView-Day-0_1_null_7,NEXUS_5,1.0,en]","ui_S_t[l.troubleshoot.impl_TroubleshootNotificationsView_null_TroubleshootNotificationsView-Night-0_2_null_7,NEXUS_5,1.0,en]",19846,],
+["ui_S_t[l.troubleshoot.impl_TroubleshootNotificationsView_null_TroubleshootNotificationsView-Day-0_1_null_0,NEXUS_5,1.0,en]","ui_S_t[l.troubleshoot.impl_TroubleshootNotificationsView_null_TroubleshootNotificationsView-Night-0_2_null_0,NEXUS_5,1.0,en]",19860,],
+["ui_S_t[l.troubleshoot.impl_TroubleshootNotificationsView_null_TroubleshootNotificationsView-Day-0_1_null_1,NEXUS_5,1.0,en]","ui_S_t[l.troubleshoot.impl_TroubleshootNotificationsView_null_TroubleshootNotificationsView-Night-0_2_null_1,NEXUS_5,1.0,en]",19860,],
+["ui_S_t[l.troubleshoot.impl_TroubleshootNotificationsView_null_TroubleshootNotificationsView-Day-0_1_null_2,NEXUS_5,1.0,en]","ui_S_t[l.troubleshoot.impl_TroubleshootNotificationsView_null_TroubleshootNotificationsView-Night-0_2_null_2,NEXUS_5,1.0,en]",19860,],
+["ui_S_t[l.troubleshoot.impl_TroubleshootNotificationsView_null_TroubleshootNotificationsView-Day-0_1_null_3,NEXUS_5,1.0,en]","ui_S_t[l.troubleshoot.impl_TroubleshootNotificationsView_null_TroubleshootNotificationsView-Night-0_2_null_3,NEXUS_5,1.0,en]",19860,],
+["ui_S_t[l.troubleshoot.impl_TroubleshootNotificationsView_null_TroubleshootNotificationsView-Day-0_1_null_4,NEXUS_5,1.0,en]","ui_S_t[l.troubleshoot.impl_TroubleshootNotificationsView_null_TroubleshootNotificationsView-Night-0_2_null_4,NEXUS_5,1.0,en]",19860,],
+["ui_S_t[l.troubleshoot.impl_TroubleshootNotificationsView_null_TroubleshootNotificationsView-Day-0_1_null_5,NEXUS_5,1.0,en]","ui_S_t[l.troubleshoot.impl_TroubleshootNotificationsView_null_TroubleshootNotificationsView-Night-0_2_null_5,NEXUS_5,1.0,en]",19860,],
+["ui_S_t[l.troubleshoot.impl_TroubleshootNotificationsView_null_TroubleshootNotificationsView-Day-0_1_null_6,NEXUS_5,1.0,en]","ui_S_t[l.troubleshoot.impl_TroubleshootNotificationsView_null_TroubleshootNotificationsView-Night-0_2_null_6,NEXUS_5,1.0,en]",19860,],
+["ui_S_t[l.troubleshoot.impl_TroubleshootNotificationsView_null_TroubleshootNotificationsView-Day-0_1_null_7,NEXUS_5,1.0,en]","ui_S_t[l.troubleshoot.impl_TroubleshootNotificationsView_null_TroubleshootNotificationsView-Night-0_2_null_7,NEXUS_5,1.0,en]",19860,],
["ui_S_t[f.messages.impl.typing_TypingNotificationView_null_TypingNotificationView-Day-68_68_null_0,NEXUS_5,1.0,en]","ui_S_t[f.messages.impl.typing_TypingNotificationView_null_TypingNotificationView-Night-68_69_null_0,NEXUS_5,1.0,en]",0,],
-["ui_S_t[f.messages.impl.typing_TypingNotificationView_null_TypingNotificationView-Day-68_68_null_1,NEXUS_5,1.0,en]","ui_S_t[f.messages.impl.typing_TypingNotificationView_null_TypingNotificationView-Night-68_69_null_1,NEXUS_5,1.0,en]",19849,],
-["ui_S_t[f.messages.impl.typing_TypingNotificationView_null_TypingNotificationView-Day-68_68_null_2,NEXUS_5,1.0,en]","ui_S_t[f.messages.impl.typing_TypingNotificationView_null_TypingNotificationView-Night-68_69_null_2,NEXUS_5,1.0,en]",19849,],
-["ui_S_t[f.messages.impl.typing_TypingNotificationView_null_TypingNotificationView-Day-68_68_null_3,NEXUS_5,1.0,en]","ui_S_t[f.messages.impl.typing_TypingNotificationView_null_TypingNotificationView-Night-68_69_null_3,NEXUS_5,1.0,en]",19849,],
-["ui_S_t[f.messages.impl.typing_TypingNotificationView_null_TypingNotificationView-Day-68_68_null_4,NEXUS_5,1.0,en]","ui_S_t[f.messages.impl.typing_TypingNotificationView_null_TypingNotificationView-Night-68_69_null_4,NEXUS_5,1.0,en]",19849,],
-["ui_S_t[f.messages.impl.typing_TypingNotificationView_null_TypingNotificationView-Day-68_68_null_5,NEXUS_5,1.0,en]","ui_S_t[f.messages.impl.typing_TypingNotificationView_null_TypingNotificationView-Night-68_69_null_5,NEXUS_5,1.0,en]",19849,],
-["ui_S_t[f.messages.impl.typing_TypingNotificationView_null_TypingNotificationView-Day-68_68_null_6,NEXUS_5,1.0,en]","ui_S_t[f.messages.impl.typing_TypingNotificationView_null_TypingNotificationView-Night-68_69_null_6,NEXUS_5,1.0,en]",19849,],
+["ui_S_t[f.messages.impl.typing_TypingNotificationView_null_TypingNotificationView-Day-68_68_null_1,NEXUS_5,1.0,en]","ui_S_t[f.messages.impl.typing_TypingNotificationView_null_TypingNotificationView-Night-68_69_null_1,NEXUS_5,1.0,en]",19860,],
+["ui_S_t[f.messages.impl.typing_TypingNotificationView_null_TypingNotificationView-Day-68_68_null_2,NEXUS_5,1.0,en]","ui_S_t[f.messages.impl.typing_TypingNotificationView_null_TypingNotificationView-Night-68_69_null_2,NEXUS_5,1.0,en]",19860,],
+["ui_S_t[f.messages.impl.typing_TypingNotificationView_null_TypingNotificationView-Day-68_68_null_3,NEXUS_5,1.0,en]","ui_S_t[f.messages.impl.typing_TypingNotificationView_null_TypingNotificationView-Night-68_69_null_3,NEXUS_5,1.0,en]",19860,],
+["ui_S_t[f.messages.impl.typing_TypingNotificationView_null_TypingNotificationView-Day-68_68_null_4,NEXUS_5,1.0,en]","ui_S_t[f.messages.impl.typing_TypingNotificationView_null_TypingNotificationView-Night-68_69_null_4,NEXUS_5,1.0,en]",19860,],
+["ui_S_t[f.messages.impl.typing_TypingNotificationView_null_TypingNotificationView-Day-68_68_null_5,NEXUS_5,1.0,en]","ui_S_t[f.messages.impl.typing_TypingNotificationView_null_TypingNotificationView-Night-68_69_null_5,NEXUS_5,1.0,en]",19860,],
+["ui_S_t[f.messages.impl.typing_TypingNotificationView_null_TypingNotificationView-Day-68_68_null_6,NEXUS_5,1.0,en]","ui_S_t[f.messages.impl.typing_TypingNotificationView_null_TypingNotificationView-Night-68_69_null_6,NEXUS_5,1.0,en]",19860,],
["ui_S_t[f.messages.impl.typing_TypingNotificationView_null_TypingNotificationView-Day-68_68_null_7,NEXUS_5,1.0,en]","ui_S_t[f.messages.impl.typing_TypingNotificationView_null_TypingNotificationView-Night-68_69_null_7,NEXUS_5,1.0,en]",0,],
["ui_S_t[f.messages.impl.typing_TypingNotificationView_null_TypingNotificationView-Day-68_68_null_8,NEXUS_5,1.0,en]","ui_S_t[f.messages.impl.typing_TypingNotificationView_null_TypingNotificationView-Night-68_69_null_8,NEXUS_5,1.0,en]",0,],
["ui_S_t[l.designsystem.atomic.atoms_UnreadIndicatorAtom_null_UnreadIndicatorAtom-Day_0_null,NEXUS_5,1.0,en]","ui_S_t[l.designsystem.atomic.atoms_UnreadIndicatorAtom_null_UnreadIndicatorAtom-Night_1_null,NEXUS_5,1.0,en]",0,],
-["ui_S_t[l.matrix.ui.components_UnresolvedUserRow_null_UnresolvedUserRow_0_null,NEXUS_5,1.0,en]","",19846,],
-["ui_S_t[l.matrix.ui.components_UnsavedAvatar_null_UnsavedAvatar-Day-10_11_null,NEXUS_5,1.0,en]","ui_S_t[l.matrix.ui.components_UnsavedAvatar_null_UnsavedAvatar-Night-10_12_null,NEXUS_5,1.0,en]",0,],
+["ui_S_t[l.matrix.ui.components_UnresolvedUserRow_null_UnresolvedUserRow_0_null,NEXUS_5,1.0,en]","",19860,],
+["ui_S_t[l.matrix.ui.components_UnsavedAvatar_null_UnsavedAvatar-Day-11_12_null,NEXUS_5,1.0,en]","ui_S_t[l.matrix.ui.components_UnsavedAvatar_null_UnsavedAvatar-Night-11_13_null,NEXUS_5,1.0,en]",0,],
["ui_S_t[l.designsystem.components.avatar_UserAvatarColors_null_UserAvatarColors-Day_0_null,NEXUS_5,1.0,en]","ui_S_t[l.designsystem.components.avatar_UserAvatarColors_null_UserAvatarColors-Night_1_null,NEXUS_5,1.0,en]",0,],
-["ui_S_t[f.roomdetails.impl.notificationsettings_UserDefinedRoomNotificationSettingsView_null_UserDefinedRoomNotificationSettingsView-Day-7_7_null_0,NEXUS_5,1.0,en]","ui_S_t[f.roomdetails.impl.notificationsettings_UserDefinedRoomNotificationSettingsView_null_UserDefinedRoomNotificationSettingsView-Night-7_8_null_0,NEXUS_5,1.0,en]",19849,],
-["ui_S_t[f.createroom.impl.components_UserListView_null_UserListView-Day-2_3_null_0,NEXUS_5,1.0,en]","ui_S_t[f.createroom.impl.components_UserListView_null_UserListView-Night-2_4_null_0,NEXUS_5,1.0,en]",19846,],
-["ui_S_t[f.createroom.impl.components_UserListView_null_UserListView-Day-2_3_null_1,NEXUS_5,1.0,en]","ui_S_t[f.createroom.impl.components_UserListView_null_UserListView-Night-2_4_null_1,NEXUS_5,1.0,en]",19846,],
-["ui_S_t[f.createroom.impl.components_UserListView_null_UserListView-Day-2_3_null_2,NEXUS_5,1.0,en]","ui_S_t[f.createroom.impl.components_UserListView_null_UserListView-Night-2_4_null_2,NEXUS_5,1.0,en]",19846,],
+["ui_S_t[f.roomdetails.impl.notificationsettings_UserDefinedRoomNotificationSettingsView_null_UserDefinedRoomNotificationSettingsView-Day-10_10_null_0,NEXUS_5,1.0,en]","ui_S_t[f.roomdetails.impl.notificationsettings_UserDefinedRoomNotificationSettingsView_null_UserDefinedRoomNotificationSettingsView-Night-10_11_null_0,NEXUS_5,1.0,en]",19860,],
+["ui_S_t[f.createroom.impl.components_UserListView_null_UserListView-Day-2_3_null_0,NEXUS_5,1.0,en]","ui_S_t[f.createroom.impl.components_UserListView_null_UserListView-Night-2_4_null_0,NEXUS_5,1.0,en]",19860,],
+["ui_S_t[f.createroom.impl.components_UserListView_null_UserListView-Day-2_3_null_1,NEXUS_5,1.0,en]","ui_S_t[f.createroom.impl.components_UserListView_null_UserListView-Night-2_4_null_1,NEXUS_5,1.0,en]",19860,],
+["ui_S_t[f.createroom.impl.components_UserListView_null_UserListView-Day-2_3_null_2,NEXUS_5,1.0,en]","ui_S_t[f.createroom.impl.components_UserListView_null_UserListView-Night-2_4_null_2,NEXUS_5,1.0,en]",19860,],
["ui_S_t[f.createroom.impl.components_UserListView_null_UserListView-Day-2_3_null_3,NEXUS_5,1.0,en]","ui_S_t[f.createroom.impl.components_UserListView_null_UserListView-Night-2_4_null_3,NEXUS_5,1.0,en]",0,],
["ui_S_t[f.createroom.impl.components_UserListView_null_UserListView-Day-2_3_null_4,NEXUS_5,1.0,en]","ui_S_t[f.createroom.impl.components_UserListView_null_UserListView-Night-2_4_null_4,NEXUS_5,1.0,en]",0,],
["ui_S_t[f.createroom.impl.components_UserListView_null_UserListView-Day-2_3_null_5,NEXUS_5,1.0,en]","ui_S_t[f.createroom.impl.components_UserListView_null_UserListView-Night-2_4_null_5,NEXUS_5,1.0,en]",0,],
["ui_S_t[f.createroom.impl.components_UserListView_null_UserListView-Day-2_3_null_6,NEXUS_5,1.0,en]","ui_S_t[f.createroom.impl.components_UserListView_null_UserListView-Night-2_4_null_6,NEXUS_5,1.0,en]",0,],
-["ui_S_t[f.createroom.impl.components_UserListView_null_UserListView-Day-2_3_null_7,NEXUS_5,1.0,en]","ui_S_t[f.createroom.impl.components_UserListView_null_UserListView-Night-2_4_null_7,NEXUS_5,1.0,en]",19846,],
+["ui_S_t[f.createroom.impl.components_UserListView_null_UserListView-Day-2_3_null_7,NEXUS_5,1.0,en]","ui_S_t[f.createroom.impl.components_UserListView_null_UserListView-Night-2_4_null_7,NEXUS_5,1.0,en]",19860,],
["ui_S_t[f.createroom.impl.components_UserListView_null_UserListView-Day-2_3_null_8,NEXUS_5,1.0,en]","ui_S_t[f.createroom.impl.components_UserListView_null_UserListView-Night-2_4_null_8,NEXUS_5,1.0,en]",0,],
-["ui_S_t[f.createroom.impl.components_UserListView_null_UserListView-Day-2_3_null_9,NEXUS_5,1.0,en]","ui_S_t[f.createroom.impl.components_UserListView_null_UserListView-Night-2_4_null_9,NEXUS_5,1.0,en]",19846,],
+["ui_S_t[f.createroom.impl.components_UserListView_null_UserListView-Day-2_3_null_9,NEXUS_5,1.0,en]","ui_S_t[f.createroom.impl.components_UserListView_null_UserListView-Night-2_4_null_9,NEXUS_5,1.0,en]",19860,],
["ui_S_t[f.preferences.impl.user_UserPreferences_null_UserPreferences-Day-9_10_null_0,NEXUS_5,1.0,en]","ui_S_t[f.preferences.impl.user_UserPreferences_null_UserPreferences-Night-9_11_null_0,NEXUS_5,1.0,en]",0,],
["ui_S_t[f.preferences.impl.user_UserPreferences_null_UserPreferences-Day-9_10_null_1,NEXUS_5,1.0,en]","ui_S_t[f.preferences.impl.user_UserPreferences_null_UserPreferences-Night-9_11_null_1,NEXUS_5,1.0,en]",0,],
["ui_S_t[f.preferences.impl.user_UserPreferences_null_UserPreferences-Day-9_10_null_2,NEXUS_5,1.0,en]","ui_S_t[f.preferences.impl.user_UserPreferences_null_UserPreferences-Night-9_11_null_2,NEXUS_5,1.0,en]",0,],
-["ui_S_t[f.userprofile.shared_UserProfileView_null_UserProfileView-Day-0_1_null_0,NEXUS_5,1.0,en]","ui_S_t[f.userprofile.shared_UserProfileView_null_UserProfileView-Night-0_2_null_0,NEXUS_5,1.0,en]",19849,],
-["ui_S_t[f.userprofile.shared_UserProfileView_null_UserProfileView-Day-0_1_null_1,NEXUS_5,1.0,en]","ui_S_t[f.userprofile.shared_UserProfileView_null_UserProfileView-Night-0_2_null_1,NEXUS_5,1.0,en]",19849,],
-["ui_S_t[f.userprofile.shared_UserProfileView_null_UserProfileView-Day-0_1_null_2,NEXUS_5,1.0,en]","ui_S_t[f.userprofile.shared_UserProfileView_null_UserProfileView-Night-0_2_null_2,NEXUS_5,1.0,en]",19849,],
-["ui_S_t[f.userprofile.shared_UserProfileView_null_UserProfileView-Day-0_1_null_3,NEXUS_5,1.0,en]","ui_S_t[f.userprofile.shared_UserProfileView_null_UserProfileView-Night-0_2_null_3,NEXUS_5,1.0,en]",19849,],
-["ui_S_t[f.userprofile.shared_UserProfileView_null_UserProfileView-Day-0_1_null_4,NEXUS_5,1.0,en]","ui_S_t[f.userprofile.shared_UserProfileView_null_UserProfileView-Night-0_2_null_4,NEXUS_5,1.0,en]",19849,],
-["ui_S_t[f.userprofile.shared_UserProfileView_null_UserProfileView-Day-0_1_null_5,NEXUS_5,1.0,en]","ui_S_t[f.userprofile.shared_UserProfileView_null_UserProfileView-Night-0_2_null_5,NEXUS_5,1.0,en]",19849,],
-["ui_S_t[f.userprofile.shared_UserProfileView_null_UserProfileView-Day-0_1_null_6,NEXUS_5,1.0,en]","ui_S_t[f.userprofile.shared_UserProfileView_null_UserProfileView-Night-0_2_null_6,NEXUS_5,1.0,en]",19849,],
-["ui_S_t[f.verifysession.impl_VerifySelfSessionView_null_VerifySelfSessionView-Day-0_1_null_0,NEXUS_5,1.0,en]","ui_S_t[f.verifysession.impl_VerifySelfSessionView_null_VerifySelfSessionView-Night-0_2_null_0,NEXUS_5,1.0,en]",19846,],
-["ui_S_t[f.verifysession.impl_VerifySelfSessionView_null_VerifySelfSessionView-Day-0_1_null_1,NEXUS_5,1.0,en]","ui_S_t[f.verifysession.impl_VerifySelfSessionView_null_VerifySelfSessionView-Night-0_2_null_1,NEXUS_5,1.0,en]",19846,],
-["ui_S_t[f.verifysession.impl_VerifySelfSessionView_null_VerifySelfSessionView-Day-0_1_null_2,NEXUS_5,1.0,en]","ui_S_t[f.verifysession.impl_VerifySelfSessionView_null_VerifySelfSessionView-Night-0_2_null_2,NEXUS_5,1.0,en]",19846,],
-["ui_S_t[f.verifysession.impl_VerifySelfSessionView_null_VerifySelfSessionView-Day-0_1_null_3,NEXUS_5,1.0,en]","ui_S_t[f.verifysession.impl_VerifySelfSessionView_null_VerifySelfSessionView-Night-0_2_null_3,NEXUS_5,1.0,en]",19846,],
-["ui_S_t[f.verifysession.impl_VerifySelfSessionView_null_VerifySelfSessionView-Day-0_1_null_4,NEXUS_5,1.0,en]","ui_S_t[f.verifysession.impl_VerifySelfSessionView_null_VerifySelfSessionView-Night-0_2_null_4,NEXUS_5,1.0,en]",19846,],
-["ui_S_t[f.verifysession.impl_VerifySelfSessionView_null_VerifySelfSessionView-Day-0_1_null_5,NEXUS_5,1.0,en]","ui_S_t[f.verifysession.impl_VerifySelfSessionView_null_VerifySelfSessionView-Night-0_2_null_5,NEXUS_5,1.0,en]",19846,],
-["ui_S_t[f.verifysession.impl_VerifySelfSessionView_null_VerifySelfSessionView-Day-0_1_null_6,NEXUS_5,1.0,en]","ui_S_t[f.verifysession.impl_VerifySelfSessionView_null_VerifySelfSessionView-Night-0_2_null_6,NEXUS_5,1.0,en]",19846,],
-["ui_S_t[f.verifysession.impl_VerifySelfSessionView_null_VerifySelfSessionView-Day-0_1_null_7,NEXUS_5,1.0,en]","ui_S_t[f.verifysession.impl_VerifySelfSessionView_null_VerifySelfSessionView-Night-0_2_null_7,NEXUS_5,1.0,en]",19846,],
-["ui_S_t[f.verifysession.impl_VerifySelfSessionView_null_VerifySelfSessionView-Day-0_1_null_8,NEXUS_5,1.0,en]","ui_S_t[f.verifysession.impl_VerifySelfSessionView_null_VerifySelfSessionView-Night-0_2_null_8,NEXUS_5,1.0,en]",19846,],
-["ui_S_t[f.verifysession.impl_VerifySelfSessionView_null_VerifySelfSessionView-Day-0_1_null_9,NEXUS_5,1.0,en]","ui_S_t[f.verifysession.impl_VerifySelfSessionView_null_VerifySelfSessionView-Night-0_2_null_9,NEXUS_5,1.0,en]",19846,],
+["ui_S_t[f.userprofile.shared_UserProfileView_null_UserProfileView-Day-0_1_null_0,NEXUS_5,1.0,en]","ui_S_t[f.userprofile.shared_UserProfileView_null_UserProfileView-Night-0_2_null_0,NEXUS_5,1.0,en]",19860,],
+["ui_S_t[f.userprofile.shared_UserProfileView_null_UserProfileView-Day-0_1_null_1,NEXUS_5,1.0,en]","ui_S_t[f.userprofile.shared_UserProfileView_null_UserProfileView-Night-0_2_null_1,NEXUS_5,1.0,en]",19860,],
+["ui_S_t[f.userprofile.shared_UserProfileView_null_UserProfileView-Day-0_1_null_2,NEXUS_5,1.0,en]","ui_S_t[f.userprofile.shared_UserProfileView_null_UserProfileView-Night-0_2_null_2,NEXUS_5,1.0,en]",19860,],
+["ui_S_t[f.userprofile.shared_UserProfileView_null_UserProfileView-Day-0_1_null_3,NEXUS_5,1.0,en]","ui_S_t[f.userprofile.shared_UserProfileView_null_UserProfileView-Night-0_2_null_3,NEXUS_5,1.0,en]",19860,],
+["ui_S_t[f.userprofile.shared_UserProfileView_null_UserProfileView-Day-0_1_null_4,NEXUS_5,1.0,en]","ui_S_t[f.userprofile.shared_UserProfileView_null_UserProfileView-Night-0_2_null_4,NEXUS_5,1.0,en]",19860,],
+["ui_S_t[f.userprofile.shared_UserProfileView_null_UserProfileView-Day-0_1_null_5,NEXUS_5,1.0,en]","ui_S_t[f.userprofile.shared_UserProfileView_null_UserProfileView-Night-0_2_null_5,NEXUS_5,1.0,en]",19860,],
+["ui_S_t[f.userprofile.shared_UserProfileView_null_UserProfileView-Day-0_1_null_6,NEXUS_5,1.0,en]","ui_S_t[f.userprofile.shared_UserProfileView_null_UserProfileView-Night-0_2_null_6,NEXUS_5,1.0,en]",19860,],
+["ui_S_t[f.userprofile.shared_UserProfileView_null_UserProfileView-Day-0_1_null_7,NEXUS_5,1.0,en]","ui_S_t[f.userprofile.shared_UserProfileView_null_UserProfileView-Night-0_2_null_7,NEXUS_5,1.0,en]",19860,],
+["ui_S_t[f.userprofile.shared_UserProfileView_null_UserProfileView-Day-0_1_null_8,NEXUS_5,1.0,en]","ui_S_t[f.userprofile.shared_UserProfileView_null_UserProfileView-Night-0_2_null_8,NEXUS_5,1.0,en]",19860,],
+["ui_S_t[f.verifysession.impl_VerifySelfSessionView_null_VerifySelfSessionView-Day-0_1_null_0,NEXUS_5,1.0,en]","ui_S_t[f.verifysession.impl_VerifySelfSessionView_null_VerifySelfSessionView-Night-0_2_null_0,NEXUS_5,1.0,en]",19860,],
+["ui_S_t[f.verifysession.impl_VerifySelfSessionView_null_VerifySelfSessionView-Day-0_1_null_1,NEXUS_5,1.0,en]","ui_S_t[f.verifysession.impl_VerifySelfSessionView_null_VerifySelfSessionView-Night-0_2_null_1,NEXUS_5,1.0,en]",19860,],
+["ui_S_t[f.verifysession.impl_VerifySelfSessionView_null_VerifySelfSessionView-Day-0_1_null_2,NEXUS_5,1.0,en]","ui_S_t[f.verifysession.impl_VerifySelfSessionView_null_VerifySelfSessionView-Night-0_2_null_2,NEXUS_5,1.0,en]",19860,],
+["ui_S_t[f.verifysession.impl_VerifySelfSessionView_null_VerifySelfSessionView-Day-0_1_null_3,NEXUS_5,1.0,en]","ui_S_t[f.verifysession.impl_VerifySelfSessionView_null_VerifySelfSessionView-Night-0_2_null_3,NEXUS_5,1.0,en]",19860,],
+["ui_S_t[f.verifysession.impl_VerifySelfSessionView_null_VerifySelfSessionView-Day-0_1_null_4,NEXUS_5,1.0,en]","ui_S_t[f.verifysession.impl_VerifySelfSessionView_null_VerifySelfSessionView-Night-0_2_null_4,NEXUS_5,1.0,en]",19860,],
+["ui_S_t[f.verifysession.impl_VerifySelfSessionView_null_VerifySelfSessionView-Day-0_1_null_5,NEXUS_5,1.0,en]","ui_S_t[f.verifysession.impl_VerifySelfSessionView_null_VerifySelfSessionView-Night-0_2_null_5,NEXUS_5,1.0,en]",19860,],
+["ui_S_t[f.verifysession.impl_VerifySelfSessionView_null_VerifySelfSessionView-Day-0_1_null_6,NEXUS_5,1.0,en]","ui_S_t[f.verifysession.impl_VerifySelfSessionView_null_VerifySelfSessionView-Night-0_2_null_6,NEXUS_5,1.0,en]",19860,],
+["ui_S_t[f.verifysession.impl_VerifySelfSessionView_null_VerifySelfSessionView-Day-0_1_null_7,NEXUS_5,1.0,en]","ui_S_t[f.verifysession.impl_VerifySelfSessionView_null_VerifySelfSessionView-Night-0_2_null_7,NEXUS_5,1.0,en]",19860,],
+["ui_S_t[f.verifysession.impl_VerifySelfSessionView_null_VerifySelfSessionView-Day-0_1_null_8,NEXUS_5,1.0,en]","ui_S_t[f.verifysession.impl_VerifySelfSessionView_null_VerifySelfSessionView-Night-0_2_null_8,NEXUS_5,1.0,en]",19860,],
+["ui_S_t[f.verifysession.impl_VerifySelfSessionView_null_VerifySelfSessionView-Day-0_1_null_9,NEXUS_5,1.0,en]","ui_S_t[f.verifysession.impl_VerifySelfSessionView_null_VerifySelfSessionView-Night-0_2_null_9,NEXUS_5,1.0,en]",19860,],
["ui_S_t[l.designsystem.ruler_VerticalRuler_null_VerticalRuler-Day_0_null,NEXUS_5,1.0,en]","ui_S_t[l.designsystem.ruler_VerticalRuler_null_VerticalRuler-Night_1_null,NEXUS_5,1.0,en]",0,],
["ui_S_t[f.viewfolder.impl.file_ViewFileView_null_ViewFileView-Day-0_1_null_0,NEXUS_5,1.0,en]","ui_S_t[f.viewfolder.impl.file_ViewFileView_null_ViewFileView-Night-0_2_null_0,NEXUS_5,1.0,en]",0,],
["ui_S_t[f.viewfolder.impl.file_ViewFileView_null_ViewFileView-Day-0_1_null_1,NEXUS_5,1.0,en]","ui_S_t[f.viewfolder.impl.file_ViewFileView_null_ViewFileView-Night-0_2_null_1,NEXUS_5,1.0,en]",0,],
@@ -1036,12 +1046,12 @@ export const screenshots = [
["ui_S_t[l.textcomposer.components_VoiceMessagePreview_null_VoiceMessagePreview-Day-15_16_null,NEXUS_5,1.0,en]","ui_S_t[l.textcomposer.components_VoiceMessagePreview_null_VoiceMessagePreview-Night-15_17_null,NEXUS_5,1.0,en]",0,],
["ui_S_t[l.textcomposer.components_VoiceMessageRecorderButton_null_VoiceMessageRecorderButton-Day-16_17_null,NEXUS_5,1.0,en]","ui_S_t[l.textcomposer.components_VoiceMessageRecorderButton_null_VoiceMessageRecorderButton-Night-16_18_null,NEXUS_5,1.0,en]",0,],
["ui_S_t[l.textcomposer.components_VoiceMessageRecording_null_VoiceMessageRecording-Day-17_18_null,NEXUS_5,1.0,en]","ui_S_t[l.textcomposer.components_VoiceMessageRecording_null_VoiceMessageRecording-Night-17_19_null,NEXUS_5,1.0,en]",0,],
-["ui_S_t[f.login.impl.screens.waitlistscreen_WaitListView_null_WaitListView-Day-8_9_null_0,NEXUS_5,1.0,en]","ui_S_t[f.login.impl.screens.waitlistscreen_WaitListView_null_WaitListView-Night-8_10_null_0,NEXUS_5,1.0,en]",19846,],
-["ui_S_t[f.login.impl.screens.waitlistscreen_WaitListView_null_WaitListView-Day-8_9_null_1,NEXUS_5,1.0,en]","ui_S_t[f.login.impl.screens.waitlistscreen_WaitListView_null_WaitListView-Night-8_10_null_1,NEXUS_5,1.0,en]",19846,],
-["ui_S_t[f.login.impl.screens.waitlistscreen_WaitListView_null_WaitListView-Day-8_9_null_2,NEXUS_5,1.0,en]","ui_S_t[f.login.impl.screens.waitlistscreen_WaitListView_null_WaitListView-Night-8_10_null_2,NEXUS_5,1.0,en]",19846,],
-["ui_S_t[f.login.impl.screens.waitlistscreen_WaitListView_null_WaitListView-Day-8_9_null_3,NEXUS_5,1.0,en]","ui_S_t[f.login.impl.screens.waitlistscreen_WaitListView_null_WaitListView-Night-8_10_null_3,NEXUS_5,1.0,en]",19846,],
-["ui_S_t[f.login.impl.screens.waitlistscreen_WaitListView_null_WaitListView-Day-8_9_null_4,NEXUS_5,1.0,en]","ui_S_t[f.login.impl.screens.waitlistscreen_WaitListView_null_WaitListView-Night-8_10_null_4,NEXUS_5,1.0,en]",19846,],
+["ui_S_t[f.login.impl.screens.waitlistscreen_WaitListView_null_WaitListView-Day-8_9_null_0,NEXUS_5,1.0,en]","ui_S_t[f.login.impl.screens.waitlistscreen_WaitListView_null_WaitListView-Night-8_10_null_0,NEXUS_5,1.0,en]",19860,],
+["ui_S_t[f.login.impl.screens.waitlistscreen_WaitListView_null_WaitListView-Day-8_9_null_1,NEXUS_5,1.0,en]","ui_S_t[f.login.impl.screens.waitlistscreen_WaitListView_null_WaitListView-Night-8_10_null_1,NEXUS_5,1.0,en]",19860,],
+["ui_S_t[f.login.impl.screens.waitlistscreen_WaitListView_null_WaitListView-Day-8_9_null_2,NEXUS_5,1.0,en]","ui_S_t[f.login.impl.screens.waitlistscreen_WaitListView_null_WaitListView-Night-8_10_null_2,NEXUS_5,1.0,en]",19860,],
+["ui_S_t[f.login.impl.screens.waitlistscreen_WaitListView_null_WaitListView-Day-8_9_null_3,NEXUS_5,1.0,en]","ui_S_t[f.login.impl.screens.waitlistscreen_WaitListView_null_WaitListView-Night-8_10_null_3,NEXUS_5,1.0,en]",19860,],
+["ui_S_t[f.login.impl.screens.waitlistscreen_WaitListView_null_WaitListView-Day-8_9_null_4,NEXUS_5,1.0,en]","ui_S_t[f.login.impl.screens.waitlistscreen_WaitListView_null_WaitListView-Night-8_10_null_4,NEXUS_5,1.0,en]",19860,],
["ui_S_t[l.designsystem.components.media_WaveformPlaybackView_null_WaveformPlaybackView-Day_0_null,NEXUS_5,1.0,en]","ui_S_t[l.designsystem.components.media_WaveformPlaybackView_null_WaveformPlaybackView-Night_1_null,NEXUS_5,1.0,en]",0,],
-["ui_S_t[f.ftue.impl.welcome_WelcomeView_null_WelcomeView-Day-1_2_null,NEXUS_5,1.0,en]","ui_S_t[f.ftue.impl.welcome_WelcomeView_null_WelcomeView-Night-1_3_null,NEXUS_5,1.0,en]",19846,],
+["ui_S_t[f.ftue.impl.welcome_WelcomeView_null_WelcomeView-Day-1_2_null,NEXUS_5,1.0,en]","ui_S_t[f.ftue.impl.welcome_WelcomeView_null_WelcomeView-Night-1_3_null,NEXUS_5,1.0,en]",19860,],
["ui_S_t[l.designsystem.ruler_WithRulers_null_WithRulers-Day_0_null,NEXUS_5,1.0,en]","ui_S_t[l.designsystem.ruler_WithRulers_null_WithRulers-Night_1_null,NEXUS_5,1.0,en]",0,],
];
diff --git a/services/analytics/api/build.gradle.kts b/services/analytics/api/build.gradle.kts
index c78a050571..76309c0179 100644
--- a/services/analytics/api/build.gradle.kts
+++ b/services/analytics/api/build.gradle.kts
@@ -25,6 +25,5 @@ dependencies {
api(projects.services.analyticsproviders.api)
api(projects.services.toolbox.api)
implementation(libs.coroutines.core)
- implementation(projects.libraries.matrix.api)
implementation(projects.libraries.core)
}
diff --git a/settings.gradle.kts b/settings.gradle.kts
index cd3689abe3..dd48d5d4af 100644
--- a/settings.gradle.kts
+++ b/settings.gradle.kts
@@ -27,6 +27,15 @@ pluginManagement {
dependencyResolutionManagement {
repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
repositories {
+ // Snapshot versions
+ maven {
+ url = URI("https://s01.oss.sonatype.org/content/repositories/snapshots")
+ content {
+ includeModule("org.matrix.rustcomponents", "sdk-android")
+ includeModule("io.element.android", "wysiwyg")
+ includeModule("io.element.android", "wysiwyg-compose")
+ }
+ }
google()
mavenCentral()
maven { url = URI("https://oss.sonatype.org/content/repositories/snapshots/") }
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 75b0df9837..52ae3660c6 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
@@ -78,6 +78,7 @@ class KonsistPreviewTest {
"IconTitleSubtitleMoleculeWithResIconPreview",
"IconsCompoundPreview",
"IconsOtherPreview",
+ "MarkdownTextComposerEditPreview",
"MentionSpanPreview",
"MessageComposerViewVoicePreview",
"MessagesReactionButtonAddPreview",
diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.createroom.impl.configureroom_ConfigureRoomView_null_ConfigureRoomView-Day-3_4_null_0,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.createroom.impl.configureroom_ConfigureRoomView_null_ConfigureRoomView-Day-3_4_null_0,NEXUS_5,1.0,en].png
index 385da4e443..8a6faf46d5 100644
--- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.createroom.impl.configureroom_ConfigureRoomView_null_ConfigureRoomView-Day-3_4_null_0,NEXUS_5,1.0,en].png
+++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.createroom.impl.configureroom_ConfigureRoomView_null_ConfigureRoomView-Day-3_4_null_0,NEXUS_5,1.0,en].png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:0aebfeacf46df5674e4b159fd9dca029288596a2835ff953783d144cbb44c91f
-size 61153
+oid sha256:ba10d755e7cefd5946a7519216a6298a1a17cbe80423bff3939e8699cc5531a6
+size 60967
diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.createroom.impl.configureroom_ConfigureRoomView_null_ConfigureRoomView-Day-3_4_null_1,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.createroom.impl.configureroom_ConfigureRoomView_null_ConfigureRoomView-Day-3_4_null_1,NEXUS_5,1.0,en].png
index 4184a2f57f..d4437de3af 100644
--- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.createroom.impl.configureroom_ConfigureRoomView_null_ConfigureRoomView-Day-3_4_null_1,NEXUS_5,1.0,en].png
+++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.createroom.impl.configureroom_ConfigureRoomView_null_ConfigureRoomView-Day-3_4_null_1,NEXUS_5,1.0,en].png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:2fe73b4f444fd4d42d99de9705ca5a73ee95cc954ab39ec874208277dac9b131
-size 84224
+oid sha256:5d2e65da53dd78db7204ffaebc8823e23f6517cdf67fcec044627a6d740361cb
+size 86948
diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.createroom.impl.configureroom_ConfigureRoomView_null_ConfigureRoomView-Night-3_5_null_0,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.createroom.impl.configureroom_ConfigureRoomView_null_ConfigureRoomView-Night-3_5_null_0,NEXUS_5,1.0,en].png
index b255d112e0..dc45b621a7 100644
--- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.createroom.impl.configureroom_ConfigureRoomView_null_ConfigureRoomView-Night-3_5_null_0,NEXUS_5,1.0,en].png
+++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.createroom.impl.configureroom_ConfigureRoomView_null_ConfigureRoomView-Night-3_5_null_0,NEXUS_5,1.0,en].png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:d8400f3b6385a3eb0096282b2e8a64d7d593ac51deb2c1a32d55acbbce430244
-size 57700
+oid sha256:3609875b66402a3cd7db798005aafb87479b07056f6e8f737cede80950a33665
+size 57693
diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.createroom.impl.configureroom_ConfigureRoomView_null_ConfigureRoomView-Night-3_5_null_1,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.createroom.impl.configureroom_ConfigureRoomView_null_ConfigureRoomView-Night-3_5_null_1,NEXUS_5,1.0,en].png
index 79cf2648fa..31fcef3505 100644
--- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.createroom.impl.configureroom_ConfigureRoomView_null_ConfigureRoomView-Night-3_5_null_1,NEXUS_5,1.0,en].png
+++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.createroom.impl.configureroom_ConfigureRoomView_null_ConfigureRoomView-Night-3_5_null_1,NEXUS_5,1.0,en].png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:495521b5b0d4cb90ebd5be62975673965bd103c5bba12c43c3c6b2d6003acbfb
-size 81045
+oid sha256:5fc8ac21d7e0e9d15b59f4bc9237dbafd974aba8bd26bd67192b04c1e3c5116c
+size 83702
diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.messagecomposer_AttachmentSourcePickerMenu_null_AttachmentSourcePickerMenu-Day-4_4_null,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.messagecomposer_AttachmentSourcePickerMenu_null_AttachmentSourcePickerMenu-Day-4_4_null,NEXUS_5,1.0,en].png
index 0920708a90..5ff865b907 100644
--- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.messagecomposer_AttachmentSourcePickerMenu_null_AttachmentSourcePickerMenu-Day-4_4_null,NEXUS_5,1.0,en].png
+++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.messagecomposer_AttachmentSourcePickerMenu_null_AttachmentSourcePickerMenu-Day-4_4_null,NEXUS_5,1.0,en].png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:71231170c8d6cff3137aaa59df68f5d4b186cd501a8195ebff18b78635a36c66
+oid sha256:a8775112e8078f699bf9366d8ef3238421527601cb5eb8c8ba946b4c3a22fefb
size 26182
diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.messagecomposer_AttachmentSourcePickerMenu_null_AttachmentSourcePickerMenu-Night-4_5_null,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.messagecomposer_AttachmentSourcePickerMenu_null_AttachmentSourcePickerMenu-Night-4_5_null,NEXUS_5,1.0,en].png
index 1a98922aea..0fa2501a12 100644
--- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.messagecomposer_AttachmentSourcePickerMenu_null_AttachmentSourcePickerMenu-Night-4_5_null,NEXUS_5,1.0,en].png
+++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.messagecomposer_AttachmentSourcePickerMenu_null_AttachmentSourcePickerMenu-Night-4_5_null,NEXUS_5,1.0,en].png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:44a3bf1e15ca379d471e7a1e531564d585298d8ba1edf82aa064b8512ccf5f22
+oid sha256:3934bee2240469aa5dd91cc7654ca012e0aa424a266ad47e09f24ed78d82ec62
size 23845
diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl_MessagesView_null_MessagesView-Day-0_0_null_2,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl_MessagesView_null_MessagesView-Day-0_0_null_2,NEXUS_5,1.0,en].png
index e8e53e2110..b167bf0fd5 100644
--- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl_MessagesView_null_MessagesView-Day-0_0_null_2,NEXUS_5,1.0,en].png
+++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl_MessagesView_null_MessagesView-Day-0_0_null_2,NEXUS_5,1.0,en].png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:5f6f3350f9e409d8a6e87116b5500f519cad1f1d731f03b3674412207c6f4b1e
+oid sha256:8ef8c712e3327374c8f186501c7dfd790b57e061b7a6540b7a53baec0e8ff563
size 28044
diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl_MessagesView_null_MessagesView-Night-0_1_null_2,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl_MessagesView_null_MessagesView-Night-0_1_null_2,NEXUS_5,1.0,en].png
index 35a7ef73bc..0f841402e9 100644
--- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl_MessagesView_null_MessagesView-Night-0_1_null_2,NEXUS_5,1.0,en].png
+++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl_MessagesView_null_MessagesView-Night-0_1_null_2,NEXUS_5,1.0,en].png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:e56586426695abaf31a2e5fd3f4367177e69378daa5ed4f8a19ec93f768a60ff
+oid sha256:3d912533966c2eca1e1b881247fb9ede01c3f47d79ea238ab4da3ee34e574721
size 24781
diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.advanced_AdvancedSettingsView_null_AdvancedSettingsView-Day-1_2_null_0,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.advanced_AdvancedSettingsView_null_AdvancedSettingsView-Day-1_2_null_0,NEXUS_5,1.0,en].png
index 0022fb4f2d..8f3d422775 100644
--- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.advanced_AdvancedSettingsView_null_AdvancedSettingsView-Day-1_2_null_0,NEXUS_5,1.0,en].png
+++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.advanced_AdvancedSettingsView_null_AdvancedSettingsView-Day-1_2_null_0,NEXUS_5,1.0,en].png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:4931140dafa7377d1583d4af9603337fbb3a0045ddbb348bf23a220bd77083d1
-size 56388
+oid sha256:fde2f5bfe13c4c775cbbea215a6a4d8fe9e474f5939e41b2ae9c23238871dedb
+size 50191
diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.advanced_AdvancedSettingsView_null_AdvancedSettingsView-Day-1_2_null_1,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.advanced_AdvancedSettingsView_null_AdvancedSettingsView-Day-1_2_null_1,NEXUS_5,1.0,en].png
index 9555fa431c..2ee9b8e3d7 100644
--- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.advanced_AdvancedSettingsView_null_AdvancedSettingsView-Day-1_2_null_1,NEXUS_5,1.0,en].png
+++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.advanced_AdvancedSettingsView_null_AdvancedSettingsView-Day-1_2_null_1,NEXUS_5,1.0,en].png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:13cffd3bf3d2eb4d266b81dd05d40e05cfd4663851ea06e9c6c24374e457fb1d
-size 55859
+oid sha256:1f20dda0c0ce1757da7014083cfa0c602eed2bd1019ddbd0566668338b6697a1
+size 49764
diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.advanced_AdvancedSettingsView_null_AdvancedSettingsView-Day-1_2_null_2,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.advanced_AdvancedSettingsView_null_AdvancedSettingsView-Day-1_2_null_2,NEXUS_5,1.0,en].png
index a693a5f7c3..f46a490647 100644
--- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.advanced_AdvancedSettingsView_null_AdvancedSettingsView-Day-1_2_null_2,NEXUS_5,1.0,en].png
+++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.advanced_AdvancedSettingsView_null_AdvancedSettingsView-Day-1_2_null_2,NEXUS_5,1.0,en].png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:00cdf4f635352c11d572faae361c066986a6812f80124fe23ab142f8c87c077f
-size 55888
+oid sha256:b6fd202a1f27239b3a6d4f587538905d01bd0fcfa745262535c050e37600e71f
+size 36066
diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.advanced_AdvancedSettingsView_null_AdvancedSettingsView-Day-1_2_null_3,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.advanced_AdvancedSettingsView_null_AdvancedSettingsView-Day-1_2_null_3,NEXUS_5,1.0,en].png
index bea917b247..17ee7ac710 100644
--- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.advanced_AdvancedSettingsView_null_AdvancedSettingsView-Day-1_2_null_3,NEXUS_5,1.0,en].png
+++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.advanced_AdvancedSettingsView_null_AdvancedSettingsView-Day-1_2_null_3,NEXUS_5,1.0,en].png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:c4a9814198e0a6be655ec1bfb8038071e29a8ee4959b5209936e6b63d92c4e07
-size 36289
+oid sha256:6fcca4452f2523e8ec8601efc5a2c08b85e1b198992020fce3d75799d046d68a
+size 49778
diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.advanced_AdvancedSettingsView_null_AdvancedSettingsView-Day-1_2_null_4,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.advanced_AdvancedSettingsView_null_AdvancedSettingsView-Day-1_2_null_4,NEXUS_5,1.0,en].png
index 086b021e64..35c515822e 100644
--- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.advanced_AdvancedSettingsView_null_AdvancedSettingsView-Day-1_2_null_4,NEXUS_5,1.0,en].png
+++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.advanced_AdvancedSettingsView_null_AdvancedSettingsView-Day-1_2_null_4,NEXUS_5,1.0,en].png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:89f646eede8992256de5df9181eccc28f0ebc3fd2d07d58e102b6cabfbf4e5e2
-size 55834
+oid sha256:22b20d44483d246fb0b10a96d2e243195b2c2c45df4721337c77be0f4261d596
+size 42891
diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.advanced_AdvancedSettingsView_null_AdvancedSettingsView-Day-1_2_null_5,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.advanced_AdvancedSettingsView_null_AdvancedSettingsView-Day-1_2_null_5,NEXUS_5,1.0,en].png
new file mode 100644
index 0000000000..35751355e7
--- /dev/null
+++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.advanced_AdvancedSettingsView_null_AdvancedSettingsView-Day-1_2_null_5,NEXUS_5,1.0,en].png
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:462452d822da2efa59ba1e6451d9ff8fecd9b1dc3a7c96bbae2c61be845b140f
+size 49428
diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.advanced_AdvancedSettingsView_null_AdvancedSettingsView-Day-1_2_null_6,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.advanced_AdvancedSettingsView_null_AdvancedSettingsView-Day-1_2_null_6,NEXUS_5,1.0,en].png
new file mode 100644
index 0000000000..1cd6b5237d
--- /dev/null
+++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.advanced_AdvancedSettingsView_null_AdvancedSettingsView-Day-1_2_null_6,NEXUS_5,1.0,en].png
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:a414a44619f982494a64348f82149e2d9ac41d8a7c963135f5ec3d5eede0c4eb
+size 49513
diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.advanced_AdvancedSettingsView_null_AdvancedSettingsView-Night-1_3_null_0,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.advanced_AdvancedSettingsView_null_AdvancedSettingsView-Night-1_3_null_0,NEXUS_5,1.0,en].png
index 2417b336b6..6af195ec37 100644
--- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.advanced_AdvancedSettingsView_null_AdvancedSettingsView-Night-1_3_null_0,NEXUS_5,1.0,en].png
+++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.advanced_AdvancedSettingsView_null_AdvancedSettingsView-Night-1_3_null_0,NEXUS_5,1.0,en].png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:e9fd3a8cee62f283571b37670b4f064dd9f6c5195dec92b20c6ee3d53c9defae
-size 53103
+oid sha256:876406e0e009f3d874cf1b9101702c82de792b6f66d4cb0870b03dafef124afa
+size 47270
diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.advanced_AdvancedSettingsView_null_AdvancedSettingsView-Night-1_3_null_1,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.advanced_AdvancedSettingsView_null_AdvancedSettingsView-Night-1_3_null_1,NEXUS_5,1.0,en].png
index 0b1d375333..0683ac11d6 100644
--- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.advanced_AdvancedSettingsView_null_AdvancedSettingsView-Night-1_3_null_1,NEXUS_5,1.0,en].png
+++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.advanced_AdvancedSettingsView_null_AdvancedSettingsView-Night-1_3_null_1,NEXUS_5,1.0,en].png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:6ad13ab2b02480a9d436fb62039139284af250aaaf806434f528307e6704162a
-size 52797
+oid sha256:f3576179a7bd4c23ecc0567c4f38282af12d34d93d988b17dad54a307a69699d
+size 46897
diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.advanced_AdvancedSettingsView_null_AdvancedSettingsView-Night-1_3_null_2,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.advanced_AdvancedSettingsView_null_AdvancedSettingsView-Night-1_3_null_2,NEXUS_5,1.0,en].png
index 3d104af37f..df10f0fa71 100644
--- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.advanced_AdvancedSettingsView_null_AdvancedSettingsView-Night-1_3_null_2,NEXUS_5,1.0,en].png
+++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.advanced_AdvancedSettingsView_null_AdvancedSettingsView-Night-1_3_null_2,NEXUS_5,1.0,en].png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:1584885ecab5a8aa3bbf1f0b116d74d398043d0b12c905d69717bec5b1e80ea7
-size 52819
+oid sha256:4f8372768cb4605bf5e3d889d847eb08bd71e0fee9fa62a60d99f04d583618e4
+size 31772
diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.advanced_AdvancedSettingsView_null_AdvancedSettingsView-Night-1_3_null_3,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.advanced_AdvancedSettingsView_null_AdvancedSettingsView-Night-1_3_null_3,NEXUS_5,1.0,en].png
index a941e8ba83..d1ac2e827c 100644
--- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.advanced_AdvancedSettingsView_null_AdvancedSettingsView-Night-1_3_null_3,NEXUS_5,1.0,en].png
+++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.advanced_AdvancedSettingsView_null_AdvancedSettingsView-Night-1_3_null_3,NEXUS_5,1.0,en].png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:99acb52cafefefbf3a17ce759e85b821d949df9c5d37fce4038b0d99e22993b5
-size 32144
+oid sha256:7dc86ad9c4246582c4468bcb0c0c1c566e76c56a73813d3a1040b4836f5f9ba6
+size 46872
diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.advanced_AdvancedSettingsView_null_AdvancedSettingsView-Night-1_3_null_4,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.advanced_AdvancedSettingsView_null_AdvancedSettingsView-Night-1_3_null_4,NEXUS_5,1.0,en].png
index 3d20590ece..106f604440 100644
--- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.advanced_AdvancedSettingsView_null_AdvancedSettingsView-Night-1_3_null_4,NEXUS_5,1.0,en].png
+++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.advanced_AdvancedSettingsView_null_AdvancedSettingsView-Night-1_3_null_4,NEXUS_5,1.0,en].png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:fc26ca6ad489264a7008c528b762a22b6349aa9c16f6d43ed41628b20aa0659c
-size 52824
+oid sha256:5ef2574271233ac991ea92ef9b5b00fec488ea14c3d75cc8a308bbe4b11e5a63
+size 37557
diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.advanced_AdvancedSettingsView_null_AdvancedSettingsView-Night-1_3_null_5,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.advanced_AdvancedSettingsView_null_AdvancedSettingsView-Night-1_3_null_5,NEXUS_5,1.0,en].png
new file mode 100644
index 0000000000..a0491f0890
--- /dev/null
+++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.advanced_AdvancedSettingsView_null_AdvancedSettingsView-Night-1_3_null_5,NEXUS_5,1.0,en].png
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:76a2946b89cd562a090b43e14f752d61c161a3409e3169ab1e88d78e325048bd
+size 46391
diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.advanced_AdvancedSettingsView_null_AdvancedSettingsView-Night-1_3_null_6,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.advanced_AdvancedSettingsView_null_AdvancedSettingsView-Night-1_3_null_6,NEXUS_5,1.0,en].png
new file mode 100644
index 0000000000..b48924e9a0
--- /dev/null
+++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.advanced_AdvancedSettingsView_null_AdvancedSettingsView-Night-1_3_null_6,NEXUS_5,1.0,en].png
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:edac5e24157eaa960bcf320c3f4fdd79f0a62bf09b47b36193d9936e953d3489
+size 46511
diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.user.editprofile_EditUserProfileView_null_EditUserProfileView-Day-10_11_null_0,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.user.editprofile_EditUserProfileView_null_EditUserProfileView-Day-10_11_null_0,NEXUS_5,1.0,en].png
index fd83a6344d..a04d892e35 100644
--- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.user.editprofile_EditUserProfileView_null_EditUserProfileView-Day-10_11_null_0,NEXUS_5,1.0,en].png
+++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.user.editprofile_EditUserProfileView_null_EditUserProfileView-Day-10_11_null_0,NEXUS_5,1.0,en].png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:984d249036bb82d31cfc7d183b0a33c6419f0827e535a79390055f574e36c89a
-size 22542
+oid sha256:b0ab108a6bc88c7a811e9589596aa41be765005086863a31eea31bf3cd651aad
+size 22351
diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.user.editprofile_EditUserProfileView_null_EditUserProfileView-Night-10_12_null_0,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.user.editprofile_EditUserProfileView_null_EditUserProfileView-Night-10_12_null_0,NEXUS_5,1.0,en].png
index 897e65667c..db020dc21e 100644
--- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.user.editprofile_EditUserProfileView_null_EditUserProfileView-Night-10_12_null_0,NEXUS_5,1.0,en].png
+++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.user.editprofile_EditUserProfileView_null_EditUserProfileView-Night-10_12_null_0,NEXUS_5,1.0,en].png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:4bec5a025508cfff5808b3c007dcb31d780635a208d959f05891538e7dd0bba2
-size 20896
+oid sha256:82b3c70a99cad62e1cfd4cee89fa96e514f1f0b6418dcf857fcd4981e32a3ba6
+size 20885
diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl.edit_RoomDetailsEditView_null_RoomDetailsEditView-Day-3_3_null_0,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl.edit_RoomDetailsEditView_null_RoomDetailsEditView-Day-3_3_null_0,NEXUS_5,1.0,en].png
index 77f392fa53..e518d52bfc 100644
--- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl.edit_RoomDetailsEditView_null_RoomDetailsEditView-Day-3_3_null_0,NEXUS_5,1.0,en].png
+++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl.edit_RoomDetailsEditView_null_RoomDetailsEditView-Day-3_3_null_0,NEXUS_5,1.0,en].png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:f238794e2139509c701d363b90ae42cd0ad127e09665d82339e6d292c04c103e
-size 30221
+oid sha256:f2c5b052dff4115a1b9b829e68fd46edf865994929a1e8ae0b463f168ef03907
+size 30399
diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl.edit_RoomDetailsEditView_null_RoomDetailsEditView-Day-3_3_null_1,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl.edit_RoomDetailsEditView_null_RoomDetailsEditView-Day-3_3_null_1,NEXUS_5,1.0,en].png
index cc9a457882..e4814f4c3f 100644
--- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl.edit_RoomDetailsEditView_null_RoomDetailsEditView-Day-3_3_null_1,NEXUS_5,1.0,en].png
+++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl.edit_RoomDetailsEditView_null_RoomDetailsEditView-Day-3_3_null_1,NEXUS_5,1.0,en].png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:8afcab5de05d583820291a8e4578a1799960cf96137bfdae46542504f6a02a06
-size 23555
+oid sha256:3c5a165e3c5c81755b739623b872bf1b1b99d6ccd8549a1c2324e59e9c421b58
+size 23688
diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl.edit_RoomDetailsEditView_null_RoomDetailsEditView-Day-3_3_null_2,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl.edit_RoomDetailsEditView_null_RoomDetailsEditView-Day-3_3_null_2,NEXUS_5,1.0,en].png
index 955974680d..afbd395bd2 100644
--- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl.edit_RoomDetailsEditView_null_RoomDetailsEditView-Day-3_3_null_2,NEXUS_5,1.0,en].png
+++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl.edit_RoomDetailsEditView_null_RoomDetailsEditView-Day-3_3_null_2,NEXUS_5,1.0,en].png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:6c7a63959ed475c3aca89125149eb66b87702fdad9e7162fda52341bb1069eca
-size 55870
+oid sha256:7eb57ad86edca68df0129f25221758647d1edab14e233e4e10f9ad1c0750e5d1
+size 31743
diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl.edit_RoomDetailsEditView_null_RoomDetailsEditView-Day-3_3_null_3,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl.edit_RoomDetailsEditView_null_RoomDetailsEditView-Day-3_3_null_3,NEXUS_5,1.0,en].png
index 9bb3821d1a..72b778a632 100644
--- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl.edit_RoomDetailsEditView_null_RoomDetailsEditView-Day-3_3_null_3,NEXUS_5,1.0,en].png
+++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl.edit_RoomDetailsEditView_null_RoomDetailsEditView-Day-3_3_null_3,NEXUS_5,1.0,en].png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:e0e895eee0d379ccff79d44f2ae3e954bbe23597f11086cdfb99c3b0981e392a
-size 29939
+oid sha256:3fdd4a80c5a8499d3b79617c1757358de7f40a1fdb43d1c537ce4170af5efb9a
+size 55730
diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl.edit_RoomDetailsEditView_null_RoomDetailsEditView-Day-3_3_null_4,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl.edit_RoomDetailsEditView_null_RoomDetailsEditView-Day-3_3_null_4,NEXUS_5,1.0,en].png
index 4a3de05872..f2fd798a84 100644
--- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl.edit_RoomDetailsEditView_null_RoomDetailsEditView-Day-3_3_null_4,NEXUS_5,1.0,en].png
+++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl.edit_RoomDetailsEditView_null_RoomDetailsEditView-Day-3_3_null_4,NEXUS_5,1.0,en].png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:acb90cc495ca721862557a0f213d80b302853309398550553bdbec0984975769
-size 29940
+oid sha256:8268170c93b3ec77e9222e926a1396f9889922fe4892d6388d2de015aee94c47
+size 30088
diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl.edit_RoomDetailsEditView_null_RoomDetailsEditView-Day-3_3_null_5,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl.edit_RoomDetailsEditView_null_RoomDetailsEditView-Day-3_3_null_5,NEXUS_5,1.0,en].png
index 79363a798a..be874e0648 100644
--- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl.edit_RoomDetailsEditView_null_RoomDetailsEditView-Day-3_3_null_5,NEXUS_5,1.0,en].png
+++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl.edit_RoomDetailsEditView_null_RoomDetailsEditView-Day-3_3_null_5,NEXUS_5,1.0,en].png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:c2beb630f1cafc363da0d1d7f508ad66b7738f0624d9cceefb7db35c12787b36
-size 30153
+oid sha256:2bc28e45b7d804766d5c0ce0cf217bbdb81459ad19415739835c849d8638c634
+size 30121
diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl.edit_RoomDetailsEditView_null_RoomDetailsEditView-Day-3_3_null_6,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl.edit_RoomDetailsEditView_null_RoomDetailsEditView-Day-3_3_null_6,NEXUS_5,1.0,en].png
index f801512b08..0e4dec53a5 100644
--- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl.edit_RoomDetailsEditView_null_RoomDetailsEditView-Day-3_3_null_6,NEXUS_5,1.0,en].png
+++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl.edit_RoomDetailsEditView_null_RoomDetailsEditView-Day-3_3_null_6,NEXUS_5,1.0,en].png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:c8b761beaa0856819a39931fbd57f12a22c30b599d545f59b21b92d0d15ab0eb
-size 27563
+oid sha256:f504a2811ed252564a9c14cf7d9c770d2c7993f4e839c5e4e506e555cb4258fc
+size 30310
diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl.edit_RoomDetailsEditView_null_RoomDetailsEditView-Day-3_3_null_7,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl.edit_RoomDetailsEditView_null_RoomDetailsEditView-Day-3_3_null_7,NEXUS_5,1.0,en].png
new file mode 100644
index 0000000000..deb8ba493e
--- /dev/null
+++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl.edit_RoomDetailsEditView_null_RoomDetailsEditView-Day-3_3_null_7,NEXUS_5,1.0,en].png
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:a01beba7ac836b5fdc66687298ced0a81d260fe1af3b3260b468226b90b8df48
+size 27695
diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl.edit_RoomDetailsEditView_null_RoomDetailsEditView-Night-3_4_null_0,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl.edit_RoomDetailsEditView_null_RoomDetailsEditView-Night-3_4_null_0,NEXUS_5,1.0,en].png
index 10259ac6a0..74a44c734f 100644
--- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl.edit_RoomDetailsEditView_null_RoomDetailsEditView-Night-3_4_null_0,NEXUS_5,1.0,en].png
+++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl.edit_RoomDetailsEditView_null_RoomDetailsEditView-Night-3_4_null_0,NEXUS_5,1.0,en].png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:cea255e3114cc3e854d9f831cd7ea646f3aa9992d3a56e81bb4a5a77a2ecf66b
-size 28877
+oid sha256:f2eb8e41704492332da26e123a48f423a73104532e947246faf73604e7d54a2c
+size 28844
diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl.edit_RoomDetailsEditView_null_RoomDetailsEditView-Night-3_4_null_1,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl.edit_RoomDetailsEditView_null_RoomDetailsEditView-Night-3_4_null_1,NEXUS_5,1.0,en].png
index 2d8674af42..94f6fb0da0 100644
--- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl.edit_RoomDetailsEditView_null_RoomDetailsEditView-Night-3_4_null_1,NEXUS_5,1.0,en].png
+++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl.edit_RoomDetailsEditView_null_RoomDetailsEditView-Night-3_4_null_1,NEXUS_5,1.0,en].png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:9eac310d1a3e7d0451ca0c21bcceeaab9c909b174a9040f31fd48a3b566673a4
-size 22568
+oid sha256:deb4b44dcd728ef7b7cef621dd67ac38087922aeeb6efffe3ab5b9ec9aa08b51
+size 22554
diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl.edit_RoomDetailsEditView_null_RoomDetailsEditView-Night-3_4_null_2,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl.edit_RoomDetailsEditView_null_RoomDetailsEditView-Night-3_4_null_2,NEXUS_5,1.0,en].png
index fbe3e62d98..19bb2dfe6a 100644
--- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl.edit_RoomDetailsEditView_null_RoomDetailsEditView-Night-3_4_null_2,NEXUS_5,1.0,en].png
+++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl.edit_RoomDetailsEditView_null_RoomDetailsEditView-Night-3_4_null_2,NEXUS_5,1.0,en].png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:fde4132005b1c340aff35cb703d1b2cbd43d0cdea9a552f90b7e124a909138c8
-size 54156
+oid sha256:62ee10256d36d435b0604e5014725de6eb4085d56390ece44852f0941115aebb
+size 30092
diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl.edit_RoomDetailsEditView_null_RoomDetailsEditView-Night-3_4_null_3,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl.edit_RoomDetailsEditView_null_RoomDetailsEditView-Night-3_4_null_3,NEXUS_5,1.0,en].png
index 387475fac7..652078a69f 100644
--- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl.edit_RoomDetailsEditView_null_RoomDetailsEditView-Night-3_4_null_3,NEXUS_5,1.0,en].png
+++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl.edit_RoomDetailsEditView_null_RoomDetailsEditView-Night-3_4_null_3,NEXUS_5,1.0,en].png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:5828dfd60d097c0d571f95c977c3b573ccb0853a50dca736b0024037dbfd7d66
-size 27797
+oid sha256:df342f6121b20e20c52bf3464be4cf6880607782d046009cc8af0e6ea3ac4644
+size 54149
diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl.edit_RoomDetailsEditView_null_RoomDetailsEditView-Night-3_4_null_4,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl.edit_RoomDetailsEditView_null_RoomDetailsEditView-Night-3_4_null_4,NEXUS_5,1.0,en].png
index b10994f542..9172ec80ba 100644
--- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl.edit_RoomDetailsEditView_null_RoomDetailsEditView-Night-3_4_null_4,NEXUS_5,1.0,en].png
+++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl.edit_RoomDetailsEditView_null_RoomDetailsEditView-Night-3_4_null_4,NEXUS_5,1.0,en].png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:f2bd04174660f32479aff938b2e9c19a7ddf2be8b90b83f51d775bacf5a5f187
-size 28584
+oid sha256:8fd504b944225a0b95bd041bde48865cc6b25f3641c70db32aa9f30e5c532975
+size 27772
diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl.edit_RoomDetailsEditView_null_RoomDetailsEditView-Night-3_4_null_5,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl.edit_RoomDetailsEditView_null_RoomDetailsEditView-Night-3_4_null_5,NEXUS_5,1.0,en].png
index b902d94951..320e35a1d6 100644
--- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl.edit_RoomDetailsEditView_null_RoomDetailsEditView-Night-3_4_null_5,NEXUS_5,1.0,en].png
+++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl.edit_RoomDetailsEditView_null_RoomDetailsEditView-Night-3_4_null_5,NEXUS_5,1.0,en].png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:7d6506e709ce97294d263032aa932eee53356c01b769f0ea0b6dc322ae7da393
-size 28026
+oid sha256:1da3677f03a01306116ae83dfd54e4ad29f414082be5611816411616b58bfe85
+size 28556
diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl.edit_RoomDetailsEditView_null_RoomDetailsEditView-Night-3_4_null_6,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl.edit_RoomDetailsEditView_null_RoomDetailsEditView-Night-3_4_null_6,NEXUS_5,1.0,en].png
index c8259d4147..d8c46db003 100644
--- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl.edit_RoomDetailsEditView_null_RoomDetailsEditView-Night-3_4_null_6,NEXUS_5,1.0,en].png
+++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl.edit_RoomDetailsEditView_null_RoomDetailsEditView-Night-3_4_null_6,NEXUS_5,1.0,en].png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:58c14e6556999a85fde1f898c2fb562fc403f38d9c287f3db44b9f0fb29496cc
-size 24255
+oid sha256:d5c26e007cdc2e7d47f79d662c64dae6ee4710e679766bc31f5eb20cfe8ddf57
+size 28023
diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl.edit_RoomDetailsEditView_null_RoomDetailsEditView-Night-3_4_null_7,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl.edit_RoomDetailsEditView_null_RoomDetailsEditView-Night-3_4_null_7,NEXUS_5,1.0,en].png
new file mode 100644
index 0000000000..ec3ab4b299
--- /dev/null
+++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl.edit_RoomDetailsEditView_null_RoomDetailsEditView-Night-3_4_null_7,NEXUS_5,1.0,en].png
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:dcb0135702ee7d8aeea60042289d30111c8b9b0d980860347f23f6ee37bd8c32
+size 24258
diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdirectory.impl.root_RoomDirectoryView_null_RoomDirectoryView-Day-0_1_null_3,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdirectory.impl.root_RoomDirectoryView_null_RoomDirectoryView-Day-0_1_null_3,NEXUS_5,1.0,en].png
deleted file mode 100644
index 4386d15a2d..0000000000
--- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdirectory.impl.root_RoomDirectoryView_null_RoomDirectoryView-Day-0_1_null_3,NEXUS_5,1.0,en].png
+++ /dev/null
@@ -1,3 +0,0 @@
-version https://git-lfs.github.com/spec/v1
-oid sha256:b717801c585a4a95f9d52984758d5d249a8f47a0a495c47b7300c8f440e0e1a9
-size 31641
diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdirectory.impl.root_RoomDirectoryView_null_RoomDirectoryView-Day-0_1_null_4,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdirectory.impl.root_RoomDirectoryView_null_RoomDirectoryView-Day-0_1_null_4,NEXUS_5,1.0,en].png
deleted file mode 100644
index 5a5947dffc..0000000000
--- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdirectory.impl.root_RoomDirectoryView_null_RoomDirectoryView-Day-0_1_null_4,NEXUS_5,1.0,en].png
+++ /dev/null
@@ -1,3 +0,0 @@
-version https://git-lfs.github.com/spec/v1
-oid sha256:e26380664b3d36f1be969f7bea8ec3ca8d053866d52e156fe6fa30767157e6a9
-size 35034
diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdirectory.impl.root_RoomDirectoryView_null_RoomDirectoryView-Night-0_2_null_3,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdirectory.impl.root_RoomDirectoryView_null_RoomDirectoryView-Night-0_2_null_3,NEXUS_5,1.0,en].png
deleted file mode 100644
index 0277d65597..0000000000
--- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdirectory.impl.root_RoomDirectoryView_null_RoomDirectoryView-Night-0_2_null_3,NEXUS_5,1.0,en].png
+++ /dev/null
@@ -1,3 +0,0 @@
-version https://git-lfs.github.com/spec/v1
-oid sha256:4bb5a5d3c9db11646da18b83e7eaf8503db6e5fe125beb22e7b1651e41d1b9e1
-size 28868
diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdirectory.impl.root_RoomDirectoryView_null_RoomDirectoryView-Night-0_2_null_4,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdirectory.impl.root_RoomDirectoryView_null_RoomDirectoryView-Night-0_2_null_4,NEXUS_5,1.0,en].png
deleted file mode 100644
index dc08bed121..0000000000
--- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdirectory.impl.root_RoomDirectoryView_null_RoomDirectoryView-Night-0_2_null_4,NEXUS_5,1.0,en].png
+++ /dev/null
@@ -1,3 +0,0 @@
-version https://git-lfs.github.com/spec/v1
-oid sha256:f5184c8c53c2943925af714cba4528133352b8dcde1051f9d00957e4e9beb20a
-size 31553
diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[l.designsystem.theme.components_ModalBottomSheetLayoutDark_null_BottomSheets_ModalBottomSheetLayoutDark_0_null,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[l.designsystem.theme.components_ModalBottomSheetLayoutDark_null_BottomSheets_ModalBottomSheetLayoutDark_0_null,NEXUS_5,1.0,en].png
deleted file mode 100644
index 73cdf31525..0000000000
--- a/tests/uitests/src/test/snapshots/images/ui_S_t[l.designsystem.theme.components_ModalBottomSheetLayoutDark_null_BottomSheets_ModalBottomSheetLayoutDark_0_null,NEXUS_5,1.0,en].png
+++ /dev/null
@@ -1,3 +0,0 @@
-version https://git-lfs.github.com/spec/v1
-oid sha256:761e809239fb9f3610e3c1760e999dd6129708e7ed41208c3eeb61f0dc0bc2bb
-size 10863
diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[l.designsystem.theme.components_ModalBottomSheetLayoutLight_null_BottomSheets_ModalBottomSheetLayoutLight_0_null,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[l.designsystem.theme.components_ModalBottomSheetLayoutLight_null_BottomSheets_ModalBottomSheetLayoutLight_0_null,NEXUS_5,1.0,en].png
deleted file mode 100644
index 7c19327f0e..0000000000
--- a/tests/uitests/src/test/snapshots/images/ui_S_t[l.designsystem.theme.components_ModalBottomSheetLayoutLight_null_BottomSheets_ModalBottomSheetLayoutLight_0_null,NEXUS_5,1.0,en].png
+++ /dev/null
@@ -1,3 +0,0 @@
-version https://git-lfs.github.com/spec/v1
-oid sha256:898b5ca8642123df13f95b0cbdc9252d6072be9b033e9bd227c32a9703328883
-size 10972
diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[l.matrix.ui.components_AvatarActionBottomSheet_null_AvatarActionBottomSheet-Day-1_2_null,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[l.matrix.ui.components_AvatarActionBottomSheet_null_AvatarActionBottomSheet-Day-1_2_null,NEXUS_5,1.0,en].png
index b8c565dcb9..9b1d7c4f19 100644
--- a/tests/uitests/src/test/snapshots/images/ui_S_t[l.matrix.ui.components_AvatarActionBottomSheet_null_AvatarActionBottomSheet-Day-1_2_null,NEXUS_5,1.0,en].png
+++ b/tests/uitests/src/test/snapshots/images/ui_S_t[l.matrix.ui.components_AvatarActionBottomSheet_null_AvatarActionBottomSheet-Day-1_2_null,NEXUS_5,1.0,en].png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:79d5851c4aac88fcf826cd9c1b114df2b82d7db132c34908f46696059404209d
-size 15176
+oid sha256:e1938c8062f0a198cbf5bdb17e24f25c76dd8e8b6efcec719cc4d996b4a18b73
+size 15291
diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[l.matrix.ui.components_AvatarActionBottomSheet_null_AvatarActionBottomSheet-Night-1_3_null,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[l.matrix.ui.components_AvatarActionBottomSheet_null_AvatarActionBottomSheet-Night-1_3_null,NEXUS_5,1.0,en].png
index ae89e9d151..6f3008e345 100644
--- a/tests/uitests/src/test/snapshots/images/ui_S_t[l.matrix.ui.components_AvatarActionBottomSheet_null_AvatarActionBottomSheet-Night-1_3_null,NEXUS_5,1.0,en].png
+++ b/tests/uitests/src/test/snapshots/images/ui_S_t[l.matrix.ui.components_AvatarActionBottomSheet_null_AvatarActionBottomSheet-Night-1_3_null,NEXUS_5,1.0,en].png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:0c2a1aaa27a9013d7f171e8463b3b32f19ce3be4f4094657a4c3f5c1e25aa88c
-size 13263
+oid sha256:f5d21fae9b198a9b7aef195938748ea5e06db9cbed397baa6cdbeb0a341393e5
+size 13485
diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[l.matrix.ui.components_EditableAvatarView_null_EditableAvatarView-Day-2_3_null_0,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[l.matrix.ui.components_EditableAvatarView_null_EditableAvatarView-Day-2_3_null_0,NEXUS_5,1.0,en].png
new file mode 100644
index 0000000000..7bf9b7c58d
--- /dev/null
+++ b/tests/uitests/src/test/snapshots/images/ui_S_t[l.matrix.ui.components_EditableAvatarView_null_EditableAvatarView-Day-2_3_null_0,NEXUS_5,1.0,en].png
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:befba1f1514fcf2f3a69b5f423fc66be7df252d133bff7fcda519c9f6acd4e8b
+size 8152
diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[l.matrix.ui.components_EditableAvatarView_null_EditableAvatarView-Day-2_3_null_1,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[l.matrix.ui.components_EditableAvatarView_null_EditableAvatarView-Day-2_3_null_1,NEXUS_5,1.0,en].png
new file mode 100644
index 0000000000..b6538451e8
--- /dev/null
+++ b/tests/uitests/src/test/snapshots/images/ui_S_t[l.matrix.ui.components_EditableAvatarView_null_EditableAvatarView-Day-2_3_null_1,NEXUS_5,1.0,en].png
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:1f9f0c4e62431e9aa5543f28f2784ae3e245cde22ed2745f15ba3fe7be2f8ef0
+size 10287
diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[l.matrix.ui.components_EditableAvatarView_null_EditableAvatarView-Day-2_3_null_2,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[l.matrix.ui.components_EditableAvatarView_null_EditableAvatarView-Day-2_3_null_2,NEXUS_5,1.0,en].png
new file mode 100644
index 0000000000..918da11691
--- /dev/null
+++ b/tests/uitests/src/test/snapshots/images/ui_S_t[l.matrix.ui.components_EditableAvatarView_null_EditableAvatarView-Day-2_3_null_2,NEXUS_5,1.0,en].png
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:fcb18ec6ab064604201838b3a1497dd236731c61cc85d7be937071870dfeb5d6
+size 34082
diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[l.matrix.ui.components_EditableAvatarView_null_EditableAvatarView-Night-2_4_null_0,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[l.matrix.ui.components_EditableAvatarView_null_EditableAvatarView-Night-2_4_null_0,NEXUS_5,1.0,en].png
new file mode 100644
index 0000000000..fb4521b9ce
--- /dev/null
+++ b/tests/uitests/src/test/snapshots/images/ui_S_t[l.matrix.ui.components_EditableAvatarView_null_EditableAvatarView-Night-2_4_null_0,NEXUS_5,1.0,en].png
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:3eae0336bcaf91c668a8a26331718085b282f335ad85a0b5eaa0b2c24d890627
+size 8424
diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[l.matrix.ui.components_EditableAvatarView_null_EditableAvatarView-Night-2_4_null_1,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[l.matrix.ui.components_EditableAvatarView_null_EditableAvatarView-Night-2_4_null_1,NEXUS_5,1.0,en].png
new file mode 100644
index 0000000000..c3060dd092
--- /dev/null
+++ b/tests/uitests/src/test/snapshots/images/ui_S_t[l.matrix.ui.components_EditableAvatarView_null_EditableAvatarView-Night-2_4_null_1,NEXUS_5,1.0,en].png
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:c2da272b8bc76f7d6dc3b79bdae73014d831c0fd225f830d6e15eaf4c8060737
+size 10435
diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[l.matrix.ui.components_EditableAvatarView_null_EditableAvatarView-Night-2_4_null_2,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[l.matrix.ui.components_EditableAvatarView_null_EditableAvatarView-Night-2_4_null_2,NEXUS_5,1.0,en].png
new file mode 100644
index 0000000000..122bb0b96c
--- /dev/null
+++ b/tests/uitests/src/test/snapshots/images/ui_S_t[l.matrix.ui.components_EditableAvatarView_null_EditableAvatarView-Night-2_4_null_2,NEXUS_5,1.0,en].png
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:36dc08ee4cb55da521a2577715de85049ccfde5c9ed10db248fc2cd8418084f9
+size 33745
diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[l.matrix.ui.components_InviteSenderView_null_InviteSenderView-Day-2_3_null,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[l.matrix.ui.components_InviteSenderView_null_InviteSenderView-Day-3_4_null,NEXUS_5,1.0,en].png
similarity index 100%
rename from tests/uitests/src/test/snapshots/images/ui_S_t[l.matrix.ui.components_InviteSenderView_null_InviteSenderView-Day-2_3_null,NEXUS_5,1.0,en].png
rename to tests/uitests/src/test/snapshots/images/ui_S_t[l.matrix.ui.components_InviteSenderView_null_InviteSenderView-Day-3_4_null,NEXUS_5,1.0,en].png
diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[l.matrix.ui.components_InviteSenderView_null_InviteSenderView-Night-2_4_null,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[l.matrix.ui.components_InviteSenderView_null_InviteSenderView-Night-3_5_null,NEXUS_5,1.0,en].png
similarity index 100%
rename from tests/uitests/src/test/snapshots/images/ui_S_t[l.matrix.ui.components_InviteSenderView_null_InviteSenderView-Night-2_4_null,NEXUS_5,1.0,en].png
rename to tests/uitests/src/test/snapshots/images/ui_S_t[l.matrix.ui.components_InviteSenderView_null_InviteSenderView-Night-3_5_null,NEXUS_5,1.0,en].png
diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[l.matrix.ui.components_MatrixUserHeaderPlaceholder_null_MatrixUserHeaderPlaceholder-Day-4_5_null,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[l.matrix.ui.components_MatrixUserHeaderPlaceholder_null_MatrixUserHeaderPlaceholder-Day-5_6_null,NEXUS_5,1.0,en].png
similarity index 100%
rename from tests/uitests/src/test/snapshots/images/ui_S_t[l.matrix.ui.components_MatrixUserHeaderPlaceholder_null_MatrixUserHeaderPlaceholder-Day-4_5_null,NEXUS_5,1.0,en].png
rename to tests/uitests/src/test/snapshots/images/ui_S_t[l.matrix.ui.components_MatrixUserHeaderPlaceholder_null_MatrixUserHeaderPlaceholder-Day-5_6_null,NEXUS_5,1.0,en].png
diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[l.matrix.ui.components_MatrixUserHeaderPlaceholder_null_MatrixUserHeaderPlaceholder-Night-4_6_null,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[l.matrix.ui.components_MatrixUserHeaderPlaceholder_null_MatrixUserHeaderPlaceholder-Night-5_7_null,NEXUS_5,1.0,en].png
similarity index 100%
rename from tests/uitests/src/test/snapshots/images/ui_S_t[l.matrix.ui.components_MatrixUserHeaderPlaceholder_null_MatrixUserHeaderPlaceholder-Night-4_6_null,NEXUS_5,1.0,en].png
rename to tests/uitests/src/test/snapshots/images/ui_S_t[l.matrix.ui.components_MatrixUserHeaderPlaceholder_null_MatrixUserHeaderPlaceholder-Night-5_7_null,NEXUS_5,1.0,en].png
diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[l.matrix.ui.components_MatrixUserHeader_null_MatrixUserHeader-Day-3_4_null_0,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[l.matrix.ui.components_MatrixUserHeader_null_MatrixUserHeader-Day-4_5_null_0,NEXUS_5,1.0,en].png
similarity index 100%
rename from tests/uitests/src/test/snapshots/images/ui_S_t[l.matrix.ui.components_MatrixUserHeader_null_MatrixUserHeader-Day-3_4_null_0,NEXUS_5,1.0,en].png
rename to tests/uitests/src/test/snapshots/images/ui_S_t[l.matrix.ui.components_MatrixUserHeader_null_MatrixUserHeader-Day-4_5_null_0,NEXUS_5,1.0,en].png
diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[l.matrix.ui.components_MatrixUserHeader_null_MatrixUserHeader-Day-3_4_null_1,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[l.matrix.ui.components_MatrixUserHeader_null_MatrixUserHeader-Day-4_5_null_1,NEXUS_5,1.0,en].png
similarity index 100%
rename from tests/uitests/src/test/snapshots/images/ui_S_t[l.matrix.ui.components_MatrixUserHeader_null_MatrixUserHeader-Day-3_4_null_1,NEXUS_5,1.0,en].png
rename to tests/uitests/src/test/snapshots/images/ui_S_t[l.matrix.ui.components_MatrixUserHeader_null_MatrixUserHeader-Day-4_5_null_1,NEXUS_5,1.0,en].png
diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[l.matrix.ui.components_MatrixUserHeader_null_MatrixUserHeader-Night-3_5_null_0,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[l.matrix.ui.components_MatrixUserHeader_null_MatrixUserHeader-Night-4_6_null_0,NEXUS_5,1.0,en].png
similarity index 100%
rename from tests/uitests/src/test/snapshots/images/ui_S_t[l.matrix.ui.components_MatrixUserHeader_null_MatrixUserHeader-Night-3_5_null_0,NEXUS_5,1.0,en].png
rename to tests/uitests/src/test/snapshots/images/ui_S_t[l.matrix.ui.components_MatrixUserHeader_null_MatrixUserHeader-Night-4_6_null_0,NEXUS_5,1.0,en].png
diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[l.matrix.ui.components_MatrixUserHeader_null_MatrixUserHeader-Night-3_5_null_1,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[l.matrix.ui.components_MatrixUserHeader_null_MatrixUserHeader-Night-4_6_null_1,NEXUS_5,1.0,en].png
similarity index 100%
rename from tests/uitests/src/test/snapshots/images/ui_S_t[l.matrix.ui.components_MatrixUserHeader_null_MatrixUserHeader-Night-3_5_null_1,NEXUS_5,1.0,en].png
rename to tests/uitests/src/test/snapshots/images/ui_S_t[l.matrix.ui.components_MatrixUserHeader_null_MatrixUserHeader-Night-4_6_null_1,NEXUS_5,1.0,en].png
diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[l.matrix.ui.components_MatrixUserRow_null_MatrixUserRow-Day-5_6_null_0,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[l.matrix.ui.components_MatrixUserRow_null_MatrixUserRow-Day-6_7_null_0,NEXUS_5,1.0,en].png
similarity index 100%
rename from tests/uitests/src/test/snapshots/images/ui_S_t[l.matrix.ui.components_MatrixUserRow_null_MatrixUserRow-Day-5_6_null_0,NEXUS_5,1.0,en].png
rename to tests/uitests/src/test/snapshots/images/ui_S_t[l.matrix.ui.components_MatrixUserRow_null_MatrixUserRow-Day-6_7_null_0,NEXUS_5,1.0,en].png
diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[l.matrix.ui.components_MatrixUserRow_null_MatrixUserRow-Day-5_6_null_1,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[l.matrix.ui.components_MatrixUserRow_null_MatrixUserRow-Day-6_7_null_1,NEXUS_5,1.0,en].png
similarity index 100%
rename from tests/uitests/src/test/snapshots/images/ui_S_t[l.matrix.ui.components_MatrixUserRow_null_MatrixUserRow-Day-5_6_null_1,NEXUS_5,1.0,en].png
rename to tests/uitests/src/test/snapshots/images/ui_S_t[l.matrix.ui.components_MatrixUserRow_null_MatrixUserRow-Day-6_7_null_1,NEXUS_5,1.0,en].png
diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[l.matrix.ui.components_MatrixUserRow_null_MatrixUserRow-Night-5_7_null_0,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[l.matrix.ui.components_MatrixUserRow_null_MatrixUserRow-Night-6_8_null_0,NEXUS_5,1.0,en].png
similarity index 100%
rename from tests/uitests/src/test/snapshots/images/ui_S_t[l.matrix.ui.components_MatrixUserRow_null_MatrixUserRow-Night-5_7_null_0,NEXUS_5,1.0,en].png
rename to tests/uitests/src/test/snapshots/images/ui_S_t[l.matrix.ui.components_MatrixUserRow_null_MatrixUserRow-Night-6_8_null_0,NEXUS_5,1.0,en].png
diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[l.matrix.ui.components_MatrixUserRow_null_MatrixUserRow-Night-5_7_null_1,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[l.matrix.ui.components_MatrixUserRow_null_MatrixUserRow-Night-6_8_null_1,NEXUS_5,1.0,en].png
similarity index 100%
rename from tests/uitests/src/test/snapshots/images/ui_S_t[l.matrix.ui.components_MatrixUserRow_null_MatrixUserRow-Night-5_7_null_1,NEXUS_5,1.0,en].png
rename to tests/uitests/src/test/snapshots/images/ui_S_t[l.matrix.ui.components_MatrixUserRow_null_MatrixUserRow-Night-6_8_null_1,NEXUS_5,1.0,en].png
diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[l.matrix.ui.components_SelectedRoom_null_SelectedRoom-Day-6_7_null_0,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[l.matrix.ui.components_SelectedRoom_null_SelectedRoom-Day-7_8_null_0,NEXUS_5,1.0,en].png
similarity index 100%
rename from tests/uitests/src/test/snapshots/images/ui_S_t[l.matrix.ui.components_SelectedRoom_null_SelectedRoom-Day-6_7_null_0,NEXUS_5,1.0,en].png
rename to tests/uitests/src/test/snapshots/images/ui_S_t[l.matrix.ui.components_SelectedRoom_null_SelectedRoom-Day-7_8_null_0,NEXUS_5,1.0,en].png
diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[l.matrix.ui.components_SelectedRoom_null_SelectedRoom-Day-6_7_null_1,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[l.matrix.ui.components_SelectedRoom_null_SelectedRoom-Day-7_8_null_1,NEXUS_5,1.0,en].png
similarity index 100%
rename from tests/uitests/src/test/snapshots/images/ui_S_t[l.matrix.ui.components_SelectedRoom_null_SelectedRoom-Day-6_7_null_1,NEXUS_5,1.0,en].png
rename to tests/uitests/src/test/snapshots/images/ui_S_t[l.matrix.ui.components_SelectedRoom_null_SelectedRoom-Day-7_8_null_1,NEXUS_5,1.0,en].png
diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[l.matrix.ui.components_SelectedRoom_null_SelectedRoom-Night-6_8_null_0,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[l.matrix.ui.components_SelectedRoom_null_SelectedRoom-Night-7_9_null_0,NEXUS_5,1.0,en].png
similarity index 100%
rename from tests/uitests/src/test/snapshots/images/ui_S_t[l.matrix.ui.components_SelectedRoom_null_SelectedRoom-Night-6_8_null_0,NEXUS_5,1.0,en].png
rename to tests/uitests/src/test/snapshots/images/ui_S_t[l.matrix.ui.components_SelectedRoom_null_SelectedRoom-Night-7_9_null_0,NEXUS_5,1.0,en].png
diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[l.matrix.ui.components_SelectedRoom_null_SelectedRoom-Night-6_8_null_1,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[l.matrix.ui.components_SelectedRoom_null_SelectedRoom-Night-7_9_null_1,NEXUS_5,1.0,en].png
similarity index 100%
rename from tests/uitests/src/test/snapshots/images/ui_S_t[l.matrix.ui.components_SelectedRoom_null_SelectedRoom-Night-6_8_null_1,NEXUS_5,1.0,en].png
rename to tests/uitests/src/test/snapshots/images/ui_S_t[l.matrix.ui.components_SelectedRoom_null_SelectedRoom-Night-7_9_null_1,NEXUS_5,1.0,en].png
diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[l.matrix.ui.components_SelectedUserCannotRemove_null_SelectedUserCannotRemove-Day-8_9_null,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[l.matrix.ui.components_SelectedUserCannotRemove_null_SelectedUserCannotRemove-Day-9_10_null,NEXUS_5,1.0,en].png
similarity index 100%
rename from tests/uitests/src/test/snapshots/images/ui_S_t[l.matrix.ui.components_SelectedUserCannotRemove_null_SelectedUserCannotRemove-Day-8_9_null,NEXUS_5,1.0,en].png
rename to tests/uitests/src/test/snapshots/images/ui_S_t[l.matrix.ui.components_SelectedUserCannotRemove_null_SelectedUserCannotRemove-Day-9_10_null,NEXUS_5,1.0,en].png
diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[l.matrix.ui.components_SelectedUserCannotRemove_null_SelectedUserCannotRemove-Night-8_10_null,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[l.matrix.ui.components_SelectedUserCannotRemove_null_SelectedUserCannotRemove-Night-9_11_null,NEXUS_5,1.0,en].png
similarity index 100%
rename from tests/uitests/src/test/snapshots/images/ui_S_t[l.matrix.ui.components_SelectedUserCannotRemove_null_SelectedUserCannotRemove-Night-8_10_null,NEXUS_5,1.0,en].png
rename to tests/uitests/src/test/snapshots/images/ui_S_t[l.matrix.ui.components_SelectedUserCannotRemove_null_SelectedUserCannotRemove-Night-9_11_null,NEXUS_5,1.0,en].png
diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[l.matrix.ui.components_SelectedUser_null_SelectedUser-Day-7_8_null,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[l.matrix.ui.components_SelectedUser_null_SelectedUser-Day-8_9_null,NEXUS_5,1.0,en].png
similarity index 100%
rename from tests/uitests/src/test/snapshots/images/ui_S_t[l.matrix.ui.components_SelectedUser_null_SelectedUser-Day-7_8_null,NEXUS_5,1.0,en].png
rename to tests/uitests/src/test/snapshots/images/ui_S_t[l.matrix.ui.components_SelectedUser_null_SelectedUser-Day-8_9_null,NEXUS_5,1.0,en].png
diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[l.matrix.ui.components_SelectedUser_null_SelectedUser-Night-7_9_null,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[l.matrix.ui.components_SelectedUser_null_SelectedUser-Night-8_10_null,NEXUS_5,1.0,en].png
similarity index 100%
rename from tests/uitests/src/test/snapshots/images/ui_S_t[l.matrix.ui.components_SelectedUser_null_SelectedUser-Night-7_9_null,NEXUS_5,1.0,en].png
rename to tests/uitests/src/test/snapshots/images/ui_S_t[l.matrix.ui.components_SelectedUser_null_SelectedUser-Night-8_10_null,NEXUS_5,1.0,en].png
diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[l.matrix.ui.components_SelectedUsersRowList_null_SelectedUsersRowList-Day-9_10_null,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[l.matrix.ui.components_SelectedUsersRowList_null_SelectedUsersRowList-Day-10_11_null,NEXUS_5,1.0,en].png
similarity index 100%
rename from tests/uitests/src/test/snapshots/images/ui_S_t[l.matrix.ui.components_SelectedUsersRowList_null_SelectedUsersRowList-Day-9_10_null,NEXUS_5,1.0,en].png
rename to tests/uitests/src/test/snapshots/images/ui_S_t[l.matrix.ui.components_SelectedUsersRowList_null_SelectedUsersRowList-Day-10_11_null,NEXUS_5,1.0,en].png
diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[l.matrix.ui.components_SelectedUsersRowList_null_SelectedUsersRowList-Night-9_11_null,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[l.matrix.ui.components_SelectedUsersRowList_null_SelectedUsersRowList-Night-10_12_null,NEXUS_5,1.0,en].png
similarity index 100%
rename from tests/uitests/src/test/snapshots/images/ui_S_t[l.matrix.ui.components_SelectedUsersRowList_null_SelectedUsersRowList-Night-9_11_null,NEXUS_5,1.0,en].png
rename to tests/uitests/src/test/snapshots/images/ui_S_t[l.matrix.ui.components_SelectedUsersRowList_null_SelectedUsersRowList-Night-10_12_null,NEXUS_5,1.0,en].png
diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[l.matrix.ui.components_UnsavedAvatar_null_UnsavedAvatar-Day-10_11_null,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[l.matrix.ui.components_UnsavedAvatar_null_UnsavedAvatar-Day-11_12_null,NEXUS_5,1.0,en].png
similarity index 100%
rename from tests/uitests/src/test/snapshots/images/ui_S_t[l.matrix.ui.components_UnsavedAvatar_null_UnsavedAvatar-Day-10_11_null,NEXUS_5,1.0,en].png
rename to tests/uitests/src/test/snapshots/images/ui_S_t[l.matrix.ui.components_UnsavedAvatar_null_UnsavedAvatar-Day-11_12_null,NEXUS_5,1.0,en].png
diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[l.matrix.ui.components_UnsavedAvatar_null_UnsavedAvatar-Night-10_12_null,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[l.matrix.ui.components_UnsavedAvatar_null_UnsavedAvatar-Night-11_13_null,NEXUS_5,1.0,en].png
similarity index 100%
rename from tests/uitests/src/test/snapshots/images/ui_S_t[l.matrix.ui.components_UnsavedAvatar_null_UnsavedAvatar-Night-10_12_null,NEXUS_5,1.0,en].png
rename to tests/uitests/src/test/snapshots/images/ui_S_t[l.matrix.ui.components_UnsavedAvatar_null_UnsavedAvatar-Night-11_13_null,NEXUS_5,1.0,en].png
diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[l.textcomposer.components.markdown_MarkdownTextInput_null_MarkdownTextInput-Day-19_20_null,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[l.textcomposer.components.markdown_MarkdownTextInput_null_MarkdownTextInput-Day-19_20_null,NEXUS_5,1.0,en].png
new file mode 100644
index 0000000000..ec896e7a81
--- /dev/null
+++ b/tests/uitests/src/test/snapshots/images/ui_S_t[l.textcomposer.components.markdown_MarkdownTextInput_null_MarkdownTextInput-Day-19_20_null,NEXUS_5,1.0,en].png
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:21d806b169f6cdce5f454c43e7877d454c4e6243af3f6de85f5c70637c8f3603
+size 7277
diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[l.textcomposer.components.markdown_MarkdownTextInput_null_MarkdownTextInput-Night-19_21_null,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[l.textcomposer.components.markdown_MarkdownTextInput_null_MarkdownTextInput-Night-19_21_null,NEXUS_5,1.0,en].png
new file mode 100644
index 0000000000..2f1ca90da9
--- /dev/null
+++ b/tests/uitests/src/test/snapshots/images/ui_S_t[l.textcomposer.components.markdown_MarkdownTextInput_null_MarkdownTextInput-Night-19_21_null,NEXUS_5,1.0,en].png
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:6a22b040124c765a1ab46b91afa2df411c3da3333ff12977bff2537bd152840d
+size 7001
diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[l.textcomposer.components_ComposerOptionsButton_null_ComposerOptionsButton-Day-8_9_null,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[l.textcomposer.components_ComposerOptionsButton_null_ComposerOptionsButton-Day-9_10_null,NEXUS_5,1.0,en].png
similarity index 100%
rename from tests/uitests/src/test/snapshots/images/ui_S_t[l.textcomposer.components_ComposerOptionsButton_null_ComposerOptionsButton-Day-8_9_null,NEXUS_5,1.0,en].png
rename to tests/uitests/src/test/snapshots/images/ui_S_t[l.textcomposer.components_ComposerOptionsButton_null_ComposerOptionsButton-Day-9_10_null,NEXUS_5,1.0,en].png
diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[l.textcomposer.components_ComposerOptionsButton_null_ComposerOptionsButton-Night-8_10_null,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[l.textcomposer.components_ComposerOptionsButton_null_ComposerOptionsButton-Night-9_11_null,NEXUS_5,1.0,en].png
similarity index 100%
rename from tests/uitests/src/test/snapshots/images/ui_S_t[l.textcomposer.components_ComposerOptionsButton_null_ComposerOptionsButton-Night-8_10_null,NEXUS_5,1.0,en].png
rename to tests/uitests/src/test/snapshots/images/ui_S_t[l.textcomposer.components_ComposerOptionsButton_null_ComposerOptionsButton-Night-9_11_null,NEXUS_5,1.0,en].png
diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[l.textcomposer.components_DismissTextFormattingButton_null_DismissTextFormattingButton-Day-9_10_null,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[l.textcomposer.components_DismissTextFormattingButton_null_DismissTextFormattingButton-Day-10_11_null,NEXUS_5,1.0,en].png
similarity index 100%
rename from tests/uitests/src/test/snapshots/images/ui_S_t[l.textcomposer.components_DismissTextFormattingButton_null_DismissTextFormattingButton-Day-9_10_null,NEXUS_5,1.0,en].png
rename to tests/uitests/src/test/snapshots/images/ui_S_t[l.textcomposer.components_DismissTextFormattingButton_null_DismissTextFormattingButton-Day-10_11_null,NEXUS_5,1.0,en].png
diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[l.textcomposer.components_DismissTextFormattingButton_null_DismissTextFormattingButton-Night-9_11_null,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[l.textcomposer.components_DismissTextFormattingButton_null_DismissTextFormattingButton-Night-10_12_null,NEXUS_5,1.0,en].png
similarity index 100%
rename from tests/uitests/src/test/snapshots/images/ui_S_t[l.textcomposer.components_DismissTextFormattingButton_null_DismissTextFormattingButton-Night-9_11_null,NEXUS_5,1.0,en].png
rename to tests/uitests/src/test/snapshots/images/ui_S_t[l.textcomposer.components_DismissTextFormattingButton_null_DismissTextFormattingButton-Night-10_12_null,NEXUS_5,1.0,en].png
diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[l.textcomposer.components_FormattingOption_null_FormattingOption-Day-10_11_null,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[l.textcomposer.components_FormattingOption_null_FormattingOption-Day-11_12_null,NEXUS_5,1.0,en].png
similarity index 100%
rename from tests/uitests/src/test/snapshots/images/ui_S_t[l.textcomposer.components_FormattingOption_null_FormattingOption-Day-10_11_null,NEXUS_5,1.0,en].png
rename to tests/uitests/src/test/snapshots/images/ui_S_t[l.textcomposer.components_FormattingOption_null_FormattingOption-Day-11_12_null,NEXUS_5,1.0,en].png
diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[l.textcomposer.components_FormattingOption_null_FormattingOption-Night-10_12_null,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[l.textcomposer.components_FormattingOption_null_FormattingOption-Night-11_13_null,NEXUS_5,1.0,en].png
similarity index 100%
rename from tests/uitests/src/test/snapshots/images/ui_S_t[l.textcomposer.components_FormattingOption_null_FormattingOption-Night-10_12_null,NEXUS_5,1.0,en].png
rename to tests/uitests/src/test/snapshots/images/ui_S_t[l.textcomposer.components_FormattingOption_null_FormattingOption-Night-11_13_null,NEXUS_5,1.0,en].png
diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[l.textcomposer.components_LiveWaveformView_null_LiveWaveformView-Day-11_12_null,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[l.textcomposer.components_LiveWaveformView_null_LiveWaveformView-Day-12_13_null,NEXUS_5,1.0,en].png
similarity index 100%
rename from tests/uitests/src/test/snapshots/images/ui_S_t[l.textcomposer.components_LiveWaveformView_null_LiveWaveformView-Day-11_12_null,NEXUS_5,1.0,en].png
rename to tests/uitests/src/test/snapshots/images/ui_S_t[l.textcomposer.components_LiveWaveformView_null_LiveWaveformView-Day-12_13_null,NEXUS_5,1.0,en].png
diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[l.textcomposer.components_LiveWaveformView_null_LiveWaveformView-Night-11_13_null,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[l.textcomposer.components_LiveWaveformView_null_LiveWaveformView-Night-12_14_null,NEXUS_5,1.0,en].png
similarity index 100%
rename from tests/uitests/src/test/snapshots/images/ui_S_t[l.textcomposer.components_LiveWaveformView_null_LiveWaveformView-Night-11_13_null,NEXUS_5,1.0,en].png
rename to tests/uitests/src/test/snapshots/images/ui_S_t[l.textcomposer.components_LiveWaveformView_null_LiveWaveformView-Night-12_14_null,NEXUS_5,1.0,en].png
diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[l.textcomposer.components_SendButton_null_SendButton-Day-12_13_null,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[l.textcomposer.components_SendButton_null_SendButton-Day-13_14_null,NEXUS_5,1.0,en].png
similarity index 100%
rename from tests/uitests/src/test/snapshots/images/ui_S_t[l.textcomposer.components_SendButton_null_SendButton-Day-12_13_null,NEXUS_5,1.0,en].png
rename to tests/uitests/src/test/snapshots/images/ui_S_t[l.textcomposer.components_SendButton_null_SendButton-Day-13_14_null,NEXUS_5,1.0,en].png
diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[l.textcomposer.components_SendButton_null_SendButton-Night-12_14_null,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[l.textcomposer.components_SendButton_null_SendButton-Night-13_15_null,NEXUS_5,1.0,en].png
similarity index 100%
rename from tests/uitests/src/test/snapshots/images/ui_S_t[l.textcomposer.components_SendButton_null_SendButton-Night-12_14_null,NEXUS_5,1.0,en].png
rename to tests/uitests/src/test/snapshots/images/ui_S_t[l.textcomposer.components_SendButton_null_SendButton-Night-13_15_null,NEXUS_5,1.0,en].png
diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[l.textcomposer.components_TextFormatting_null_TextFormatting-Day-13_14_null,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[l.textcomposer.components_TextFormatting_null_TextFormatting-Day-14_15_null,NEXUS_5,1.0,en].png
similarity index 100%
rename from tests/uitests/src/test/snapshots/images/ui_S_t[l.textcomposer.components_TextFormatting_null_TextFormatting-Day-13_14_null,NEXUS_5,1.0,en].png
rename to tests/uitests/src/test/snapshots/images/ui_S_t[l.textcomposer.components_TextFormatting_null_TextFormatting-Day-14_15_null,NEXUS_5,1.0,en].png
diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[l.textcomposer.components_TextFormatting_null_TextFormatting-Night-13_15_null,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[l.textcomposer.components_TextFormatting_null_TextFormatting-Night-14_16_null,NEXUS_5,1.0,en].png
similarity index 100%
rename from tests/uitests/src/test/snapshots/images/ui_S_t[l.textcomposer.components_TextFormatting_null_TextFormatting-Night-13_15_null,NEXUS_5,1.0,en].png
rename to tests/uitests/src/test/snapshots/images/ui_S_t[l.textcomposer.components_TextFormatting_null_TextFormatting-Night-14_16_null,NEXUS_5,1.0,en].png
diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[l.textcomposer.components_VoiceMessageDeleteButton_null_VoiceMessageDeleteButton-Day-14_15_null,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[l.textcomposer.components_VoiceMessageDeleteButton_null_VoiceMessageDeleteButton-Day-15_16_null,NEXUS_5,1.0,en].png
similarity index 100%
rename from tests/uitests/src/test/snapshots/images/ui_S_t[l.textcomposer.components_VoiceMessageDeleteButton_null_VoiceMessageDeleteButton-Day-14_15_null,NEXUS_5,1.0,en].png
rename to tests/uitests/src/test/snapshots/images/ui_S_t[l.textcomposer.components_VoiceMessageDeleteButton_null_VoiceMessageDeleteButton-Day-15_16_null,NEXUS_5,1.0,en].png
diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[l.textcomposer.components_VoiceMessageDeleteButton_null_VoiceMessageDeleteButton-Night-14_16_null,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[l.textcomposer.components_VoiceMessageDeleteButton_null_VoiceMessageDeleteButton-Night-15_17_null,NEXUS_5,1.0,en].png
similarity index 100%
rename from tests/uitests/src/test/snapshots/images/ui_S_t[l.textcomposer.components_VoiceMessageDeleteButton_null_VoiceMessageDeleteButton-Night-14_16_null,NEXUS_5,1.0,en].png
rename to tests/uitests/src/test/snapshots/images/ui_S_t[l.textcomposer.components_VoiceMessageDeleteButton_null_VoiceMessageDeleteButton-Night-15_17_null,NEXUS_5,1.0,en].png
diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[l.textcomposer.components_VoiceMessagePreview_null_VoiceMessagePreview-Day-15_16_null,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[l.textcomposer.components_VoiceMessagePreview_null_VoiceMessagePreview-Day-16_17_null,NEXUS_5,1.0,en].png
similarity index 100%
rename from tests/uitests/src/test/snapshots/images/ui_S_t[l.textcomposer.components_VoiceMessagePreview_null_VoiceMessagePreview-Day-15_16_null,NEXUS_5,1.0,en].png
rename to tests/uitests/src/test/snapshots/images/ui_S_t[l.textcomposer.components_VoiceMessagePreview_null_VoiceMessagePreview-Day-16_17_null,NEXUS_5,1.0,en].png
diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[l.textcomposer.components_VoiceMessagePreview_null_VoiceMessagePreview-Night-15_17_null,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[l.textcomposer.components_VoiceMessagePreview_null_VoiceMessagePreview-Night-16_18_null,NEXUS_5,1.0,en].png
similarity index 100%
rename from tests/uitests/src/test/snapshots/images/ui_S_t[l.textcomposer.components_VoiceMessagePreview_null_VoiceMessagePreview-Night-15_17_null,NEXUS_5,1.0,en].png
rename to tests/uitests/src/test/snapshots/images/ui_S_t[l.textcomposer.components_VoiceMessagePreview_null_VoiceMessagePreview-Night-16_18_null,NEXUS_5,1.0,en].png
diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[l.textcomposer.components_VoiceMessageRecorderButton_null_VoiceMessageRecorderButton-Day-16_17_null,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[l.textcomposer.components_VoiceMessageRecorderButton_null_VoiceMessageRecorderButton-Day-17_18_null,NEXUS_5,1.0,en].png
similarity index 100%
rename from tests/uitests/src/test/snapshots/images/ui_S_t[l.textcomposer.components_VoiceMessageRecorderButton_null_VoiceMessageRecorderButton-Day-16_17_null,NEXUS_5,1.0,en].png
rename to tests/uitests/src/test/snapshots/images/ui_S_t[l.textcomposer.components_VoiceMessageRecorderButton_null_VoiceMessageRecorderButton-Day-17_18_null,NEXUS_5,1.0,en].png
diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[l.textcomposer.components_VoiceMessageRecorderButton_null_VoiceMessageRecorderButton-Night-16_18_null,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[l.textcomposer.components_VoiceMessageRecorderButton_null_VoiceMessageRecorderButton-Night-17_19_null,NEXUS_5,1.0,en].png
similarity index 100%
rename from tests/uitests/src/test/snapshots/images/ui_S_t[l.textcomposer.components_VoiceMessageRecorderButton_null_VoiceMessageRecorderButton-Night-16_18_null,NEXUS_5,1.0,en].png
rename to tests/uitests/src/test/snapshots/images/ui_S_t[l.textcomposer.components_VoiceMessageRecorderButton_null_VoiceMessageRecorderButton-Night-17_19_null,NEXUS_5,1.0,en].png
diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[l.textcomposer.components_VoiceMessageRecording_null_VoiceMessageRecording-Day-17_18_null,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[l.textcomposer.components_VoiceMessageRecording_null_VoiceMessageRecording-Day-18_19_null,NEXUS_5,1.0,en].png
similarity index 100%
rename from tests/uitests/src/test/snapshots/images/ui_S_t[l.textcomposer.components_VoiceMessageRecording_null_VoiceMessageRecording-Day-17_18_null,NEXUS_5,1.0,en].png
rename to tests/uitests/src/test/snapshots/images/ui_S_t[l.textcomposer.components_VoiceMessageRecording_null_VoiceMessageRecording-Day-18_19_null,NEXUS_5,1.0,en].png
diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[l.textcomposer.components_VoiceMessageRecording_null_VoiceMessageRecording-Night-17_19_null,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[l.textcomposer.components_VoiceMessageRecording_null_VoiceMessageRecording-Night-18_20_null,NEXUS_5,1.0,en].png
similarity index 100%
rename from tests/uitests/src/test/snapshots/images/ui_S_t[l.textcomposer.components_VoiceMessageRecording_null_VoiceMessageRecording-Night-17_19_null,NEXUS_5,1.0,en].png
rename to tests/uitests/src/test/snapshots/images/ui_S_t[l.textcomposer.components_VoiceMessageRecording_null_VoiceMessageRecording-Night-18_20_null,NEXUS_5,1.0,en].png
diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[l.textcomposer.mentions_MentionSpan_null_MentionSpan-Day-18_19_null,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[l.textcomposer.mentions_MentionSpan_null_MentionSpan-Day-18_19_null,NEXUS_5,1.0,en].png
deleted file mode 100644
index 077598db00..0000000000
--- a/tests/uitests/src/test/snapshots/images/ui_S_t[l.textcomposer.mentions_MentionSpan_null_MentionSpan-Day-18_19_null,NEXUS_5,1.0,en].png
+++ /dev/null
@@ -1,3 +0,0 @@
-version https://git-lfs.github.com/spec/v1
-oid sha256:c17bc39b80bbed42378b2df6ad2332b8da78b315a177f56a7eca0a7b595a3036
-size 43943
diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[l.textcomposer.mentions_MentionSpan_null_MentionSpan-Day-20_21_null,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[l.textcomposer.mentions_MentionSpan_null_MentionSpan-Day-20_21_null,NEXUS_5,1.0,en].png
new file mode 100644
index 0000000000..67ee9d1eb8
--- /dev/null
+++ b/tests/uitests/src/test/snapshots/images/ui_S_t[l.textcomposer.mentions_MentionSpan_null_MentionSpan-Day-20_21_null,NEXUS_5,1.0,en].png
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:6bef87fa9b2320571b91093cbe3293b67d9e2180edf036b9bc894da6c6ea6a8d
+size 39499
diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[l.textcomposer.mentions_MentionSpan_null_MentionSpan-Night-18_20_null,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[l.textcomposer.mentions_MentionSpan_null_MentionSpan-Night-18_20_null,NEXUS_5,1.0,en].png
deleted file mode 100644
index 08ca64ce83..0000000000
--- a/tests/uitests/src/test/snapshots/images/ui_S_t[l.textcomposer.mentions_MentionSpan_null_MentionSpan-Night-18_20_null,NEXUS_5,1.0,en].png
+++ /dev/null
@@ -1,3 +0,0 @@
-version https://git-lfs.github.com/spec/v1
-oid sha256:0464a6fc68efe26f6233d993a06024c88ec1936a108f33829e7b474042199fb6
-size 37110
diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[l.textcomposer.mentions_MentionSpan_null_MentionSpan-Night-20_22_null,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[l.textcomposer.mentions_MentionSpan_null_MentionSpan-Night-20_22_null,NEXUS_5,1.0,en].png
new file mode 100644
index 0000000000..f478f3d605
--- /dev/null
+++ b/tests/uitests/src/test/snapshots/images/ui_S_t[l.textcomposer.mentions_MentionSpan_null_MentionSpan-Night-20_22_null,NEXUS_5,1.0,en].png
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:1a03fbda4d8199f29ca78201e6e9ae38d17760332ef7b0ee12585819b3c92dc1
+size 33348
diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[l.textcomposer_MarkdownTextComposerEdit_null_MarkdownTextComposerEdit-Day-3_4_null,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[l.textcomposer_MarkdownTextComposerEdit_null_MarkdownTextComposerEdit-Day-3_4_null,NEXUS_5,1.0,en].png
new file mode 100644
index 0000000000..9f1159b500
--- /dev/null
+++ b/tests/uitests/src/test/snapshots/images/ui_S_t[l.textcomposer_MarkdownTextComposerEdit_null_MarkdownTextComposerEdit-Day-3_4_null,NEXUS_5,1.0,en].png
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:1eac95cd279b53be30c45f6ee959d617ca70f1cc1097fafe9cdcb58c76a3d72b
+size 14190
diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[l.textcomposer_MarkdownTextComposerEdit_null_MarkdownTextComposerEdit-Night-3_5_null,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[l.textcomposer_MarkdownTextComposerEdit_null_MarkdownTextComposerEdit-Night-3_5_null,NEXUS_5,1.0,en].png
new file mode 100644
index 0000000000..56df65158a
--- /dev/null
+++ b/tests/uitests/src/test/snapshots/images/ui_S_t[l.textcomposer_MarkdownTextComposerEdit_null_MarkdownTextComposerEdit-Night-3_5_null,NEXUS_5,1.0,en].png
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:d43d29a19b1639f9e569018abd0b3a77d34dac9eb374bff28fa8d673ede272ce
+size 13302
diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[l.textcomposer_TextComposerLinkDialogCreateLinkWithoutText_null_TextComposerLinkDialogCreateLinkWithoutText-Day-6_7_null,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[l.textcomposer_TextComposerLinkDialogCreateLinkWithoutText_null_TextComposerLinkDialogCreateLinkWithoutText-Day-7_8_null,NEXUS_5,1.0,en].png
similarity index 100%
rename from tests/uitests/src/test/snapshots/images/ui_S_t[l.textcomposer_TextComposerLinkDialogCreateLinkWithoutText_null_TextComposerLinkDialogCreateLinkWithoutText-Day-6_7_null,NEXUS_5,1.0,en].png
rename to tests/uitests/src/test/snapshots/images/ui_S_t[l.textcomposer_TextComposerLinkDialogCreateLinkWithoutText_null_TextComposerLinkDialogCreateLinkWithoutText-Day-7_8_null,NEXUS_5,1.0,en].png
diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[l.textcomposer_TextComposerLinkDialogCreateLinkWithoutText_null_TextComposerLinkDialogCreateLinkWithoutText-Night-6_8_null,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[l.textcomposer_TextComposerLinkDialogCreateLinkWithoutText_null_TextComposerLinkDialogCreateLinkWithoutText-Night-7_9_null,NEXUS_5,1.0,en].png
similarity index 100%
rename from tests/uitests/src/test/snapshots/images/ui_S_t[l.textcomposer_TextComposerLinkDialogCreateLinkWithoutText_null_TextComposerLinkDialogCreateLinkWithoutText-Night-6_8_null,NEXUS_5,1.0,en].png
rename to tests/uitests/src/test/snapshots/images/ui_S_t[l.textcomposer_TextComposerLinkDialogCreateLinkWithoutText_null_TextComposerLinkDialogCreateLinkWithoutText-Night-7_9_null,NEXUS_5,1.0,en].png
diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[l.textcomposer_TextComposerLinkDialogCreateLink_null_TextComposerLinkDialogCreateLink-Day-5_6_null,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[l.textcomposer_TextComposerLinkDialogCreateLink_null_TextComposerLinkDialogCreateLink-Day-6_7_null,NEXUS_5,1.0,en].png
similarity index 100%
rename from tests/uitests/src/test/snapshots/images/ui_S_t[l.textcomposer_TextComposerLinkDialogCreateLink_null_TextComposerLinkDialogCreateLink-Day-5_6_null,NEXUS_5,1.0,en].png
rename to tests/uitests/src/test/snapshots/images/ui_S_t[l.textcomposer_TextComposerLinkDialogCreateLink_null_TextComposerLinkDialogCreateLink-Day-6_7_null,NEXUS_5,1.0,en].png
diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[l.textcomposer_TextComposerLinkDialogCreateLink_null_TextComposerLinkDialogCreateLink-Night-5_7_null,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[l.textcomposer_TextComposerLinkDialogCreateLink_null_TextComposerLinkDialogCreateLink-Night-6_8_null,NEXUS_5,1.0,en].png
similarity index 100%
rename from tests/uitests/src/test/snapshots/images/ui_S_t[l.textcomposer_TextComposerLinkDialogCreateLink_null_TextComposerLinkDialogCreateLink-Night-5_7_null,NEXUS_5,1.0,en].png
rename to tests/uitests/src/test/snapshots/images/ui_S_t[l.textcomposer_TextComposerLinkDialogCreateLink_null_TextComposerLinkDialogCreateLink-Night-6_8_null,NEXUS_5,1.0,en].png
diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[l.textcomposer_TextComposerLinkDialogEditLink_null_TextComposerLinkDialogEditLink-Day-7_8_null,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[l.textcomposer_TextComposerLinkDialogEditLink_null_TextComposerLinkDialogEditLink-Day-8_9_null,NEXUS_5,1.0,en].png
similarity index 100%
rename from tests/uitests/src/test/snapshots/images/ui_S_t[l.textcomposer_TextComposerLinkDialogEditLink_null_TextComposerLinkDialogEditLink-Day-7_8_null,NEXUS_5,1.0,en].png
rename to tests/uitests/src/test/snapshots/images/ui_S_t[l.textcomposer_TextComposerLinkDialogEditLink_null_TextComposerLinkDialogEditLink-Day-8_9_null,NEXUS_5,1.0,en].png
diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[l.textcomposer_TextComposerLinkDialogEditLink_null_TextComposerLinkDialogEditLink-Night-7_9_null,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[l.textcomposer_TextComposerLinkDialogEditLink_null_TextComposerLinkDialogEditLink-Night-8_10_null,NEXUS_5,1.0,en].png
similarity index 100%
rename from tests/uitests/src/test/snapshots/images/ui_S_t[l.textcomposer_TextComposerLinkDialogEditLink_null_TextComposerLinkDialogEditLink-Night-7_9_null,NEXUS_5,1.0,en].png
rename to tests/uitests/src/test/snapshots/images/ui_S_t[l.textcomposer_TextComposerLinkDialogEditLink_null_TextComposerLinkDialogEditLink-Night-8_10_null,NEXUS_5,1.0,en].png
diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[l.textcomposer_TextComposerReply_null_TextComposerReply-Day-3_4_null,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[l.textcomposer_TextComposerReply_null_TextComposerReply-Day-4_5_null,NEXUS_5,1.0,en].png
similarity index 100%
rename from tests/uitests/src/test/snapshots/images/ui_S_t[l.textcomposer_TextComposerReply_null_TextComposerReply-Day-3_4_null,NEXUS_5,1.0,en].png
rename to tests/uitests/src/test/snapshots/images/ui_S_t[l.textcomposer_TextComposerReply_null_TextComposerReply-Day-4_5_null,NEXUS_5,1.0,en].png
diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[l.textcomposer_TextComposerReply_null_TextComposerReply-Night-3_5_null,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[l.textcomposer_TextComposerReply_null_TextComposerReply-Night-4_6_null,NEXUS_5,1.0,en].png
similarity index 100%
rename from tests/uitests/src/test/snapshots/images/ui_S_t[l.textcomposer_TextComposerReply_null_TextComposerReply-Night-3_5_null,NEXUS_5,1.0,en].png
rename to tests/uitests/src/test/snapshots/images/ui_S_t[l.textcomposer_TextComposerReply_null_TextComposerReply-Night-4_6_null,NEXUS_5,1.0,en].png
diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[l.textcomposer_TextComposerVoice_null_TextComposerVoice-Day-4_5_null,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[l.textcomposer_TextComposerVoice_null_TextComposerVoice-Day-5_6_null,NEXUS_5,1.0,en].png
similarity index 100%
rename from tests/uitests/src/test/snapshots/images/ui_S_t[l.textcomposer_TextComposerVoice_null_TextComposerVoice-Day-4_5_null,NEXUS_5,1.0,en].png
rename to tests/uitests/src/test/snapshots/images/ui_S_t[l.textcomposer_TextComposerVoice_null_TextComposerVoice-Day-5_6_null,NEXUS_5,1.0,en].png
diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[l.textcomposer_TextComposerVoice_null_TextComposerVoice-Night-4_6_null,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[l.textcomposer_TextComposerVoice_null_TextComposerVoice-Night-5_7_null,NEXUS_5,1.0,en].png
similarity index 100%
rename from tests/uitests/src/test/snapshots/images/ui_S_t[l.textcomposer_TextComposerVoice_null_TextComposerVoice-Night-4_6_null,NEXUS_5,1.0,en].png
rename to tests/uitests/src/test/snapshots/images/ui_S_t[l.textcomposer_TextComposerVoice_null_TextComposerVoice-Night-5_7_null,NEXUS_5,1.0,en].png