diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index 09ba964a0c..dba9677ae3 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -38,7 +38,7 @@ jobs:
distribution: 'temurin' # See 'Supported distributions' for available options
java-version: '17'
- name: Configure gradle
- uses: gradle/gradle-build-action@v2.12.0
+ uses: gradle/actions/setup-gradle@v3
with:
cache-read-only: ${{ github.ref != 'refs/heads/develop' }}
- name: Assemble debug APK
diff --git a/.github/workflows/fork-pr-notice.yml b/.github/workflows/fork-pr-notice.yml
index 42b1e54c3f..b11a81bfb1 100644
--- a/.github/workflows/fork-pr-notice.yml
+++ b/.github/workflows/fork-pr-notice.yml
@@ -11,7 +11,8 @@ jobs:
welcome:
runs-on: ubuntu-latest
name: Welcome comment
- if: github.event.pull_request.fork != null
+ # Only display it if base repo (upstream) is different from HEAD repo (possibly a fork)
+ if: github.event.pull_request.base.repo.full_name != github.event.pull_request.head.repo.full_name
steps:
- name: Add auto-generated commit warning
uses: actions/github-script@v7
diff --git a/.github/workflows/nightlyReports.yml b/.github/workflows/nightlyReports.yml
index 9b5a01a14e..8b429a4d13 100644
--- a/.github/workflows/nightlyReports.yml
+++ b/.github/workflows/nightlyReports.yml
@@ -62,7 +62,7 @@ jobs:
distribution: 'temurin' # See 'Supported distributions' for available options
java-version: '17'
- name: Configure gradle
- uses: gradle/gradle-build-action@v2.12.0
+ uses: gradle/actions/setup-gradle@v3
with:
cache-read-only: ${{ github.ref != 'refs/heads/develop' }}
- name: Dependency analysis
diff --git a/.github/workflows/quality.yml b/.github/workflows/quality.yml
index e1eb132ee7..73bee00499 100644
--- a/.github/workflows/quality.yml
+++ b/.github/workflows/quality.yml
@@ -40,7 +40,7 @@ jobs:
distribution: 'temurin' # See 'Supported distributions' for available options
java-version: '17'
- name: Configure gradle
- uses: gradle/gradle-build-action@v2.12.0
+ uses: gradle/actions/setup-gradle@v3
with:
cache-read-only: ${{ github.ref != 'refs/heads/develop' }}
- name: Run code quality check suite
diff --git a/.github/workflows/recordScreenshots.yml b/.github/workflows/recordScreenshots.yml
index 5024bea3af..a9293f006e 100644
--- a/.github/workflows/recordScreenshots.yml
+++ b/.github/workflows/recordScreenshots.yml
@@ -39,7 +39,7 @@ jobs:
java-version: '17'
# Add gradle cache, this should speed up the process
- name: Configure gradle
- uses: gradle/gradle-build-action@v2.12.0
+ uses: gradle/actions/setup-gradle@v3
with:
cache-read-only: ${{ github.ref != 'refs/heads/develop' }}
- name: Record screenshots
diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml
index bf672d8315..274214a98b 100644
--- a/.github/workflows/release.yml
+++ b/.github/workflows/release.yml
@@ -25,7 +25,7 @@ jobs:
distribution: 'temurin' # See 'Supported distributions' for available options
java-version: '17'
- name: Configure gradle
- uses: gradle/gradle-build-action@v2.12.0
+ uses: gradle/actions/setup-gradle@v3
- name: Create app bundle
env:
ELEMENT_ANDROID_MAPTILER_API_KEY: ${{ secrets.MAPTILER_KEY }}
diff --git a/.github/workflows/sonar.yml b/.github/workflows/sonar.yml
index 130eb573d4..ec1fa5eb8f 100644
--- a/.github/workflows/sonar.yml
+++ b/.github/workflows/sonar.yml
@@ -32,7 +32,7 @@ jobs:
distribution: 'temurin' # See 'Supported distributions' for available options
java-version: '17'
- name: Configure gradle
- uses: gradle/gradle-build-action@v2.12.0
+ uses: gradle/actions/setup-gradle@v3
with:
cache-read-only: ${{ github.ref != 'refs/heads/develop' }}
- name: 🔊 Publish results to Sonar
diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml
index 3cbda49612..bcbfac1d7f 100644
--- a/.github/workflows/tests.yml
+++ b/.github/workflows/tests.yml
@@ -44,7 +44,7 @@ jobs:
distribution: 'temurin' # See 'Supported distributions' for available options
java-version: '17'
- name: Configure gradle
- uses: gradle/gradle-build-action@v2.12.0
+ uses: gradle/actions/setup-gradle@v3
with:
cache-read-only: ${{ github.ref != 'refs/heads/develop' }}
@@ -81,6 +81,9 @@ jobs:
# https://github.com/codecov/codecov-action
- name: ☂️ Upload coverage reports to codecov
if: always()
- uses: codecov/codecov-action@v3
- # with:
- # files: build/reports/kover/xml/report.xml
+ uses: codecov/codecov-action@v4
+ with:
+ fail_ci_if_error: true
+ token: ${{ secrets.CODECOV_TOKEN }}
+# with:
+# files: build/reports/kover/xml/report.xml
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index 5cf10c0fdf..c65cd25105 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -31,7 +31,7 @@
Please read https://github.com/matrix-org/synapse/blob/master/CONTRIBUTING.md
-Element X Android support can be found in this room: [](https://matrix.to/#/#element-android:matrix.org).
+Element X Android support can be found in this room: [](https://matrix.to/#/#element-x-android:matrix.org).
The rest of the document contains specific rules for Matrix Android projects
diff --git a/README.md b/README.md
index 91da420f1a..77d76adc3e 100644
--- a/README.md
+++ b/README.md
@@ -3,7 +3,7 @@
[](https://sonarcloud.io/summary/new_code?id=vector-im_element-x-android)
[](https://sonarcloud.io/summary/new_code?id=vector-im_element-x-android)
[](https://codecov.io/github/vector-im/element-x-android)
-[](https://matrix.to/#/#element-x-android:matrix.org)
+[](https://matrix.to/#/#element-x-android:matrix.org)
[](https://localazy.com/p/element)
# Element X Android
diff --git a/app/src/main/kotlin/io/element/android/x/icon/IconPreview.kt b/app/src/main/kotlin/io/element/android/x/icon/IconPreview.kt
index 2effcd9f4c..ce8eb0eba7 100644
--- a/app/src/main/kotlin/io/element/android/x/icon/IconPreview.kt
+++ b/app/src/main/kotlin/io/element/android/x/icon/IconPreview.kt
@@ -35,10 +35,8 @@ import io.element.android.x.R
@Preview
@Composable
-internal fun IconPreview(
- modifier: Modifier = Modifier,
-) {
- Box(modifier = modifier) {
+internal fun IconPreview() {
+ Box {
Image(painter = painterResource(id = R.mipmap.ic_launcher_background), contentDescription = null)
Image(painter = painterResource(id = R.mipmap.ic_launcher_foreground), contentDescription = null)
}
@@ -46,10 +44,8 @@ internal fun IconPreview(
@Preview
@Composable
-internal fun RoundIconPreview(
- modifier: Modifier = Modifier,
-) {
- Box(modifier = modifier.clip(shape = CircleShape)) {
+internal fun RoundIconPreview() {
+ Box(modifier = Modifier.clip(shape = CircleShape)) {
Image(painter = painterResource(id = R.mipmap.ic_launcher_background), contentDescription = null)
Image(painter = painterResource(id = R.mipmap.ic_launcher_foreground), contentDescription = null)
}
@@ -57,11 +53,9 @@ internal fun RoundIconPreview(
@Preview
@Composable
-internal fun MonochromeIconPreview(
- modifier: Modifier = Modifier,
-) {
+internal fun MonochromeIconPreview() {
Box(
- modifier = modifier
+ modifier = Modifier
.size(108.dp)
.background(Color(0xFF2F3133))
.clip(shape = RoundedCornerShape(32.dp)),
diff --git a/appnav/src/main/kotlin/io/element/android/appnav/room/LoadingRoomNodeView.kt b/appnav/src/main/kotlin/io/element/android/appnav/room/LoadingRoomNodeView.kt
index 26d69cc213..8db8d608b2 100644
--- a/appnav/src/main/kotlin/io/element/android/appnav/room/LoadingRoomNodeView.kt
+++ b/appnav/src/main/kotlin/io/element/android/appnav/room/LoadingRoomNodeView.kt
@@ -84,10 +84,8 @@ fun LoadingRoomNodeView(
@Composable
private fun LoadingRoomTopBar(
onBackClicked: () -> Unit,
- modifier: Modifier = Modifier
) {
TopAppBar(
- modifier = modifier,
navigationIcon = {
BackButton(onClick = onBackClicked)
},
diff --git a/appnav/src/test/kotlin/io/element/android/appnav/RootPresenterTest.kt b/appnav/src/test/kotlin/io/element/android/appnav/RootPresenterTest.kt
index 5b382d1dc5..0806937c1a 100644
--- a/appnav/src/test/kotlin/io/element/android/appnav/RootPresenterTest.kt
+++ b/appnav/src/test/kotlin/io/element/android/appnav/RootPresenterTest.kt
@@ -28,6 +28,7 @@ import io.element.android.features.rageshake.test.crash.FakeCrashDataStore
import io.element.android.features.rageshake.test.rageshake.FakeRageShake
import io.element.android.features.rageshake.test.rageshake.FakeRageshakeDataStore
import io.element.android.features.rageshake.test.screenshot.FakeScreenshotHolder
+import io.element.android.libraries.matrix.test.core.aBuildMeta
import io.element.android.services.apperror.api.AppErrorState
import io.element.android.services.apperror.api.AppErrorStateService
import io.element.android.services.apperror.impl.DefaultAppErrorStateService
@@ -83,6 +84,7 @@ class RootPresenterTest {
val rageshake = FakeRageShake()
val screenshotHolder = FakeScreenshotHolder()
val crashDetectionPresenter = DefaultCrashDetectionPresenter(
+ buildMeta = aBuildMeta(),
crashDataStore = crashDataStore
)
val rageshakeDetectionPresenter = DefaultRageshakeDetectionPresenter(
diff --git a/changelog.d/+fix-message-forwarding-after-sdk-api-change.bugfix b/changelog.d/+fix-message-forwarding-after-sdk-api-change.bugfix
new file mode 100644
index 0000000000..76765d60ac
--- /dev/null
+++ b/changelog.d/+fix-message-forwarding-after-sdk-api-change.bugfix
@@ -0,0 +1 @@
+Fix message forwarding after SDK API change related to Timeline intitialization.
diff --git a/changelog.d/+remove-compose-foundation-workaround.misc b/changelog.d/+remove-compose-foundation-workaround.misc
new file mode 100644
index 0000000000..91bb19be2e
--- /dev/null
+++ b/changelog.d/+remove-compose-foundation-workaround.misc
@@ -0,0 +1 @@
+Remove Compose Foundation version pinning workaround. This was done to avoid a bug introduced in the default foundation version used by the material3 library, but that has already been fixed.
diff --git a/changelog.d/+remove-hidden-event-type-filter.misc b/changelog.d/+remove-hidden-event-type-filter.misc
new file mode 100644
index 0000000000..27c1d83bfa
--- /dev/null
+++ b/changelog.d/+remove-hidden-event-type-filter.misc
@@ -0,0 +1,2 @@
+Remove `FilterHiddenStateEventsProcessor`, as this is already handled by the Rust SDK.
+
diff --git a/changelog.d/+remove-session-preferences-on-logout.misc b/changelog.d/+remove-session-preferences-on-logout.misc
new file mode 100644
index 0000000000..6d6146d75f
--- /dev/null
+++ b/changelog.d/+remove-session-preferences-on-logout.misc
@@ -0,0 +1 @@
+Remove session preferences on user log out.
diff --git a/changelog.d/2241.feature b/changelog.d/2241.feature
new file mode 100644
index 0000000000..4d97eccc21
--- /dev/null
+++ b/changelog.d/2241.feature
@@ -0,0 +1,2 @@
+Change "Read receipts" advanced setting used to send private Read Receipt to "Share presence" settings.
+When disabled, private Read Receipts will be sent, and no typing notification will be sent. Also Read Receipts and typing notifications will not be rendered in the timeline.
diff --git a/changelog.d/2242.feature b/changelog.d/2242.feature
new file mode 100644
index 0000000000..947661653f
--- /dev/null
+++ b/changelog.d/2242.feature
@@ -0,0 +1 @@
+Rendering typing notification
diff --git a/changelog.d/2261.feature b/changelog.d/2261.feature
new file mode 100644
index 0000000000..c643cdf43a
--- /dev/null
+++ b/changelog.d/2261.feature
@@ -0,0 +1 @@
+Manually mark a room as unread
diff --git a/changelog.d/2304.bugfix b/changelog.d/2304.bugfix
new file mode 100644
index 0000000000..5f0c485ddd
--- /dev/null
+++ b/changelog.d/2304.bugfix
@@ -0,0 +1 @@
+Fix crash after unregistering UnifiedPush distributor
diff --git a/changelog.d/2310.misc b/changelog.d/2310.misc
new file mode 100644
index 0000000000..b5106ad927
--- /dev/null
+++ b/changelog.d/2310.misc
@@ -0,0 +1 @@
+Move migration screen to within the room list
diff --git a/changelog.d/2330.feature b/changelog.d/2330.feature
new file mode 100644
index 0000000000..c501ded646
--- /dev/null
+++ b/changelog.d/2330.feature
@@ -0,0 +1 @@
+Add empty state to the room list.
diff --git a/changelog.d/2333.feature b/changelog.d/2333.feature
new file mode 100644
index 0000000000..5bde0d6734
--- /dev/null
+++ b/changelog.d/2333.feature
@@ -0,0 +1 @@
+Allow joining unencrypted video calls in non encrypted rooms.
diff --git a/changelog.d/825.misc b/changelog.d/825.misc
new file mode 100644
index 0000000000..a715b61217
--- /dev/null
+++ b/changelog.d/825.misc
@@ -0,0 +1 @@
+Adjusted the login flow buttons so the continue button is always at the same height
diff --git a/features/analytics/api/src/main/res/values-be/translations.xml b/features/analytics/api/src/main/res/values-be/translations.xml
new file mode 100644
index 0000000000..34f69b49b4
--- /dev/null
+++ b/features/analytics/api/src/main/res/values-be/translations.xml
@@ -0,0 +1,7 @@
+
+
+ "Дзяліцеся дадзенымі аналітыкі"
+ "Даваць ананімныя дадзеныя аб выкарыстанні, каб дапамагчы нам выявіць праблемы."
+ "Вы можаце азнаёміцца з усімі нашымі ўмовамі %1$s."
+ "тут"
+
diff --git a/features/analytics/impl/src/main/kotlin/io/element/android/features/analytics/impl/AnalyticsOptInView.kt b/features/analytics/impl/src/main/kotlin/io/element/android/features/analytics/impl/AnalyticsOptInView.kt
index 9f75d4bd6e..cf8700b684 100644
--- a/features/analytics/impl/src/main/kotlin/io/element/android/features/analytics/impl/AnalyticsOptInView.kt
+++ b/features/analytics/impl/src/main/kotlin/io/element/android/features/analytics/impl/AnalyticsOptInView.kt
@@ -57,7 +57,6 @@ import io.element.android.libraries.designsystem.theme.components.ButtonSize
import io.element.android.libraries.designsystem.theme.components.Icon
import io.element.android.libraries.designsystem.theme.components.TextButton
import io.element.android.libraries.designsystem.theme.temporaryColorBgSpecial
-import io.element.android.libraries.designsystem.utils.LogCompositions
import io.element.android.libraries.ui.strings.CommonStrings
import kotlinx.collections.immutable.persistentListOf
@@ -67,7 +66,6 @@ fun AnalyticsOptInView(
onClickTerms: () -> Unit,
modifier: Modifier = Modifier,
) {
- LogCompositions(tag = "Analytics", msg = "Root")
val eventSink = state.eventSink
fun onTermsAccepted() {
@@ -101,10 +99,8 @@ private const val LINK_TAG = "link"
private fun AnalyticsOptInHeader(
state: AnalyticsOptInState,
onClickTerms: () -> Unit,
- modifier: Modifier = Modifier,
) {
Column(
- modifier = modifier,
horizontalAlignment = Alignment.CenterHorizontally,
) {
IconTitleSubtitleMolecule(
@@ -141,9 +137,9 @@ private fun AnalyticsOptInHeader(
}
@Composable
-private fun CheckIcon(modifier: Modifier = Modifier) {
+private fun CheckIcon() {
Icon(
- modifier = modifier
+ modifier = Modifier
.size(20.dp)
.background(color = MaterialTheme.colorScheme.background, shape = CircleShape)
.padding(2.dp),
@@ -154,11 +150,9 @@ private fun CheckIcon(modifier: Modifier = Modifier) {
}
@Composable
-private fun AnalyticsOptInContent(
- modifier: Modifier = Modifier,
-) {
+private fun AnalyticsOptInContent() {
Box(
- modifier = modifier.fillMaxSize(),
+ modifier = Modifier.fillMaxSize(),
contentAlignment = BiasAlignment(
horizontalBias = 0f,
verticalBias = -0.4f
@@ -190,11 +184,8 @@ private fun AnalyticsOptInContent(
private fun AnalyticsOptInFooter(
onTermsAccepted: () -> Unit,
onTermsDeclined: () -> Unit,
- modifier: Modifier = Modifier,
) {
- ButtonColumnMolecule(
- modifier = modifier,
- ) {
+ ButtonColumnMolecule {
Button(
text = stringResource(id = CommonStrings.action_ok),
onClick = onTermsAccepted,
diff --git a/features/analytics/impl/src/main/res/values-be/translations.xml b/features/analytics/impl/src/main/res/values-be/translations.xml
new file mode 100644
index 0000000000..6d322781c3
--- /dev/null
+++ b/features/analytics/impl/src/main/res/values-be/translations.xml
@@ -0,0 +1,10 @@
+
+
+ "Мы не будзем запісваць або прафіляваць любыя асабістыя даныя"
+ "Даваць ананімныя дадзеныя аб выкарыстанні, каб дапамагчы нам выявіць праблемы."
+ "Вы можаце азнаёміцца з усімі нашымі ўмовамі %1$s."
+ "тут"
+ "Вы можаце адключыць гэта ў любы час"
+ "Мы не будзем перадаваць вашыя дадзеныя трэцім асобам"
+ "Дапамажыце палепшыць %1$s"
+
diff --git a/features/call/src/main/kotlin/io/element/android/features/call/utils/DefaultCallWidgetProvider.kt b/features/call/src/main/kotlin/io/element/android/features/call/utils/DefaultCallWidgetProvider.kt
index cc6e2a299f..7fb6d3cb48 100644
--- a/features/call/src/main/kotlin/io/element/android/features/call/utils/DefaultCallWidgetProvider.kt
+++ b/features/call/src/main/kotlin/io/element/android/features/call/utils/DefaultCallWidgetProvider.kt
@@ -43,7 +43,7 @@ class DefaultCallWidgetProvider @Inject constructor(
): Result> = runCatching {
val room = matrixClientsProvider.getOrRestore(sessionId).getOrThrow().getRoom(roomId) ?: error("Room not found")
val baseUrl = appPreferencesStore.getCustomElementCallBaseUrlFlow().firstOrNull() ?: ElementCallConfig.DEFAULT_BASE_URL
- val widgetSettings = callWidgetSettingsProvider.provide(baseUrl)
+ val widgetSettings = callWidgetSettingsProvider.provide(baseUrl, encrypted = room.isEncrypted)
val callUrl = room.generateWidgetWebViewUrl(widgetSettings, clientId, languageTag, theme).getOrThrow()
room.getWidgetDriver(widgetSettings).getOrThrow() to callUrl
}
diff --git a/features/call/src/main/res/values-be/translations.xml b/features/call/src/main/res/values-be/translations.xml
new file mode 100644
index 0000000000..8355f3af9b
--- /dev/null
+++ b/features/call/src/main/res/values-be/translations.xml
@@ -0,0 +1,6 @@
+
+
+ "Бягучы выклік"
+ "Націсніце, каб вярнуцца да выкліка"
+ "☎️ Выконваецца выклік"
+
diff --git a/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/addpeople/AddPeopleView.kt b/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/addpeople/AddPeopleView.kt
index 147020fddb..788e6b64ee 100644
--- a/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/addpeople/AddPeopleView.kt
+++ b/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/addpeople/AddPeopleView.kt
@@ -88,10 +88,8 @@ private fun AddPeopleViewTopBar(
hasSelectedUsers: Boolean,
onBackPressed: () -> Unit,
onNextPressed: () -> Unit,
- modifier: Modifier = Modifier,
) {
TopAppBar(
- modifier = modifier,
title = {
Text(
text = stringResource(id = R.string.screen_create_room_add_people_title),
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 c3887ecba6..2f1c55adc7 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
@@ -18,7 +18,6 @@ package io.element.android.features.createroom.impl.configureroom
import android.net.Uri
import androidx.compose.foundation.clickable
-import androidx.compose.foundation.gestures.detectTapGestures
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.PaddingValues
@@ -38,8 +37,6 @@ import androidx.compose.runtime.Composable
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
-import androidx.compose.ui.focus.FocusManager
-import androidx.compose.ui.input.pointer.pointerInput
import androidx.compose.ui.platform.LocalFocusManager
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.input.KeyboardCapitalization
@@ -52,6 +49,7 @@ import io.element.android.libraries.designsystem.components.LabelledTextField
import io.element.android.libraries.designsystem.components.async.AsyncActionView
import io.element.android.libraries.designsystem.components.async.AsyncActionViewDefaults
import io.element.android.libraries.designsystem.components.button.BackButton
+import io.element.android.libraries.designsystem.modifiers.clearFocusOnTap
import io.element.android.libraries.designsystem.preview.ElementPreview
import io.element.android.libraries.designsystem.preview.PreviewsDayNight
import io.element.android.libraries.designsystem.theme.aliasScreenTitle
@@ -173,10 +171,8 @@ private fun ConfigureRoomToolbar(
isNextActionEnabled: Boolean,
onBackPressed: () -> Unit,
onNextPressed: () -> Unit,
- modifier: Modifier = Modifier,
) {
TopAppBar(
- modifier = modifier,
title = {
Text(
text = stringResource(R.string.screen_create_room_title),
@@ -259,13 +255,6 @@ private fun RoomPrivacyOptions(
}
}
-private fun Modifier.clearFocusOnTap(focusManager: FocusManager): Modifier =
- pointerInput(Unit) {
- detectTapGestures(onTap = {
- focusManager.clearFocus()
- })
- }
-
@PreviewsDayNight
@Composable
internal fun ConfigureRoomViewPreview(@PreviewParameter(ConfigureRoomStateProvider::class) state: ConfigureRoomState) = ElementPreview {
diff --git a/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/root/CreateRoomRootView.kt b/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/root/CreateRoomRootView.kt
index 24b1145e2e..77b54644dd 100644
--- a/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/root/CreateRoomRootView.kt
+++ b/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/root/CreateRoomRootView.kt
@@ -117,10 +117,8 @@ fun CreateRoomRootView(
@Composable
private fun CreateRoomRootViewTopBar(
onClosePressed: () -> Unit,
- modifier: Modifier = Modifier,
) {
TopAppBar(
- modifier = modifier,
title = {
Text(
text = stringResource(id = CommonStrings.action_start_chat),
@@ -141,9 +139,8 @@ private fun CreateRoomActionButtonsList(
state: CreateRoomRootState,
onNewRoomClicked: () -> Unit,
onInvitePeopleClicked: () -> Unit,
- modifier: Modifier = Modifier,
) {
- Column(modifier = modifier) {
+ Column {
CreateRoomActionButton(
iconRes = CompoundDrawables.ic_plus,
text = stringResource(id = R.string.screen_create_room_action_create_room),
@@ -162,10 +159,9 @@ private fun CreateRoomActionButton(
@DrawableRes iconRes: Int,
text: String,
onClick: () -> Unit,
- modifier: Modifier = Modifier,
) {
Row(
- modifier = modifier
+ modifier = Modifier
.fillMaxWidth()
.height(56.dp)
.clickable { onClick() }
diff --git a/features/createroom/impl/src/main/res/values-be/translations.xml b/features/createroom/impl/src/main/res/values-be/translations.xml
new file mode 100644
index 0000000000..d838edaa3a
--- /dev/null
+++ b/features/createroom/impl/src/main/res/values-be/translations.xml
@@ -0,0 +1,15 @@
+
+
+ "Новы пакой"
+ "Запрасіце сяброў у Element"
+ "Запрасіць людзей"
+ "Пры стварэнні пакоя адбылася памылка"
+ "Паведамленні ў гэтым пакоі зашыфраваны. Гэта шыфраванне нельга адключыць."
+ "Прыватны пакой (толькі па запрашэнні)"
+ "Паведамленні не зашыфраваны, і кожны можа іх прачытаць. Вы можаце ўключыць шыфраванне пазней."
+ "Адкрыты пакой (для ўсіх)"
+ "Тэма (неабавязкова)"
+ "Пры спробе пачаць чат адбылася памылка"
+ "Назва пакоя"
+ "Стварыце пакой"
+
diff --git a/features/createroom/impl/src/main/res/values-cs/translations.xml b/features/createroom/impl/src/main/res/values-cs/translations.xml
index febd535cb0..7131c871f7 100644
--- a/features/createroom/impl/src/main/res/values-cs/translations.xml
+++ b/features/createroom/impl/src/main/res/values-cs/translations.xml
@@ -8,8 +8,8 @@
"Soukromá místnost (jen pro pozvané)"
"Zprávy nejsou šifrované a může si je přečíst kdokoli. Šifrování můžete povolit později."
"Veřejná místnost (kdokoli)"
- "Název místnosti"
"Téma (nepovinné)"
"Při pokusu o zahájení chatu došlo k chybě"
+ "Název místnosti"
"Vytvořit místnost"
diff --git a/features/createroom/impl/src/main/res/values-de/translations.xml b/features/createroom/impl/src/main/res/values-de/translations.xml
index 59ebe82ff1..94a4baccba 100644
--- a/features/createroom/impl/src/main/res/values-de/translations.xml
+++ b/features/createroom/impl/src/main/res/values-de/translations.xml
@@ -8,8 +8,8 @@
"Privater Raum (nur auf Einladung)"
"Die Nachrichten sind nicht verschlüsselt und können von jedem gelesen werden. Die Verschlüsselung kann zu einem späteren Zeitpunkt aktiviert werden."
"Öffentlicher Raum (für alle)"
- "Raumname"
"Thema (optional)"
"Beim Versuch, einen Chat zu starten, ist ein Fehler aufgetreten"
+ "Raumname"
"Raum erstellen"
diff --git a/features/createroom/impl/src/main/res/values-es/translations.xml b/features/createroom/impl/src/main/res/values-es/translations.xml
index 1c4c687d31..c5bae8be29 100644
--- a/features/createroom/impl/src/main/res/values-es/translations.xml
+++ b/features/createroom/impl/src/main/res/values-es/translations.xml
@@ -8,8 +8,8 @@
"Sala privada (sólo con invitación)"
"Los mensajes no están cifrados y cualquiera puede leerlos. Puedes activar la encriptación más adelante."
"Sala pública (cualquiera)"
- "Nombre de la sala"
"Tema (opcional)"
"Se ha producido un error al intentar iniciar un chat"
+ "Nombre de la sala"
"Crear una sala"
diff --git a/features/createroom/impl/src/main/res/values-fr/translations.xml b/features/createroom/impl/src/main/res/values-fr/translations.xml
index e060b99ed8..d584410e8a 100644
--- a/features/createroom/impl/src/main/res/values-fr/translations.xml
+++ b/features/createroom/impl/src/main/res/values-fr/translations.xml
@@ -8,8 +8,8 @@
"Salon privé (sur invitation seulement)"
"Les messages ne sont pas chiffrés et n’importe qui peut les lire. Vous pouvez activer le chiffrement ultérieurement."
"Salon public (tout le monde)"
- "Nom du salon"
"Sujet (facultatif)"
"Une erreur s’est produite lors de la tentative de création de la discussion"
+ "Nom du salon"
"Créer un salon"
diff --git a/features/createroom/impl/src/main/res/values-hu/translations.xml b/features/createroom/impl/src/main/res/values-hu/translations.xml
index 29a403a091..68af83d977 100644
--- a/features/createroom/impl/src/main/res/values-hu/translations.xml
+++ b/features/createroom/impl/src/main/res/values-hu/translations.xml
@@ -8,8 +8,8 @@
"Privát szoba (csak meghívással)"
"Az üzenetek nincsenek titkosítva, és bárki elolvashatja őket. A titkosítást később is engedélyezheti."
"Nyilvános szoba (bárki)"
- "Szoba neve"
"Téma (nem kötelező)"
"Hiba történt a csevegés indításakor"
+ "Szoba neve"
"Szoba létrehozása"
diff --git a/features/createroom/impl/src/main/res/values-in/translations.xml b/features/createroom/impl/src/main/res/values-in/translations.xml
index 775eef7fda..421362fff3 100644
--- a/features/createroom/impl/src/main/res/values-in/translations.xml
+++ b/features/createroom/impl/src/main/res/values-in/translations.xml
@@ -8,8 +8,8 @@
"Ruangan pribadi (hanya undangan)"
"Pesan tidak dienkripsi dan siapa pun dapat membacanya. Anda dapat mengaktifkan enkripsi di kemudian hari."
"Ruang publik (siapa saja)"
- "Nama ruangan"
"Topik (opsional)"
"Terjadi kesalahan saat mencoba memulai obrolan"
+ "Nama ruangan"
"Buat ruangan"
diff --git a/features/createroom/impl/src/main/res/values-it/translations.xml b/features/createroom/impl/src/main/res/values-it/translations.xml
index 836cff3452..00793c2bd1 100644
--- a/features/createroom/impl/src/main/res/values-it/translations.xml
+++ b/features/createroom/impl/src/main/res/values-it/translations.xml
@@ -8,8 +8,8 @@
"Stanza privata (solo su invito)"
"I messaggi non sono cifrati e chiunque può leggerli. Puoi attivare la crittografia in un secondo momento."
"Stanza pubblica (chiunque)"
- "Nome stanza"
"Argomento (facoltativo)"
"Si è verificato un errore durante il tentativo di avviare una chat"
+ "Nome stanza"
"Crea una stanza"
diff --git a/features/createroom/impl/src/main/res/values-ro/translations.xml b/features/createroom/impl/src/main/res/values-ro/translations.xml
index 9f68a006e5..ad97c81fbc 100644
--- a/features/createroom/impl/src/main/res/values-ro/translations.xml
+++ b/features/createroom/impl/src/main/res/values-ro/translations.xml
@@ -8,8 +8,8 @@
"Cameră privată (doar pe bază de invitație)"
"Mesajele nu sunt criptate și oricine le poate citi. Puteți activa criptarea la o dată ulterioară."
"Cameră publică (oricine)"
- "Numele camerei"
"Subiect (opțional)"
"A apărut o eroare la încercarea începerii conversației"
+ "Numele camerei"
"Creați o cameră"
diff --git a/features/createroom/impl/src/main/res/values-ru/translations.xml b/features/createroom/impl/src/main/res/values-ru/translations.xml
index 1557931e85..ce16a9fab3 100644
--- a/features/createroom/impl/src/main/res/values-ru/translations.xml
+++ b/features/createroom/impl/src/main/res/values-ru/translations.xml
@@ -8,8 +8,8 @@
"Приватная комната (только по приглашению)"
"Сообщения не зашифрованы, каждый может их прочитать. Вы можете включить шифрование позже."
"Публичная комната (любой)"
- "Название комнаты"
"Тема (необязательно)"
"Произошла ошибка при попытке открытия комнаты"
+ "Название комнаты"
"Создать комнату"
diff --git a/features/createroom/impl/src/main/res/values-sk/translations.xml b/features/createroom/impl/src/main/res/values-sk/translations.xml
index 15fa779609..730297c17c 100644
--- a/features/createroom/impl/src/main/res/values-sk/translations.xml
+++ b/features/createroom/impl/src/main/res/values-sk/translations.xml
@@ -8,8 +8,8 @@
"Súkromná miestnosť (len pre pozvaných)"
"Správy nie sú šifrované a môže si ich prečítať ktokoľvek. Šifrovanie môžete zapnúť neskôr."
"Verejná miestnosť (ktokoľvek)"
- "Názov miestnosti"
"Téma (voliteľné)"
"Pri pokuse o spustenie konverzácie sa vyskytla chyba"
+ "Názov miestnosti"
"Vytvoriť miestnosť"
diff --git a/features/createroom/impl/src/main/res/values-zh-rTW/translations.xml b/features/createroom/impl/src/main/res/values-zh-rTW/translations.xml
index a078802c36..226bd4eb93 100644
--- a/features/createroom/impl/src/main/res/values-zh-rTW/translations.xml
+++ b/features/createroom/impl/src/main/res/values-zh-rTW/translations.xml
@@ -8,7 +8,7 @@
"私密聊天室(僅限邀請)"
"訊息未加密,任何人都可以查看。您可以在之後啟用加密功能。"
"公開聊天室(任何人)"
- "聊天室名稱"
"主題(非必填)"
+ "聊天室名稱"
"建立聊天室"
diff --git a/features/createroom/impl/src/main/res/values/localazy.xml b/features/createroom/impl/src/main/res/values/localazy.xml
index eadcf49f34..e3607275f2 100644
--- a/features/createroom/impl/src/main/res/values/localazy.xml
+++ b/features/createroom/impl/src/main/res/values/localazy.xml
@@ -8,8 +8,8 @@
"Private room (invite only)"
"Messages are not encrypted and anyone can read them. You can enable encryption at a later date."
"Public room (anyone)"
- "Room name"
"Topic (optional)"
"An error occurred when trying to start a chat"
+ "Room name"
"Create a room"
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 5840671b6f..983e0c8db2 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
@@ -33,7 +33,6 @@ import dagger.assisted.AssistedInject
import io.element.android.anvilannotations.ContributesNode
import io.element.android.features.analytics.api.AnalyticsEntryPoint
import io.element.android.features.ftue.api.FtueEntryPoint
-import io.element.android.features.ftue.impl.migration.MigrationScreenNode
import io.element.android.features.ftue.impl.notifications.NotificationsOptInNode
import io.element.android.features.ftue.impl.state.DefaultFtueState
import io.element.android.features.ftue.impl.state.FtueStep
@@ -74,9 +73,6 @@ class FtueFlowNode @AssistedInject constructor(
@Parcelize
data object Placeholder : NavTarget
- @Parcelize
- data object MigrationScreen : NavTarget
-
@Parcelize
data object WelcomeScreen : NavTarget
@@ -114,14 +110,6 @@ class FtueFlowNode @AssistedInject constructor(
NavTarget.Placeholder -> {
createNode(buildContext)
}
- NavTarget.MigrationScreen -> {
- val callback = object : MigrationScreenNode.Callback {
- override fun onMigrationFinished() {
- lifecycleScope.launch { moveToNextStep() }
- }
- }
- createNode(buildContext, listOf(callback))
- }
NavTarget.WelcomeScreen -> {
val callback = object : WelcomeNode.Callback {
override fun onContinueClicked() {
@@ -158,9 +146,6 @@ class FtueFlowNode @AssistedInject constructor(
private fun moveToNextStep() {
when (ftueState.getNextStep()) {
- FtueStep.MigrationScreen -> {
- backstack.newRoot(NavTarget.MigrationScreen)
- }
FtueStep.WelcomeScreen -> {
backstack.newRoot(NavTarget.WelcomeScreen)
}
diff --git a/features/ftue/impl/src/main/kotlin/io/element/android/features/ftue/impl/migration/MigrationScreenNode.kt b/features/ftue/impl/src/main/kotlin/io/element/android/features/ftue/impl/migration/MigrationScreenNode.kt
deleted file mode 100644
index 7c4257c422..0000000000
--- a/features/ftue/impl/src/main/kotlin/io/element/android/features/ftue/impl/migration/MigrationScreenNode.kt
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * Copyright (c) 2023 New Vector Ltd
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package io.element.android.features.ftue.impl.migration
-
-import androidx.compose.runtime.Composable
-import androidx.compose.ui.Modifier
-import com.bumble.appyx.core.modality.BuildContext
-import com.bumble.appyx.core.node.Node
-import com.bumble.appyx.core.plugin.Plugin
-import dagger.assisted.Assisted
-import dagger.assisted.AssistedInject
-import io.element.android.anvilannotations.ContributesNode
-import io.element.android.libraries.di.SessionScope
-
-@ContributesNode(SessionScope::class)
-class MigrationScreenNode @AssistedInject constructor(
- @Assisted buildContext: BuildContext,
- @Assisted plugins: List,
- private val presenter: MigrationScreenPresenter,
-) : Node(buildContext, plugins = plugins) {
- interface Callback : Plugin {
- fun onMigrationFinished()
- }
-
- private fun onMigrationFinished() {
- plugins.filterIsInstance().forEach { it.onMigrationFinished() }
- }
-
- @Composable
- override fun View(modifier: Modifier) {
- val state = presenter.present()
- MigrationScreenView(
- state,
- onMigrationFinished = ::onMigrationFinished,
- modifier = modifier
- )
- }
-}
diff --git a/features/ftue/impl/src/main/kotlin/io/element/android/features/ftue/impl/notifications/NotificationsOptInView.kt b/features/ftue/impl/src/main/kotlin/io/element/android/features/ftue/impl/notifications/NotificationsOptInView.kt
index 616e6aa809..c617d684e4 100644
--- a/features/ftue/impl/src/main/kotlin/io/element/android/features/ftue/impl/notifications/NotificationsOptInView.kt
+++ b/features/ftue/impl/src/main/kotlin/io/element/android/features/ftue/impl/notifications/NotificationsOptInView.kt
@@ -67,7 +67,7 @@ fun NotificationsOptInView(
header = { NotificationsOptInHeader(modifier = Modifier.padding(top = 60.dp, bottom = 12.dp)) },
footer = { NotificationsOptInFooter(state) },
) {
- NotificationsOptInContent(modifier = Modifier.fillMaxWidth())
+ NotificationsOptInContent()
}
}
@@ -104,10 +104,8 @@ private fun NotificationsOptInFooter(state: NotificationsOptInState) {
}
@Composable
-private fun NotificationsOptInContent(
- modifier: Modifier = Modifier,
-) {
- Box(modifier = modifier.fillMaxSize(), contentAlignment = Alignment.Center) {
+private fun NotificationsOptInContent() {
+ Box(modifier = Modifier.fillMaxSize(), contentAlignment = Alignment.Center) {
Column(
verticalArrangement = Arrangement.spacedBy(
16.dp,
@@ -144,10 +142,8 @@ private fun NotificationRow(
avatarColorsId: String,
firstRowPercent: Float,
secondRowPercent: Float,
- modifier: Modifier = Modifier
) {
Surface(
- modifier = modifier,
color = ElementTheme.colors.bgCanvasDisabled,
shape = RoundedCornerShape(14.dp),
shadowElevation = 2.dp,
diff --git a/features/ftue/impl/src/main/kotlin/io/element/android/features/ftue/impl/state/DefaultFtueState.kt b/features/ftue/impl/src/main/kotlin/io/element/android/features/ftue/impl/state/DefaultFtueState.kt
index 212919a691..ce7a769187 100644
--- a/features/ftue/impl/src/main/kotlin/io/element/android/features/ftue/impl/state/DefaultFtueState.kt
+++ b/features/ftue/impl/src/main/kotlin/io/element/android/features/ftue/impl/state/DefaultFtueState.kt
@@ -21,11 +21,9 @@ import android.os.Build
import androidx.annotation.VisibleForTesting
import com.squareup.anvil.annotations.ContributesBinding
import io.element.android.features.ftue.api.state.FtueState
-import io.element.android.features.ftue.impl.migration.MigrationScreenStore
import io.element.android.features.ftue.impl.welcome.state.WelcomeScreenState
import io.element.android.features.lockscreen.api.LockScreenService
import io.element.android.libraries.di.SessionScope
-import io.element.android.libraries.matrix.api.MatrixClient
import io.element.android.libraries.permissions.api.PermissionStateProvider
import io.element.android.services.analytics.api.AnalyticsService
import io.element.android.services.toolbox.api.sdk.BuildVersionSdkIntProvider
@@ -43,17 +41,14 @@ class DefaultFtueState @Inject constructor(
coroutineScope: CoroutineScope,
private val analyticsService: AnalyticsService,
private val welcomeScreenState: WelcomeScreenState,
- private val migrationScreenStore: MigrationScreenStore,
private val permissionStateProvider: PermissionStateProvider,
private val lockScreenService: LockScreenService,
- private val matrixClient: MatrixClient,
) : FtueState {
override val shouldDisplayFlow = MutableStateFlow(isAnyStepIncomplete())
override suspend fun reset() {
welcomeScreenState.reset()
analyticsService.reset()
- migrationScreenStore.reset()
if (sdkVersionProvider.isAtLeast(Build.VERSION_CODES.TIRAMISU)) {
permissionStateProvider.resetPermission(Manifest.permission.POST_NOTIFICATIONS)
}
@@ -67,12 +62,7 @@ class DefaultFtueState @Inject constructor(
fun getNextStep(currentStep: FtueStep? = null): FtueStep? =
when (currentStep) {
- null -> if (shouldDisplayMigrationScreen()) {
- FtueStep.MigrationScreen
- } else {
- getNextStep(FtueStep.MigrationScreen)
- }
- FtueStep.MigrationScreen -> if (shouldDisplayWelcomeScreen()) {
+ null -> if (shouldDisplayWelcomeScreen()) {
FtueStep.WelcomeScreen
} else {
getNextStep(FtueStep.WelcomeScreen)
@@ -97,7 +87,6 @@ class DefaultFtueState @Inject constructor(
private fun isAnyStepIncomplete(): Boolean {
return listOf(
- { shouldDisplayMigrationScreen() },
{ shouldDisplayWelcomeScreen() },
{ shouldAskNotificationPermissions() },
{ needsAnalyticsOptIn() },
@@ -105,10 +94,6 @@ class DefaultFtueState @Inject constructor(
).any { it() }
}
- private fun shouldDisplayMigrationScreen(): Boolean {
- return migrationScreenStore.isMigrationScreenNeeded(matrixClient.sessionId)
- }
-
private fun needsAnalyticsOptIn(): Boolean {
// We need this function to not be suspend, so we need to load the value through runBlocking
return runBlocking { analyticsService.didAskUserConsent().first().not() }
@@ -147,7 +132,6 @@ class DefaultFtueState @Inject constructor(
}
sealed interface FtueStep {
- data object MigrationScreen : FtueStep
data object WelcomeScreen : FtueStep
data object NotificationsOptIn : FtueStep
data object AnalyticsOptIn : FtueStep
diff --git a/features/ftue/impl/src/main/res/values-be/translations.xml b/features/ftue/impl/src/main/res/values-be/translations.xml
new file mode 100644
index 0000000000..413bad9132
--- /dev/null
+++ b/features/ftue/impl/src/main/res/values-be/translations.xml
@@ -0,0 +1,11 @@
+
+
+ "Вы можаце змяніць налады пазней."
+ "Дазвольце апавяшчэнні і ніколі не прапускайце іх"
+ "Званкі, апытанні, пошук і многае іншае будзе дададзена пазней у гэтым годзе."
+ "Гісторыя паведамленняў для зашыфраваных пакояў пакуль недаступна."
+ "Мы будзем рады пачуць вашае меркаванне, паведаміце нам аб гэтым праз старонку налад."
+ "Пачнём!"
+ "Вось што вам трэба ведаць:"
+ "Вітаем у %1$s!"
+
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 9363c704ad..bc262cf2b4 100644
--- a/features/ftue/impl/src/main/res/values-cs/translations.xml
+++ b/features/ftue/impl/src/main/res/values-cs/translations.xml
@@ -1,7 +1,5 @@
- "Jedná se o jednorázový proces, prosíme o strpení."
- "Nastavení vašeho účtu"
"Nastavení můžete později změnit."
"Povolte oznámení a nezmeškejte žádnou zprávu"
"Hovory, hlasování, vyhledávání a další budou přidány koncem tohoto roku."
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 d2a71e98e5..151500adda 100644
--- a/features/ftue/impl/src/main/res/values-de/translations.xml
+++ b/features/ftue/impl/src/main/res/values-de/translations.xml
@@ -1,7 +1,5 @@
- "Dies ist ein einmaliger Vorgang, danke fürs Warten."
- "Dein Konto wird eingerichtet."
"Du kannst deine Einstellungen später ändern."
"Erlaube Benachrichtigungen und verpasse keine Nachricht"
"Anrufe, Umfragen, Suchfunktionen und mehr werden im Laufe des Jahres hinzugefügt."
diff --git a/features/ftue/impl/src/main/res/values-es/translations.xml b/features/ftue/impl/src/main/res/values-es/translations.xml
index b5bac7f6a1..6a3224c531 100644
--- a/features/ftue/impl/src/main/res/values-es/translations.xml
+++ b/features/ftue/impl/src/main/res/values-es/translations.xml
@@ -1,7 +1,5 @@
- "Este proceso solo se hace una vez, gracias por esperar."
- "Configura tu cuenta"
"Puedes cambiar la configuración más tarde."
"Activa las notificaciones y nunca te pierdas un mensaje"
"Las llamadas, las encuestas, la búsqueda y más se agregarán más adelante este año."
diff --git a/features/ftue/impl/src/main/res/values-fr/translations.xml b/features/ftue/impl/src/main/res/values-fr/translations.xml
index 864a887f20..9fc11413cb 100644
--- a/features/ftue/impl/src/main/res/values-fr/translations.xml
+++ b/features/ftue/impl/src/main/res/values-fr/translations.xml
@@ -1,7 +1,5 @@
- "Il s’agit d’une opération ponctuelle, merci d’attendre quelques instants."
- "Configuration de votre compte."
"Vous pourrez modifier vos paramètres ultérieurement."
"Autorisez les notifications et ne manquez aucun message"
"Les appels, les sondages, les recherches et plus encore seront ajoutés plus tard cette année."
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 6585aaf4a8..6a7acab0a4 100644
--- a/features/ftue/impl/src/main/res/values-hu/translations.xml
+++ b/features/ftue/impl/src/main/res/values-hu/translations.xml
@@ -1,7 +1,5 @@
- "Ez egy egyszeri folyamat, köszönjük a türelmét."
- "A fiók beállítása."
"A beállításokat később is módosíthatja."
"Értesítések engedélyezése, hogy soha ne maradjon le egyetlen üzenetről sem"
"A hívások, szavazások, keresések és egyebek az év további részében kerülnek hozzáadásra."
diff --git a/features/ftue/impl/src/main/res/values-in/translations.xml b/features/ftue/impl/src/main/res/values-in/translations.xml
index 126ce6376b..1004f8a643 100644
--- a/features/ftue/impl/src/main/res/values-in/translations.xml
+++ b/features/ftue/impl/src/main/res/values-in/translations.xml
@@ -1,7 +1,5 @@
- "Ini adalah proses satu kali, terima kasih telah menunggu."
- "Menyiapkan akun Anda."
"Anda dapat mengubah pengaturan Anda nanti."
"Izinkan pemberitahuan dan jangan pernah melewatkan pesan"
"Panggilan, pemungutan suara, pencarian, dan lainnya akan ditambahkan di tahun ini."
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 69013ebdb8..eaff5216dc 100644
--- a/features/ftue/impl/src/main/res/values-it/translations.xml
+++ b/features/ftue/impl/src/main/res/values-it/translations.xml
@@ -1,7 +1,5 @@
- "Si tratta di una procedura che si effettua una sola volta, grazie per l\'attesa."
- "Configurazione del tuo account."
"Potrai modificare le tue impostazioni in seguito."
"Consenti le notifiche e non perdere mai un messaggio"
"Chiamate, sondaggi, ricerche e altro ancora saranno aggiunti nel corso dell\'anno."
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 f932256318..d48049b8b8 100644
--- a/features/ftue/impl/src/main/res/values-ro/translations.xml
+++ b/features/ftue/impl/src/main/res/values-ro/translations.xml
@@ -1,7 +1,5 @@
- "Acesta este un proces care se desfășoară o singură dată, vă mulțumim pentru așteptare."
- "Contul dumneavoastră se configurează"
"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 ab225b5d0f..6ddceef57f 100644
--- a/features/ftue/impl/src/main/res/values-ru/translations.xml
+++ b/features/ftue/impl/src/main/res/values-ru/translations.xml
@@ -1,7 +1,5 @@
- "Это одноразовый процесс, спасибо, что подождали."
- "Настройка учетной записи."
"Вы можете изменить настройки позже."
"Разрешите уведомления и никогда не пропустите сообщение"
"Звонки, опросы, поиск и многое другое будут добавлены позже в этом году."
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 c7eb1f83be..d963dbd734 100644
--- a/features/ftue/impl/src/main/res/values-sk/translations.xml
+++ b/features/ftue/impl/src/main/res/values-sk/translations.xml
@@ -1,7 +1,5 @@
- "Ide o jednorazový proces, ďakujeme za trpezlivosť."
- "Nastavenie vášho účtu."
"Svoje nastavenia môžete neskôr zmeniť."
"Povoľte oznámenia a nikdy nezmeškajte žiadnu správu"
"Hovory, ankety, vyhľadávanie a ďalšie funkcie pribudnú neskôr v tomto roku."
diff --git a/features/ftue/impl/src/main/res/values-zh-rTW/translations.xml b/features/ftue/impl/src/main/res/values-zh-rTW/translations.xml
index 1edd145776..8e5d5e3109 100644
--- a/features/ftue/impl/src/main/res/values-zh-rTW/translations.xml
+++ b/features/ftue/impl/src/main/res/values-zh-rTW/translations.xml
@@ -1,7 +1,5 @@
- "這是一次性的程序,感謝您耐心等候。"
- "正在設定您的帳號。"
"通話、投票、搜尋等更多功能將在今年登場。"
"在這次的更新,您無法查看聊天室內被加密的歷史訊息。"
"我們很樂意聽取您的意見,請到設定頁面告訴我們您的想法。"
diff --git a/features/ftue/impl/src/main/res/values/localazy.xml b/features/ftue/impl/src/main/res/values/localazy.xml
index f89cc622f6..3e8c86b761 100644
--- a/features/ftue/impl/src/main/res/values/localazy.xml
+++ b/features/ftue/impl/src/main/res/values/localazy.xml
@@ -1,7 +1,5 @@
- "This is a one time process, thanks for waiting."
- "Setting up your account."
"You can change your settings later."
"Allow notifications and never miss a message"
"Calls, polls, search and more will be added later this year."
diff --git a/features/ftue/impl/src/test/kotlin/io/element/android/features/ftue/impl/DefaultFtueStateTests.kt b/features/ftue/impl/src/test/kotlin/io/element/android/features/ftue/impl/DefaultFtueStateTests.kt
index 44df35ca05..834aaa5c1f 100644
--- a/features/ftue/impl/src/test/kotlin/io/element/android/features/ftue/impl/DefaultFtueStateTests.kt
+++ b/features/ftue/impl/src/test/kotlin/io/element/android/features/ftue/impl/DefaultFtueStateTests.kt
@@ -18,16 +18,11 @@ package io.element.android.features.ftue.impl
import android.os.Build
import com.google.common.truth.Truth.assertThat
-import io.element.android.features.ftue.impl.migration.InMemoryMigrationScreenStore
-import io.element.android.features.ftue.impl.migration.MigrationScreenStore
import io.element.android.features.ftue.impl.state.DefaultFtueState
import io.element.android.features.ftue.impl.state.FtueStep
import io.element.android.features.ftue.impl.welcome.state.FakeWelcomeState
import io.element.android.features.lockscreen.api.LockScreenService
import io.element.android.features.lockscreen.test.FakeLockScreenService
-import io.element.android.libraries.matrix.api.MatrixClient
-import io.element.android.libraries.matrix.test.A_SESSION_ID
-import io.element.android.libraries.matrix.test.FakeMatrixClient
import io.element.android.libraries.permissions.impl.FakePermissionStateProvider
import io.element.android.services.analytics.api.AnalyticsService
import io.element.android.services.analytics.test.FakeAnalyticsService
@@ -54,7 +49,6 @@ class DefaultFtueStateTests {
fun `given all checks being true, should display flow is false`() = runTest {
val welcomeState = FakeWelcomeState()
val analyticsService = FakeAnalyticsService()
- val migrationScreenStore = InMemoryMigrationScreenStore()
val permissionStateProvider = FakePermissionStateProvider(permissionGranted = true)
val lockScreenService = FakeLockScreenService()
val coroutineScope = CoroutineScope(coroutineContext + SupervisorJob())
@@ -63,14 +57,12 @@ class DefaultFtueStateTests {
coroutineScope = coroutineScope,
welcomeState = welcomeState,
analyticsService = analyticsService,
- migrationScreenStore = migrationScreenStore,
permissionStateProvider = permissionStateProvider,
lockScreenService = lockScreenService,
)
welcomeState.setWelcomeScreenShown()
analyticsService.setDidAskUserConsent()
- migrationScreenStore.setMigrationScreenShown(A_SESSION_ID)
permissionStateProvider.setPermissionGranted()
lockScreenService.setIsPinSetup(true)
state.updateState()
@@ -85,7 +77,6 @@ class DefaultFtueStateTests {
fun `traverse flow`() = runTest {
val welcomeState = FakeWelcomeState()
val analyticsService = FakeAnalyticsService()
- val migrationScreenStore = InMemoryMigrationScreenStore()
val permissionStateProvider = FakePermissionStateProvider(permissionGranted = false)
val lockScreenService = FakeLockScreenService()
val coroutineScope = CoroutineScope(coroutineContext + SupervisorJob())
@@ -94,29 +85,24 @@ class DefaultFtueStateTests {
coroutineScope = coroutineScope,
welcomeState = welcomeState,
analyticsService = analyticsService,
- migrationScreenStore = migrationScreenStore,
permissionStateProvider = permissionStateProvider,
lockScreenService = lockScreenService,
)
val steps = mutableListOf()
- // First step, migration screen
- steps.add(state.getNextStep(steps.lastOrNull()))
- migrationScreenStore.setMigrationScreenShown(A_SESSION_ID)
-
- // Second step, welcome screen
+ // First step, welcome screen
steps.add(state.getNextStep(steps.lastOrNull()))
welcomeState.setWelcomeScreenShown()
- // Third step, notifications opt in
+ // Second step, notifications opt in
steps.add(state.getNextStep(steps.lastOrNull()))
permissionStateProvider.setPermissionGranted()
- // Fourth step, entering PIN code
+ // Third step, entering PIN code
steps.add(state.getNextStep(steps.lastOrNull()))
lockScreenService.setIsPinSetup(true)
- // Fifth step, analytics opt in
+ // Fourth step, analytics opt in
steps.add(state.getNextStep(steps.lastOrNull()))
analyticsService.setDidAskUserConsent()
@@ -124,7 +110,6 @@ class DefaultFtueStateTests {
steps.add(state.getNextStep(steps.lastOrNull()))
assertThat(steps).containsExactly(
- FtueStep.MigrationScreen,
FtueStep.WelcomeScreen,
FtueStep.NotificationsOptIn,
FtueStep.LockscreenSetup,
@@ -141,19 +126,16 @@ class DefaultFtueStateTests {
fun `if a check for a step is true, start from the next one`() = runTest {
val coroutineScope = CoroutineScope(coroutineContext + SupervisorJob())
val analyticsService = FakeAnalyticsService()
- val migrationScreenStore = InMemoryMigrationScreenStore()
val permissionStateProvider = FakePermissionStateProvider(permissionGranted = false)
val lockScreenService = FakeLockScreenService()
val state = createState(
coroutineScope = coroutineScope,
analyticsService = analyticsService,
- migrationScreenStore = migrationScreenStore,
permissionStateProvider = permissionStateProvider,
lockScreenService = lockScreenService,
)
- // Skip first 4 steps
- migrationScreenStore.setMigrationScreenShown(A_SESSION_ID)
+ // Skip first 3 steps
state.setWelcomeScreenShown()
permissionStateProvider.setPermissionGranted()
lockScreenService.setIsPinSetup(true)
@@ -171,18 +153,15 @@ class DefaultFtueStateTests {
fun `if version is older than 13 we don't display the notification opt in screen`() = runTest {
val coroutineScope = CoroutineScope(coroutineContext + SupervisorJob())
val analyticsService = FakeAnalyticsService()
- val migrationScreenStore = InMemoryMigrationScreenStore()
val lockScreenService = FakeLockScreenService()
val state = createState(
sdkIntVersion = Build.VERSION_CODES.M,
coroutineScope = coroutineScope,
analyticsService = analyticsService,
- migrationScreenStore = migrationScreenStore,
lockScreenService = lockScreenService,
)
- migrationScreenStore.setMigrationScreenShown(A_SESSION_ID)
assertThat(state.getNextStep()).isEqualTo(FtueStep.WelcomeScreen)
state.setWelcomeScreenShown()
lockScreenService.setIsPinSetup(true)
@@ -200,9 +179,7 @@ class DefaultFtueStateTests {
coroutineScope: CoroutineScope,
welcomeState: FakeWelcomeState = FakeWelcomeState(),
analyticsService: AnalyticsService = FakeAnalyticsService(),
- migrationScreenStore: MigrationScreenStore = InMemoryMigrationScreenStore(),
permissionStateProvider: FakePermissionStateProvider = FakePermissionStateProvider(permissionGranted = false),
- matrixClient: MatrixClient = FakeMatrixClient(),
lockScreenService: LockScreenService = FakeLockScreenService(),
// First version where notification permission is required
sdkIntVersion: Int = Build.VERSION_CODES.TIRAMISU,
@@ -211,9 +188,7 @@ class DefaultFtueStateTests {
coroutineScope = coroutineScope,
analyticsService = analyticsService,
welcomeScreenState = welcomeState,
- migrationScreenStore = migrationScreenStore,
permissionStateProvider = permissionStateProvider,
lockScreenService = lockScreenService,
- matrixClient = matrixClient,
)
}
diff --git a/features/invitelist/impl/src/main/res/values-be/translations.xml b/features/invitelist/impl/src/main/res/values-be/translations.xml
new file mode 100644
index 0000000000..36c895dcb9
--- /dev/null
+++ b/features/invitelist/impl/src/main/res/values-be/translations.xml
@@ -0,0 +1,9 @@
+
+
+ "Вы ўпэўненыя, што жадаеце адхіліць запрашэнне ў %1$s?"
+ "Адхіліць запрашэнне"
+ "Вы ўпэўненыя, што жадаеце адмовіцца ад прыватных зносін з %1$s?"
+ "Адхіліць чат"
+ "Няма запрашэнняў"
+ "%1$s (%2$s) запрасіў вас"
+
diff --git a/features/leaveroom/api/src/main/res/values-be/translations.xml b/features/leaveroom/api/src/main/res/values-be/translations.xml
new file mode 100644
index 0000000000..f7d4ed17df
--- /dev/null
+++ b/features/leaveroom/api/src/main/res/values-be/translations.xml
@@ -0,0 +1,6 @@
+
+
+ "Вы ўпэўнены, што жадаеце пакінуць гэты пакой? Вы тут адзіны карыстальнік. Калі вы выйдзеце, ніхто не зможа далучыцца ў будучыні, у тым ліку і вы."
+ "Вы ўпэўнены, што жадаеце пакінуць гэты пакой? Гэты пакой не агульнадаступны, і вы не зможаце далучыцца да яго зноў без запрашэння."
+ "Вы ўпэўнены, што жадаеце пакінуць пакой?"
+
diff --git a/features/leaveroom/api/src/main/res/values-de/translations.xml b/features/leaveroom/api/src/main/res/values-de/translations.xml
index c691f57471..e684dd1e42 100644
--- a/features/leaveroom/api/src/main/res/values-de/translations.xml
+++ b/features/leaveroom/api/src/main/res/values-de/translations.xml
@@ -1,5 +1,6 @@
+ "Bist du sicher, dass du diese Unterhaltung verlassen willst? Diese Unterhaltung ist nicht öffentlich und du kannst ihr ohne Einladung nicht wieder beitreten."
"Bist du sicher, dass du diesen Raum verlassen möchtest? Du bist die einzige Person hier. Wenn du austritst, kann in Zukunft niemand mehr eintreten, auch du nicht."
"Bist du sicher, dass du diesen Raum verlassen möchtest? Dieser Raum ist nicht öffentlich und du kannst ihm ohne Einladung nicht erneut beitreten."
"Bist du sicher, dass du den Raum verlassen willst?"
diff --git a/features/leaveroom/api/src/main/res/values-hu/translations.xml b/features/leaveroom/api/src/main/res/values-hu/translations.xml
index 0fb52a61aa..c75cddfd05 100644
--- a/features/leaveroom/api/src/main/res/values-hu/translations.xml
+++ b/features/leaveroom/api/src/main/res/values-hu/translations.xml
@@ -1,5 +1,6 @@
+ "Biztos, hogy elhagyja ezt a beszélgetést? Ez a beszélgetés nem nyilvános, és meghívás nélkül nem fog tudni visszacsatlakozni."
"Biztos, hogy elhagyja ezt a szobát? Ön az egyedüli ember itt. Ha kilép, akkor senki sem fog tudni csatlakozni a jövőben, Önt is beleértve."
"Biztos, hogy elhagyod ezt a szobát? Ez a szoba nem nyilvános, és meghívó nélkül nem fogsz tudni újra belépni."
"Biztos, hogy elhagyod a szobát?"
diff --git a/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/components/PinEntryTextField.kt b/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/components/PinEntryTextField.kt
index 3c7a451bfc..674bc0d27e 100644
--- a/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/components/PinEntryTextField.kt
+++ b/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/components/PinEntryTextField.kt
@@ -66,10 +66,8 @@ fun PinEntryTextField(
private fun PinEntryRow(
pinEntry: PinEntry,
isSecured: Boolean,
- modifier: Modifier = Modifier,
) {
FlowRow(
- modifier = modifier,
horizontalArrangement = Arrangement.spacedBy(8.dp, alignment = Alignment.CenterHorizontally),
verticalArrangement = Arrangement.spacedBy(8.dp),
) {
@@ -83,7 +81,6 @@ private fun PinEntryRow(
private fun PinDigitView(
digit: PinDigit,
isSecured: Boolean,
- modifier: Modifier = Modifier,
) {
val shape = RoundedCornerShape(8.dp)
val appearanceModifier = when (digit) {
@@ -95,7 +92,7 @@ private fun PinDigitView(
}
}
Box(
- modifier = modifier
+ modifier = Modifier
.size(48.dp)
.then(appearanceModifier),
contentAlignment = Alignment.Center,
diff --git a/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/setup/biometric/SetupBiometricView.kt b/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/setup/biometric/SetupBiometricView.kt
index 8e7a326c90..99001e5334 100644
--- a/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/setup/biometric/SetupBiometricView.kt
+++ b/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/setup/biometric/SetupBiometricView.kt
@@ -57,13 +57,12 @@ fun SetupBiometricView(
}
@Composable
-private fun SetupBiometricHeader(modifier: Modifier = Modifier) {
+private fun SetupBiometricHeader() {
val biometricAuth = stringResource(id = R.string.screen_app_lock_biometric_authentication)
IconTitleSubtitleMolecule(
iconImageVector = Icons.Default.Fingerprint,
title = stringResource(id = R.string.screen_app_lock_settings_enable_biometric_unlock),
subTitle = stringResource(id = R.string.screen_app_lock_setup_biometric_unlock_subtitle, biometricAuth),
- modifier = modifier
)
}
@@ -71,11 +70,8 @@ private fun SetupBiometricHeader(modifier: Modifier = Modifier) {
private fun SetupBiometricFooter(
onAllowClicked: () -> Unit,
onSkipClicked: () -> Unit,
- modifier: Modifier = Modifier
) {
- ButtonColumnMolecule(
- modifier = modifier,
- ) {
+ ButtonColumnMolecule {
val biometricAuth = stringResource(id = R.string.screen_app_lock_biometric_authentication)
Button(
text = stringResource(id = R.string.screen_app_lock_setup_biometric_unlock_allow_title, biometricAuth),
diff --git a/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/setup/pin/SetupPinView.kt b/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/setup/pin/SetupPinView.kt
index 095848c9fb..a3dcab5a43 100644
--- a/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/setup/pin/SetupPinView.kt
+++ b/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/setup/pin/SetupPinView.kt
@@ -86,10 +86,8 @@ fun SetupPinView(
private fun SetupPinHeader(
isValidationStep: Boolean,
appName: String,
- modifier: Modifier = Modifier,
) {
Column(
- modifier = modifier,
horizontalAlignment = Alignment.CenterHorizontally,
) {
IconTitleSubtitleMolecule(
@@ -107,7 +105,6 @@ private fun SetupPinHeader(
@Composable
private fun SetupPinContent(
state: SetupPinState,
- modifier: Modifier = Modifier,
) {
val focusRequester = remember { FocusRequester() }
LaunchedEffect(Unit) {
@@ -119,14 +116,13 @@ private fun SetupPinContent(
onValueChange = { entry ->
state.eventSink(SetupPinEvents.OnPinEntryChanged(entry, state.isConfirmationStep))
},
- modifier = modifier
+ modifier = Modifier
.focusRequester(focusRequester)
.padding(top = 36.dp)
.fillMaxWidth()
)
if (state.setupPinFailure != null) {
ErrorDialog(
- modifier = modifier,
title = state.setupPinFailure.title(),
content = state.setupPinFailure.content(),
onDismiss = {
diff --git a/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/unlock/PinUnlockView.kt b/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/unlock/PinUnlockView.kt
index ad4dc5da99..db12006e04 100644
--- a/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/unlock/PinUnlockView.kt
+++ b/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/unlock/PinUnlockView.kt
@@ -107,10 +107,9 @@ fun PinUnlockView(
private fun PinUnlockPage(
state: PinUnlockState,
isInAppUnlock: Boolean,
- modifier: Modifier = Modifier
) {
BoxWithConstraints {
- val commonModifier = modifier
+ val commonModifier = Modifier
.fillMaxSize()
.systemBarsPadding()
.imePadding()
@@ -188,7 +187,6 @@ private fun SignOutPrompt(
isCancellable: Boolean,
onSignOut: () -> Unit,
onDismiss: () -> Unit,
- modifier: Modifier = Modifier
) {
if (isCancellable) {
ConfirmationDialog(
@@ -196,14 +194,12 @@ private fun SignOutPrompt(
content = stringResource(id = R.string.screen_app_lock_signout_alert_message),
onSubmitClicked = onSignOut,
onDismiss = onDismiss,
- modifier = modifier,
)
} else {
ErrorDialog(
title = stringResource(id = R.string.screen_app_lock_signout_alert_title),
content = stringResource(id = R.string.screen_app_lock_signout_alert_message),
onDismiss = onSignOut,
- modifier = modifier,
)
}
}
@@ -258,9 +254,11 @@ private fun PinUnlockExpandedView(
@Composable
private fun PinDotsRow(
pinEntry: PinEntry,
- modifier: Modifier = Modifier,
) {
- Row(modifier, horizontalArrangement = spacedBy(8.dp), verticalAlignment = Alignment.CenterVertically) {
+ Row(
+ horizontalArrangement = spacedBy(8.dp),
+ verticalAlignment = Alignment.CenterVertically,
+ ) {
for (digit in pinEntry.digits) {
PinDot(isFilled = digit is PinDigit.Filled)
}
@@ -270,7 +268,6 @@ private fun PinDotsRow(
@Composable
private fun PinDot(
isFilled: Boolean,
- modifier: Modifier = Modifier,
) {
val backgroundColor = if (isFilled) {
ElementTheme.colors.iconPrimary
@@ -278,7 +275,7 @@ private fun PinDot(
ElementTheme.colors.bgSubtlePrimary
}
Box(
- modifier = modifier
+ modifier = Modifier
.size(14.dp)
.background(backgroundColor, CircleShape)
)
@@ -290,7 +287,10 @@ private fun PinUnlockHeader(
isInAppUnlock: Boolean,
modifier: Modifier = Modifier,
) {
- Column(modifier, horizontalAlignment = Alignment.CenterHorizontally) {
+ Column(
+ modifier = modifier,
+ horizontalAlignment = Alignment.CenterHorizontally,
+ ) {
if (isInAppUnlock) {
RoundedIconAtom(imageVector = Icons.Filled.Lock)
} else {
diff --git a/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/unlock/keypad/PinKeypad.kt b/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/unlock/keypad/PinKeypad.kt
index 6c51b10979..4033a1b6f7 100644
--- a/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/unlock/keypad/PinKeypad.kt
+++ b/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/unlock/keypad/PinKeypad.kt
@@ -108,14 +108,13 @@ private fun PinKeypadRow(
models: ImmutableList,
onClick: (PinKeypadModel) -> Unit,
pinKeySize: Dp,
- modifier: Modifier = Modifier,
horizontalArrangement: Arrangement.Horizontal = Arrangement.Start,
verticalAlignment: Alignment.Vertical = Alignment.Top,
) {
Row(
horizontalArrangement = horizontalArrangement,
verticalAlignment = verticalAlignment,
- modifier = modifier.fillMaxWidth(),
+ modifier = Modifier.fillMaxWidth(),
) {
val commonModifier = Modifier.size(pinKeySize)
for (model in models) {
diff --git a/features/lockscreen/impl/src/main/res/values-be/translations.xml b/features/lockscreen/impl/src/main/res/values-be/translations.xml
new file mode 100644
index 0000000000..508ddc97cd
--- /dev/null
+++ b/features/lockscreen/impl/src/main/res/values-be/translations.xml
@@ -0,0 +1,39 @@
+
+
+
+ - "У вас %1$d спроба разблакіроўкі"
+ - "У вас %1$d спроб разблакіроўкі"
+ - "У вас %1$d спроб разблакіроўкі"
+
+
+ - "Няправільны PIN-код. У вас застаўся %1$d шанец"
+ - "Няправільны PIN-код. У вас застаўася %1$d шанцаў"
+ - "Няправільны PIN-код. У вас застаўася %1$d шанцаў"
+
+ "біяметрычная аўтэнтыфікацыя"
+ "біяметрычная разблакіроўка"
+ "Разблакіроўка з дапамогай біяметрыі"
+ "Забыліся PIN-код?"
+ "Змяніць PIN-код"
+ "Дазволіць біяметрычную разблакіроўку"
+ "Выдаліць PIN-код"
+ "Вы ўпэўнены, што жадаеце выдаліць PIN-код?"
+ "Выдаліць PIN-код?"
+ "Дазволіць %1$s"
+ "Я хацеў бы выкарыстоўваць PIN-код"
+ "Эканомце час і выкарыстоўвайце %1$s для разблакіроўкі праграмы"
+ "Выберыце PIN-код"
+ "Пацвярджэнне PIN-кода"
+ "Вы не можаце выбраць гэты PIN-код з меркаванняў бяспекі"
+ "Выберыце іншы PIN-код"
+ "Заблакіруйце %1$s, каб павялічыць бяспеку вашых чатаў.
+
+Абярыце што-небудзь незабыўнае. Калі вы забудзецеся гэты PIN-код, вы выйдзеце з праграмы."
+ "Увядзіце адзін і той жа PIN двойчы"
+ "PIN-коды не супадаюць"
+ "Каб працягнуць, вам неабходна паўторна ўвайсці ў сістэму і стварыць новы PIN-код"
+ "Вы выходзіце з сістэмы"
+ "Выкарыстоўваць біяметрыю"
+ "Выкарыстоўваць PIN-код"
+ "Выхад…"
+
diff --git a/features/login/impl/src/main/kotlin/io/element/android/features/login/impl/screens/loginpassword/LoginPasswordView.kt b/features/login/impl/src/main/kotlin/io/element/android/features/login/impl/screens/loginpassword/LoginPasswordView.kt
index 1c97836b02..2bf76c2189 100644
--- a/features/login/impl/src/main/kotlin/io/element/android/features/login/impl/screens/loginpassword/LoginPasswordView.kt
+++ b/features/login/impl/src/main/kotlin/io/element/android/features/login/impl/screens/loginpassword/LoginPasswordView.kt
@@ -16,6 +16,7 @@
package io.element.android.features.login.impl.screens.loginpassword
+import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.consumeWindowInsets
@@ -55,6 +56,7 @@ import io.element.android.features.login.impl.R
import io.element.android.features.login.impl.error.isWaitListError
import io.element.android.features.login.impl.error.loginError
import io.element.android.libraries.architecture.AsyncData
+import io.element.android.libraries.designsystem.atomic.molecules.ButtonColumnMolecule
import io.element.android.libraries.designsystem.atomic.molecules.IconTitleSubtitleMolecule
import io.element.android.libraries.designsystem.components.button.BackButton
import io.element.android.libraries.designsystem.components.dialogs.ErrorDialog
@@ -114,7 +116,7 @@ fun LoginPasswordView(
.padding(padding)
.consumeWindowInsets(padding)
.verticalScroll(state = scrollState)
- .padding(horizontal = 16.dp),
+ .padding(start = 20.dp, end = 20.dp, bottom = 20.dp),
) {
// Title
IconTitleSubtitleMolecule(
@@ -137,16 +139,23 @@ fun LoginPasswordView(
// Flexible spacing to keep the submit button at the bottom
Spacer(modifier = Modifier.weight(1f))
// Submit
- Button(
- text = stringResource(CommonStrings.action_continue),
- showProgress = isLoading,
- onClick = ::submit,
- enabled = state.submitEnabled || isLoading,
+ Box(
modifier = Modifier
- .fillMaxWidth()
- .testTag(TestTags.loginContinue)
- )
- Spacer(modifier = Modifier.height(60.dp))
+ .padding(horizontal = 16.dp)
+ ) {
+ ButtonColumnMolecule {
+ Button(
+ text = stringResource(CommonStrings.action_continue),
+ showProgress = isLoading,
+ onClick = ::submit,
+ enabled = state.submitEnabled || isLoading,
+ modifier = Modifier
+ .fillMaxWidth()
+ .testTag(TestTags.loginContinue)
+ )
+ Spacer(modifier = Modifier.height(48.dp))
+ }
+ }
if (state.loginAction is AsyncData.Failure) {
when {
@@ -170,7 +179,6 @@ private fun LoginForm(
state: LoginPasswordState,
isLoading: Boolean,
onSubmit: () -> Unit,
- modifier: Modifier = Modifier
) {
var loginFieldState by textFieldState(stateValue = state.formState.login)
var passwordFieldState by textFieldState(stateValue = state.formState.password)
@@ -178,7 +186,7 @@ private fun LoginForm(
val focusManager = LocalFocusManager.current
val eventSink = state.eventSink
- Column(modifier) {
+ Column {
Text(
text = stringResource(R.string.screen_login_form_header),
modifier = Modifier.padding(start = 16.dp),
diff --git a/features/login/impl/src/main/kotlin/io/element/android/features/login/impl/screens/waitlistscreen/WaitListView.kt b/features/login/impl/src/main/kotlin/io/element/android/features/login/impl/screens/waitlistscreen/WaitListView.kt
index e8a3bddc43..7a47255b6c 100644
--- a/features/login/impl/src/main/kotlin/io/element/android/features/login/impl/screens/waitlistscreen/WaitListView.kt
+++ b/features/login/impl/src/main/kotlin/io/element/android/features/login/impl/screens/waitlistscreen/WaitListView.kt
@@ -25,11 +25,11 @@ import androidx.compose.runtime.Composable
import androidx.compose.runtime.CompositionLocalProvider
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
-import androidx.compose.ui.graphics.Color
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.tooling.preview.PreviewParameter
import androidx.compose.ui.unit.dp
import androidx.lifecycle.Lifecycle
+import io.element.android.compound.theme.ElementTheme
import io.element.android.features.login.impl.R
import io.element.android.features.login.impl.error.isWaitListError
import io.element.android.features.login.impl.error.loginError
@@ -119,11 +119,10 @@ private fun WaitListContent(
private fun OverallContent(
state: WaitListState,
onCancelClicked: () -> Unit,
- modifier: Modifier = Modifier,
) {
- Box(modifier = modifier.fillMaxSize()) {
+ Box(modifier = Modifier.fillMaxSize()) {
if (state.loginAction !is AsyncData.Success) {
- CompositionLocalProvider(LocalContentColor provides Color.Black) {
+ CompositionLocalProvider(LocalContentColor provides ElementTheme.colors.textOnSolidPrimary) {
TextButton(
text = stringResource(CommonStrings.action_cancel),
onClick = onCancelClicked,
diff --git a/features/login/impl/src/main/res/values-be/translations.xml b/features/login/impl/src/main/res/values-be/translations.xml
new file mode 100644
index 0000000000..1e4bd1f7af
--- /dev/null
+++ b/features/login/impl/src/main/res/values-be/translations.xml
@@ -0,0 +1,41 @@
+
+
+ "Змяніць правайдара ўліковага запісу"
+ "Адрас хатняга сервера"
+ "Увядзіце пошукавы запыт або адрас дамена."
+ "Пошук кампаніі, супольнасці або прыватнага сервера."
+ "Знайдзіце правайдара ўліковых запісаў"
+ "Вы збіраецеся ўвайсці ў %s"
+ "Вы збіраецеся стварыць уліковы запіс на %s"
+ "Matrix.org - гэта вялікі бясплатны сервер у агульнадаступнай сетцы Matrix для бяспечнай дэцэнтралізаванай сувязі, якім кіруе фонд Matrix.org."
+ "Іншае"
+ "Выкарыстоўвайце іншага правайдара ўліковых запісаў, напрыклад, уласны прыватны сервер або працоўны ўліковы запіс."
+ "Змяніць правайдара ўліковага запісу"
+ "Нам не ўдалося звязацца з гэтым хатнім серверам. Упэўніцеся, што вы правільна ўвялі URL-адрас хатняга сервера. Калі URL-адрас пазначаны правільна, звярніцеся да адміністратара хатняга сервера за дадатковай дапамогай."
+ "На жаль, гэты сервер не падтрымлівае sliding sync."
+ "URL хатняга сервера"
+ "Вы можаце падключыцца толькі да існуючага сервера, які падтрымлівае sliding sync. Адміністратару хатняга сервера запатрабуецца наладзіць яго. %1$s"
+ "Які адрас вашага сервера?"
+ "Выберыце свой сервер"
+ "Гэты ўліковы запіс быў дэактываваны."
+ "Няправільнае імя карыстальніка і/або пароль"
+ "Гэта несапраўдны ідэнтыфікатар карыстальніка. Чаканы фармат: ‘@user:homeserver.org’"
+ "Выбраны хатні сервер не падтрымлівае пароль або ўваход у OIDC. Калі ласка, звярніцеся да адміністратара або абярыце іншы хатні сервер."
+ "Увядзіце свае даныя"
+ "Сардэчна запрашаем!"
+ "Увайдзіце ў %1$s"
+ "Змяніць правайдара ўліковага запісу"
+ "Прыватны сервер для супрацоўнікаў Element."
+ "Matrix - гэта адкрытая сетка для бяспечнай, дэцэнтралізаванай сувязі."
+ "Тут будуць захоўвацца вашыя размовы - сапраўды гэтак жа, як вы выкарыстоўваеце паштовага правайдара для захоўвання сваіх лістоў."
+ "Вы збіраецеся ўвайсці ў %1$s"
+ "Вы збіраецеся стварыць уліковы запіс на %1$s"
+ "Зараз існуе высокі попыт на %1$s на %2$s. Калі ласка, вярніцеся ў дадатак праз некалькі дзён і паспрабуйце зноў.
+
+Дзякуй за цярпенне!"
+ "Амаль гатова."
+ "Тут будуць захоўвацца вашыя размовы - сапраўды гэтак жа, як вы выкарыстоўваеце паштовага правайдара для захоўвання сваіх лістоў."
+ "Тут будуць захоўвацца вашыя размовы - сапраўды гэтак жа, як вы выкарыстоўваеце паштовага правайдара для захоўвання сваіх лістоў."
+ "Matrix - гэта адкрытая сетка для бяспечнай, дэцэнтралізаванай сувязі."
+ "Вітаем у %1$s!"
+
diff --git a/features/login/impl/src/main/res/values-cs/translations.xml b/features/login/impl/src/main/res/values-cs/translations.xml
index 0094479b12..8295b140c3 100644
--- a/features/login/impl/src/main/res/values-cs/translations.xml
+++ b/features/login/impl/src/main/res/values-cs/translations.xml
@@ -5,9 +5,7 @@
"Zadejte hledaný výraz nebo adresu domény."
"Vyhledejte společnost, komunitu nebo soukromý server."
"Najít poskytovatele účtu"
- "Zde budou uloženy vaše konverzace - podobně jako u poskytovatele e-mailových služeb uchováváte své e-maily."
"Chystáte se přihlásit do %s"
- "Zde budou uloženy vaše konverzace - podobně jako u poskytovatele e-mailových služeb uchováváte své e-maily."
"Chystáte se vytvořit účet na %s"
"Matrix.org je velký bezplatný server ve veřejné síti Matrix pro bezpečnou decentralizovanou komunikaci, který provozuje nadace Matrix.org."
"Jiný"
@@ -37,6 +35,8 @@
Díky za trpělivost!"
"Jste v pořadníku!"
"Jdete do toho!"
+ "Zde budou uloženy vaše konverzace - podobně jako u poskytovatele e-mailových služeb uchováváte své e-maily."
+ "Zde budou uloženy vaše konverzace - podobně jako u poskytovatele e-mailových služeb uchováváte své e-maily."
"Matrix je otevřená síť pro bezpečnou a decentralizovanou komunikaci."
"Vítá vás %1$s!"
diff --git a/features/login/impl/src/main/res/values-de/translations.xml b/features/login/impl/src/main/res/values-de/translations.xml
index 2603548cab..2dbf83ad8a 100644
--- a/features/login/impl/src/main/res/values-de/translations.xml
+++ b/features/login/impl/src/main/res/values-de/translations.xml
@@ -5,9 +5,7 @@
"Gib einen Suchbegriff oder eine Domainadresse ein."
"Suche nach einem Unternehmen, einer Community oder einem privaten Server."
"Kontoanbieter finden"
- "Hier werden deine Gespräche gespeichert – genau so, wie du einen E-Mail-Anbieter nutzen würdest, um deine E-Mails aufzubewahren."
"Du bist dabei, dich bei %s anzumelden"
- "Hier werden deine Gespräche gespeichert – genau so, wie du einen E-Mail-Anbieter nutzen würdest, um deine E-Mails aufzubewahren."
"Du bist dabei, ein Konto bei %s zu erstellen"
"Matrix.org ist ein großer, kostenloser Server im öffentlichen Matrix-Netzwerk für eine sichere, dezentralisierte Kommunikation, der von der Matrix.org Foundation betrieben wird."
"Sonstige"
@@ -37,6 +35,8 @@
Danke für deine Geduld!"
"Du bist fast am Ziel."
"Du bist dabei."
+ "Hier werden deine Gespräche gespeichert - so wie du deine E-Mails bei einem E-Mail-Anbieter aufbewahren würden."
+ "Hier werden deine Gespräche gespeichert - so wie du deine E-Mails bei einem E-Mail-Anbieter aufbewahren würden."
"Matrix ist ein offenes Netzwerk für eine sichere, dezentrale Kommunikation."
"Willkommen bei %1$s!"
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 a9020cbd22..e51f908654 100644
--- a/features/login/impl/src/main/res/values-es/translations.xml
+++ b/features/login/impl/src/main/res/values-es/translations.xml
@@ -5,9 +5,7 @@
"Introduzca un término de búsqueda o una dirección de dominio."
"Busca una empresa, comunidad o servidor privado."
"Encontrar un proveedor de cuenta"
- "Aquí es donde se alojarán tus conversaciones — justo como si utilizaras un proveedor de correo electrónico para guardar tus correos electrónicos."
"Estás a punto de iniciar sesión en %s"
- "Aquí es donde se alojarán tus conversaciones — justo como si utilizaras un proveedor de correo electrónico para guardar tus correos electrónicos."
"Estás a punto de crear una cuenta en %s"
"Matrix.org es un servidor grande y gratuito en la red pública Matrix para una comunicación segura y descentralizada, administrado por la Fundación Matrix.org."
"Otro"
@@ -37,6 +35,8 @@
¡Gracias por tu paciencia!"
"Ya casi has terminado."
"Estás dentro."
+ "Aquí es donde se alojarán tus conversaciones — justo como utilizarías un proveedor de correo electrónico para guardar tus correos electrónicos."
+ "Aquí es donde se alojarán tus conversaciones — justo como utilizarías un proveedor de correo electrónico para guardar tus correos electrónicos."
"Matrix es una red abierta para una comunicación segura y descentralizada."
"¡Bienvenido a %1$s!"
diff --git a/features/login/impl/src/main/res/values-fr/translations.xml b/features/login/impl/src/main/res/values-fr/translations.xml
index eedba864da..b07b674a97 100644
--- a/features/login/impl/src/main/res/values-fr/translations.xml
+++ b/features/login/impl/src/main/res/values-fr/translations.xml
@@ -5,9 +5,7 @@
"Entrez un terme de recherche ou une adresse de domaine."
"Recherchez une entreprise, une communauté ou un serveur privé."
"Trouver un fournisseur de comptes"
- "C’est ici que vos conversations seront enregistrées, comme vous le feriez avec un fournisseur de messagerie pour conserver vos e-mails."
"Vous êtes sur le point de vous connecter à %s"
- "C’est ici que vos conversations seront enregistrées, comme vous le feriez avec un fournisseur de messagerie pour conserver vos e-mails."
"Vous êtes sur le point de créer un compte sur %s"
"Matrix.org est un grand serveur gratuit sur le réseau public Matrix pour une communication sécurisée et décentralisée, géré par la Fondation Matrix.org."
"Autres"
@@ -37,6 +35,8 @@
Merci pour votre patience !"
"Vous y êtes presque."
"Vous y êtes."
+ "C’est ici que vos conversations seront enregistrées, comme vous le feriez avec un fournisseur de messagerie pour conserver vos e-mails."
+ "C’est ici que vos conversations seront enregistrées, comme vous le feriez avec un fournisseur de messagerie pour conserver vos e-mails."
"Matrix est un réseau ouvert pour une communication sécurisée et décentralisée."
"Bienvenue dans %1$s !"
diff --git a/features/login/impl/src/main/res/values-hu/translations.xml b/features/login/impl/src/main/res/values-hu/translations.xml
index e41ff77592..1c3957f028 100644
--- a/features/login/impl/src/main/res/values-hu/translations.xml
+++ b/features/login/impl/src/main/res/values-hu/translations.xml
@@ -5,10 +5,8 @@
"Adjon meg egy keresési kifejezést vagy egy tartománycímet."
"Keresés egy cégre, közösségre vagy privát kiszolgálóra."
"Fiókszolgáltató keresése"
- "Itt lesznek a beszélgetései – ahogyan egy e-mail-szolgáltatást is használna a levelei kezeléséhez."
"Hamarosan bejelentkezik ide: %s"
- "Itt lesznek a beszélgetéseid – ahogyan egy e-mail-szolgáltatást is használnál a leveleid kezeléséhez."
- "Hamarosan létrehoz egy fiókot itt: %s"
+ "Hamarosan létrehozol egy fiókot itt: %s"
"A Matrix.org egy nagy, ingyenes kiszolgáló a nyilvános Matrix-hálózaton, a biztonságos, decentralizált kommunikáció érdekében, amelyet a Matrix.org Alapítvány üzemeltet."
"Egyéb"
"Másik fiókszolgáltató, például a saját privát kiszolgáló vagy egy munkahelyi fiók használata."
@@ -37,6 +35,8 @@
Köszönjük a türelmét!"
"Már majdnem kész van."
"Bent van."
+ "Itt lesznek a beszélgetései – ahogyan egy e-mail-szolgáltatást is használna a levelei kezeléséhez."
+ "Itt lesznek a beszélgetései – ahogyan egy e-mail-szolgáltatást is használna a levelei kezeléséhez."
"A Matrix egy nyitott hálózat a biztonságos, decentralizált kommunikációhoz."
"Üdvözli az %1$s!"
diff --git a/features/login/impl/src/main/res/values-in/translations.xml b/features/login/impl/src/main/res/values-in/translations.xml
index 6d4cb91baa..ed98a36efa 100644
--- a/features/login/impl/src/main/res/values-in/translations.xml
+++ b/features/login/impl/src/main/res/values-in/translations.xml
@@ -5,9 +5,7 @@
"Masukkan istilah pencarian atau alamat domain."
"Cari perusahaan, komunitas, atau server pribadi."
"Cari penyedia akun"
- "Di sinilah percakapan Anda akan berlangsung — sama seperti Anda menggunakan penyedia surel untuk menyimpan surel Anda."
"Anda akan masuk ke %s"
- "Di sinilah percakapan Anda akan berlangsung — sama seperti Anda menggunakan penyedia surel untuk menyimpan surel Anda."
"Anda akan membuat akun di %s"
"Matrix.org adalah server besar dan gratis di jaringan Matrix publik untuk komunikasi yang aman dan terdesentralisasi, disediakan oleh Yayasan Matrix.org."
"Lainnya"
@@ -37,6 +35,8 @@
Terima kasih atas kesabaran Anda!"
"Anda hampir selesai."
"Anda sudah masuk."
+ "Di sinilah percakapan Anda akan berlangsung — sama seperti Anda menggunakan penyedia surel untuk menyimpan surel Anda."
+ "Di sinilah percakapan Anda akan berlangsung — sama seperti Anda menggunakan penyedia surel untuk menyimpan surel Anda."
"Matrix adalah jaringan terbuka untuk komunikasi yang aman dan terdesentralisasi."
"Selamat datang di %1$s!"
diff --git a/features/login/impl/src/main/res/values-it/translations.xml b/features/login/impl/src/main/res/values-it/translations.xml
index c3e43e5933..0036cf25d3 100644
--- a/features/login/impl/src/main/res/values-it/translations.xml
+++ b/features/login/impl/src/main/res/values-it/translations.xml
@@ -5,9 +5,7 @@
"Inserisci un termine di ricerca o un indirizzo di dominio."
"Cerca un\' azienda, una comunità o un server privato."
"Trova un fornitore di account"
- "Qui è dove vivranno le tue conversazioni - proprio come useresti un fornitore di posta elettronica per conservare le tue email."
"Stai per accedere a %s"
- "Qui è dove vivranno le tue conversazioni - proprio come useresti un fornitore di posta elettronica per conservare le tue email."
"Stai per creare un account su %s"
"Matrix.org è un grande server gratuito nella rete pubblica Matrix per una comunicazione sicura e decentralizzata, gestito dalla Fondazione Matrix.org."
"Altro"
@@ -37,6 +35,8 @@
Grazie per la pazienza!"
"Ci sei quasi."
"Sei dentro."
+ "Qui è dove vivranno le tue conversazioni — proprio come useresti un fornitore di posta elettronica per conservare le tue email."
+ "Qui è dove vivranno le tue conversazioni — proprio come useresti un fornitore di posta elettronica per conservare le tue email."
"Matrix è una rete aperta per comunicazioni sicure e decentralizzate."
"Benvenuti in %1$s!"
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 49e701558a..bc4ac6d0f8 100644
--- a/features/login/impl/src/main/res/values-ro/translations.xml
+++ b/features/login/impl/src/main/res/values-ro/translations.xml
@@ -5,9 +5,7 @@
"Introduceţi un termen de căutare sau o adresă de domeniu."
"Căutați o companie, o comunitate sau un server privat."
"Găsiți un furnizor de cont"
- "Aici vor trăi conversațiile dumneavoastră - la fel cum ați folosi un furnizor de e-mail pentru a vă păstra e-mailurile."
"Sunteți pe cale să vă conectați la %s"
- "Aici vor trăi conversațiile dumneavoastră - la fel cum ați folosi un furnizor de e-mail pentru a vă păstra e-mailurile."
"Sunteți pe cale să creați un cont pe %s"
"Matrix.org este un server mare și gratuit din rețeaua publică Matrix pentru comunicații sigure și descentralizate, administrat de Fundația Matrix.org."
"Altul"
@@ -36,6 +34,8 @@
Vă mulțumim pentru răbdare!"
"Sunteți pe lista de așteptare"
"Sunteți conectat!"
+ "Aici vor trăi conversațiile dvs. - la fel cum ați folosi un furnizor de e-mail pentru a vă păstra e-mailurile."
+ "Aici vor trăi conversațiile dvs. - la fel cum ați folosi un furnizor de e-mail pentru a vă păstra e-mailurile."
"Matrix este o rețea deschisă pentru o comunicare sigură și descentralizată."
"Bun venit la%1$s!"
diff --git a/features/login/impl/src/main/res/values-ru/translations.xml b/features/login/impl/src/main/res/values-ru/translations.xml
index 0917813950..1451bcd85c 100644
--- a/features/login/impl/src/main/res/values-ru/translations.xml
+++ b/features/login/impl/src/main/res/values-ru/translations.xml
@@ -5,9 +5,7 @@
"Введите поисковый запрос или адрес домена."
"Поиск компании, сообщества или частного сервера."
"Поиск сервера учетной записи"
- "Здесь будут храниться ваши разговоры - точно так же, как вы используете почтового провайдера для хранения своих писем."
"Вы собираетесь войти в %s"
- "Здесь будут храниться ваши разговоры - точно так же, как вы используете почтового провайдера для хранения своих писем."
"Вы собираетесь создать учетную запись на %s"
"Matrix.org — это большой бесплатный сервер в общедоступной сети Matrix для безопасной децентрализованной связи, управляемый Matrix.org Foundation."
"Другое"
@@ -37,6 +35,8 @@
Спасибо за терпение!"
"Почти готово."
"Вы зарегистрированы."
+ "Здесь будут храниться ваши разговоры - точно так же, как вы используете почтового провайдера для хранения своих писем."
+ "Здесь будут храниться ваши разговоры - точно так же, как вы используете почтового провайдера для хранения своих писем."
"Matrix — это открытая сеть для безопасной децентрализованной связи."
"Добро пожаловать в %1$s!"
diff --git a/features/login/impl/src/main/res/values-sk/translations.xml b/features/login/impl/src/main/res/values-sk/translations.xml
index b2e41b5a43..016aed6786 100644
--- a/features/login/impl/src/main/res/values-sk/translations.xml
+++ b/features/login/impl/src/main/res/values-sk/translations.xml
@@ -5,9 +5,7 @@
"Zadajte hľadaný výraz alebo adresu domény."
"Vyhľadať spoločnosť, komunitu alebo súkromný server."
"Nájsť poskytovateľa účtu"
- "Tu budú žiť vaše konverzácie — podobne ako používate poskytovateľa e-mailových služieb na uchovávanie e-mailov."
"Chystáte sa prihlásiť do %s"
- "Tu budú žiť vaše konverzácie — podobne ako používate poskytovateľa e-mailových služieb na uchovávanie e-mailov."
"Chystáte sa vytvoriť účet na %s"
"Matrix.org je veľký bezplatný server vo verejnej sieti Matrix na bezpečnú, decentralizovanú komunikáciu, ktorý prevádzkuje nadácia Matrix.org."
"Iný"
@@ -37,6 +35,8 @@
Ďakujeme za trpezlivosť!"
"Ste na čakanej listine!"
"Ste dnu!"
+ "Tu budú žiť vaše konverzácie - podobne ako používate poskytovateľa e-mailových služieb na uchovávanie e-mailov."
+ "Tu budú žiť vaše konverzácie - podobne ako používate poskytovateľa e-mailových služieb na uchovávanie e-mailov."
"Matrix je otvorená sieť pre bezpečnú a decentralizovanú komunikáciu."
"Vitajte v %1$s!"
diff --git a/features/login/impl/src/main/res/values-zh-rTW/translations.xml b/features/login/impl/src/main/res/values-zh-rTW/translations.xml
index 7fd944aac2..cdf9a9d9d6 100644
--- a/features/login/impl/src/main/res/values-zh-rTW/translations.xml
+++ b/features/login/impl/src/main/res/values-zh-rTW/translations.xml
@@ -5,9 +5,7 @@
"輸入關鍵字或網域名稱。"
"搜尋公司、社群、私有伺服器。"
"尋找帳號提供者"
- "您的所有對話將保存於此,就如同您的電子郵件供應商會保存您的電子郵件一樣。"
"您即將登入 %s"
- "您的所有對話將保存於此,就如同您的電子郵件供應商會保存您的電子郵件一樣。"
"您即將在 %s 建立帳號"
"Matrix.org 由 Matrix.org 基金會營運,是用於安全、去中心化通訊的公共 Matrix 網路上的大型免費伺服器。"
"其他"
@@ -27,6 +25,8 @@
"您的所有對話將保存於此,就如同您的電子郵件供應商會保存您的電子郵件一樣。"
"您即將登入 %1$s"
"您即將在 %1$s 建立帳號"
+ "您的所有對話將保存於此,就如同您的電子郵件供應商會保存您的電子郵件一樣。"
+ "您的所有對話將保存於此,就如同您的電子郵件供應商會保存您的電子郵件一樣。"
"Matrix 是一個開放網路,為了安全且去中心化的通訊而生。"
"歡迎使用 %1$s!"
diff --git a/features/login/impl/src/main/res/values/localazy.xml b/features/login/impl/src/main/res/values/localazy.xml
index 2149318670..bec21c85dc 100644
--- a/features/login/impl/src/main/res/values/localazy.xml
+++ b/features/login/impl/src/main/res/values/localazy.xml
@@ -5,9 +5,7 @@
"Enter a search term or a domain address."
"Search for a company, community, or private server."
"Find an account provider"
- "This is where your conversations will live — just like you would use an email provider to keep your emails."
"You’re about to sign in to %s"
- "This is where your conversations will live — just like you would use an email provider to keep your emails."
"You’re about to create an account on %s"
"Matrix.org is a large, free server on the public Matrix network for secure, decentralised communication, run by the Matrix.org Foundation."
"Other"
@@ -37,6 +35,8 @@
Thanks for your patience!"
"You’re almost there."
"You\'re in."
+ "This is where your conversations will live — just like you would use an email provider to keep your emails."
+ "This is where your conversations will live — just like you would use an email provider to keep your emails."
"Matrix is an open network for secure, decentralised communication."
"Welcome to %1$s!"
diff --git a/features/logout/impl/src/main/kotlin/io/element/android/features/logout/impl/LogoutView.kt b/features/logout/impl/src/main/kotlin/io/element/android/features/logout/impl/LogoutView.kt
index ecec90cf06..98827b4700 100644
--- a/features/logout/impl/src/main/kotlin/io/element/android/features/logout/impl/LogoutView.kt
+++ b/features/logout/impl/src/main/kotlin/io/element/android/features/logout/impl/LogoutView.kt
@@ -86,7 +86,7 @@ fun LogoutView(
onForceLogoutClicked = {
eventSink(LogoutEvents.Logout(ignoreSdkError = true))
},
- onDismissError = {
+ onDismissDialog = {
eventSink(LogoutEvents.CloseDialogs)
},
onSuccessLogout = {
diff --git a/features/logout/impl/src/main/kotlin/io/element/android/features/logout/impl/direct/DefaultDirectLogoutView.kt b/features/logout/impl/src/main/kotlin/io/element/android/features/logout/impl/direct/DefaultDirectLogoutView.kt
index f646d86c9e..64935f8cda 100644
--- a/features/logout/impl/src/main/kotlin/io/element/android/features/logout/impl/direct/DefaultDirectLogoutView.kt
+++ b/features/logout/impl/src/main/kotlin/io/element/android/features/logout/impl/direct/DefaultDirectLogoutView.kt
@@ -41,7 +41,7 @@ class DefaultDirectLogoutView @Inject constructor() : DirectLogoutView {
onForceLogoutClicked = {
eventSink(DirectLogoutEvents.Logout(ignoreSdkError = true))
},
- onDismissError = {
+ onDismissDialog = {
eventSink(DirectLogoutEvents.CloseDialogs)
},
onSuccessLogout = {
diff --git a/features/logout/impl/src/main/kotlin/io/element/android/features/logout/impl/ui/LogoutActionDialog.kt b/features/logout/impl/src/main/kotlin/io/element/android/features/logout/impl/ui/LogoutActionDialog.kt
index bf103745b4..18e2809034 100644
--- a/features/logout/impl/src/main/kotlin/io/element/android/features/logout/impl/ui/LogoutActionDialog.kt
+++ b/features/logout/impl/src/main/kotlin/io/element/android/features/logout/impl/ui/LogoutActionDialog.kt
@@ -32,8 +32,7 @@ fun LogoutActionDialog(
state: AsyncAction,
onConfirmClicked: () -> Unit,
onForceLogoutClicked: () -> Unit,
- // TODO Rename
- onDismissError: () -> Unit,
+ onDismissDialog: () -> Unit,
onSuccessLogout: (String?) -> Unit,
) {
when (state) {
@@ -42,7 +41,7 @@ fun LogoutActionDialog(
AsyncAction.Confirming ->
LogoutConfirmationDialog(
onSubmitClicked = onConfirmClicked,
- onDismiss = onDismissError
+ onDismiss = onDismissDialog
)
is AsyncAction.Loading ->
ProgressDialog(text = stringResource(id = R.string.screen_signout_in_progress_dialog_content))
@@ -52,7 +51,7 @@ fun LogoutActionDialog(
content = stringResource(id = CommonStrings.error_unknown),
retryText = stringResource(id = CommonStrings.action_signout_anyway),
onRetry = onForceLogoutClicked,
- onDismiss = onDismissError,
+ onDismiss = onDismissDialog,
)
is AsyncAction.Success -> {
val latestOnSuccessLogout by rememberUpdatedState(onSuccessLogout)
diff --git a/features/logout/impl/src/main/res/values-be/translations.xml b/features/logout/impl/src/main/res/values-be/translations.xml
new file mode 100644
index 0000000000..237c7ff2b0
--- /dev/null
+++ b/features/logout/impl/src/main/res/values-be/translations.xml
@@ -0,0 +1,18 @@
+
+
+ "Вы ўпэўнены, што жадаеце выйсці?"
+ "Выхад…"
+ "Вы збіраецеся выйсці з апошняга сеанса. Калі вы выйдзеце з сістэмы зараз, вы страціце доступ да зашыфраваных паведамленняў."
+ "Вы адключылі рэзервовае капіраванне"
+ "Вашы ключы ўсё яшчэ захоўваліся, калі вы выйшлі з сеткі. Паўторна падключыцеся, каб можна было стварыць рэзервовую копію вашых ключоў перад выхадам."
+ "Рэзервовае капіраванне ключоў усё яшчэ працягваецца"
+ "Калі ласка, дачакайцеся завяршэння працэсу, перш чым выходзіць з сістэмы."
+ "Вашы ключы ўсё яшчэ ствараюцца"
+ "Вы збіраецеся выйсці з апошняга сеанса. Калі вы выйдзеце з сістэмы зараз, вы страціце доступ да зашыфраваных паведамленняў."
+ "Аднаўленне не наладжана"
+ "Вы збіраецеся выйсці з апошняга сеанса. Калі вы выйдзеце з сістэмы зараз, вы страціце доступ да зашыфраваных паведамленняў."
+ "Вы захавалі свой ключ аднаўлення?"
+ "Выйсці"
+ "Выйсці"
+ "Выйсці"
+
diff --git a/features/messages/impl/build.gradle.kts b/features/messages/impl/build.gradle.kts
index 897dc36faa..dbfc80d820 100644
--- a/features/messages/impl/build.gradle.kts
+++ b/features/messages/impl/build.gradle.kts
@@ -62,6 +62,7 @@ dependencies {
implementation(projects.libraries.voicerecorder.api)
implementation(projects.libraries.mediaplayer.api)
implementation(projects.libraries.uiUtils)
+ implementation(projects.libraries.testtags)
implementation(projects.features.networkmonitor.api)
implementation(projects.services.analytics.api)
implementation(libs.coil.compose)
@@ -94,6 +95,7 @@ dependencies {
testImplementation(projects.libraries.voicerecorder.test)
testImplementation(projects.libraries.mediaplayer.test)
testImplementation(projects.libraries.mediaviewer.test)
+ testImplementation(projects.libraries.testtags)
testImplementation(libs.test.mockk)
testImplementation(libs.test.junitext)
testImplementation(libs.test.robolectric)
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 d378014e2f..986dba4709 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
@@ -59,6 +59,7 @@ import io.element.android.features.messages.impl.timeline.model.event.TimelineIt
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemUnknownContent
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemVideoContent
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemVoiceContent
+import io.element.android.features.messages.impl.typing.TypingNotificationPresenter
import io.element.android.features.messages.impl.utils.messagesummary.MessageSummaryFormatter
import io.element.android.features.messages.impl.voicemessages.composer.VoiceMessageComposerPresenter
import io.element.android.features.networkmonitor.api.NetworkMonitor
@@ -97,6 +98,7 @@ class MessagesPresenter @AssistedInject constructor(
private val composerPresenter: MessageComposerPresenter,
private val voiceMessageComposerPresenter: VoiceMessageComposerPresenter,
timelinePresenterFactory: TimelinePresenter.Factory,
+ private val typingNotificationPresenter: TypingNotificationPresenter,
private val actionListPresenter: ActionListPresenter,
private val customReactionPresenter: CustomReactionPresenter,
private val reactionSummaryPresenter: ReactionSummaryPresenter,
@@ -129,6 +131,7 @@ class MessagesPresenter @AssistedInject constructor(
val composerState = composerPresenter.present()
val voiceMessageComposerState = voiceMessageComposerPresenter.present()
val timelineState = timelinePresenter.present()
+ val typingNotificationState = typingNotificationPresenter.present()
val actionListState = actionListPresenter.present()
val customReactionState = customReactionPresenter.present()
val reactionSummaryState = reactionSummaryPresenter.present()
@@ -139,7 +142,7 @@ class MessagesPresenter @AssistedInject constructor(
val userHasPermissionToSendMessage by room.canSendMessageAsState(type = MessageEventType.ROOM_MESSAGE, updateKey = syncUpdateFlow.value)
val userHasPermissionToRedactOwn by room.canRedactOwnAsState(updateKey = syncUpdateFlow.value)
val userHasPermissionToRedactOther by room.canRedactOtherAsState(updateKey = syncUpdateFlow.value)
- val userHasPermissionToSendReaction by room.canSendMessageAsState(type = MessageEventType.REACTION_SENT, updateKey = syncUpdateFlow.value)
+ val userHasPermissionToSendReaction by room.canSendMessageAsState(type = MessageEventType.REACTION, updateKey = syncUpdateFlow.value)
val roomName: AsyncData by remember {
derivedStateOf { roomInfo?.name?.let { AsyncData.Success(it) } ?: AsyncData.Uninitialized }
}
@@ -155,6 +158,14 @@ class MessagesPresenter @AssistedInject constructor(
mutableStateOf(false)
}
+ LaunchedEffect(Unit) {
+ // Mark the room as read on entering but don't send read receipts
+ // as those will be handled by the timeline.
+ withContext(dispatchers.io) {
+ room.markAsRead(null)
+ }
+ }
+
LaunchedEffect(syncUpdateFlow.value) {
withContext(dispatchers.io) {
canJoinCall = room.canUserJoinCall(room.sessionId).getOrDefault(false)
@@ -225,6 +236,7 @@ class MessagesPresenter @AssistedInject constructor(
composerState = composerState,
voiceMessageComposerState = voiceMessageComposerState,
timelineState = timelineState,
+ typingNotificationState = typingNotificationState,
actionListState = actionListState,
customReactionState = customReactionState,
reactionSummaryState = reactionSummaryState,
diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/MessagesState.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/MessagesState.kt
index 8e4d1c484b..5c6e1c7ffa 100644
--- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/MessagesState.kt
+++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/MessagesState.kt
@@ -24,6 +24,7 @@ import io.element.android.features.messages.impl.timeline.components.customreact
import io.element.android.features.messages.impl.timeline.components.reactionsummary.ReactionSummaryState
import io.element.android.features.messages.impl.timeline.components.receipt.bottomsheet.ReadReceiptBottomSheetState
import io.element.android.features.messages.impl.timeline.components.retrysendmenu.RetrySendMenuState
+import io.element.android.features.messages.impl.typing.TypingNotificationState
import io.element.android.features.messages.impl.voicemessages.composer.VoiceMessageComposerState
import io.element.android.libraries.architecture.AsyncData
import io.element.android.libraries.designsystem.components.avatar.AvatarData
@@ -42,6 +43,7 @@ data class MessagesState(
val composerState: MessageComposerState,
val voiceMessageComposerState: VoiceMessageComposerState,
val timelineState: TimelineState,
+ val typingNotificationState: TypingNotificationState,
val actionListState: ActionListState,
val customReactionState: CustomReactionState,
val reactionSummaryState: ReactionSummaryState,
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 1bb500e08f..da278904a3 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
@@ -17,16 +17,22 @@
package io.element.android.features.messages.impl
import androidx.compose.ui.tooling.preview.PreviewParameterProvider
+import io.element.android.features.messages.impl.actionlist.ActionListState
import io.element.android.features.messages.impl.actionlist.anActionListState
import io.element.android.features.messages.impl.messagecomposer.AttachmentsState
+import io.element.android.features.messages.impl.messagecomposer.MessageComposerState
import io.element.android.features.messages.impl.messagecomposer.aMessageComposerState
import io.element.android.features.messages.impl.timeline.aTimelineItemList
import io.element.android.features.messages.impl.timeline.aTimelineState
+import io.element.android.features.messages.impl.timeline.components.customreaction.CustomReactionEvents
import io.element.android.features.messages.impl.timeline.components.customreaction.CustomReactionState
+import io.element.android.features.messages.impl.timeline.components.reactionsummary.ReactionSummaryEvents
import io.element.android.features.messages.impl.timeline.components.reactionsummary.ReactionSummaryState
import io.element.android.features.messages.impl.timeline.components.receipt.bottomsheet.ReadReceiptBottomSheetState
import io.element.android.features.messages.impl.timeline.components.retrysendmenu.RetrySendMenuState
import io.element.android.features.messages.impl.timeline.model.event.aTimelineItemTextContent
+import io.element.android.features.messages.impl.typing.aTypingNotificationState
+import io.element.android.features.messages.impl.voicemessages.composer.VoiceMessageComposerState
import io.element.android.features.messages.impl.voicemessages.composer.aVoiceMessageComposerState
import io.element.android.features.messages.impl.voicemessages.composer.aVoiceMessagePreviewState
import io.element.android.libraries.architecture.AsyncData
@@ -42,62 +48,77 @@ open class MessagesStateProvider : PreviewParameterProvider {
override val values: Sequence
get() = sequenceOf(
aMessagesState(),
- aMessagesState().copy(hasNetworkConnection = false),
- aMessagesState().copy(composerState = aMessageComposerState().copy(showAttachmentSourcePicker = true)),
- aMessagesState().copy(userHasPermissionToSendMessage = false),
- aMessagesState().copy(showReinvitePrompt = true),
- aMessagesState().copy(
+ aMessagesState(hasNetworkConnection = false),
+ aMessagesState(composerState = aMessageComposerState(showAttachmentSourcePicker = true)),
+ aMessagesState(userHasPermissionToSendMessage = false),
+ aMessagesState(showReinvitePrompt = true),
+ aMessagesState(
roomName = AsyncData.Uninitialized,
roomAvatar = AsyncData.Uninitialized,
),
- aMessagesState().copy(composerState = aMessageComposerState().copy(showTextFormatting = true)),
- aMessagesState().copy(
+ aMessagesState(composerState = aMessageComposerState(showTextFormatting = true)),
+ aMessagesState(
enableVoiceMessages = true,
voiceMessageComposerState = aVoiceMessageComposerState(showPermissionRationaleDialog = true),
),
- aMessagesState().copy(
- composerState = aMessageComposerState().copy(
+ aMessagesState(
+ composerState = aMessageComposerState(
attachmentsState = AttachmentsState.Sending.Processing(persistentListOf())
),
),
- aMessagesState().copy(
- composerState = aMessageComposerState().copy(
+ aMessagesState(
+ composerState = aMessageComposerState(
attachmentsState = AttachmentsState.Sending.Uploading(0.33f)
),
),
- aMessagesState().copy(
+ aMessagesState(
callState = RoomCallState.ONGOING,
),
- aMessagesState().copy(
+ aMessagesState(
enableVoiceMessages = true,
voiceMessageComposerState = aVoiceMessageComposerState(
voiceMessageState = aVoiceMessagePreviewState(),
showSendFailureDialog = true
),
),
- aMessagesState().copy(
+ aMessagesState(
callState = RoomCallState.DISABLED,
),
)
}
-fun aMessagesState() = MessagesState(
- roomId = RoomId("!id:domain"),
- roomName = AsyncData.Success("Room name"),
- roomAvatar = AsyncData.Success(AvatarData("!id:domain", "Room name", size = AvatarSize.TimelineRoom)),
- userHasPermissionToSendMessage = true,
- userHasPermissionToRedactOwn = false,
- userHasPermissionToRedactOther = false,
- userHasPermissionToSendReaction = true,
- composerState = aMessageComposerState().copy(
+fun aMessagesState(
+ roomName: AsyncData = AsyncData.Success("Room name"),
+ roomAvatar: AsyncData = AsyncData.Success(AvatarData("!id:domain", "Room name", size = AvatarSize.TimelineRoom)),
+ userHasPermissionToSendMessage: Boolean = true,
+ composerState: MessageComposerState = aMessageComposerState(
richTextEditorState = RichTextEditorState("Hello", initialFocus = true),
isFullScreen = false,
mode = MessageComposerMode.Normal,
),
- voiceMessageComposerState = aVoiceMessageComposerState(),
- timelineState = aTimelineState().copy(
+ voiceMessageComposerState: VoiceMessageComposerState = aVoiceMessageComposerState(),
+ actionListState: ActionListState = anActionListState(),
+ customReactionState: CustomReactionState = aCustomReactionState(),
+ reactionSummaryState: ReactionSummaryState = aReactionSummaryState(),
+ hasNetworkConnection: Boolean = true,
+ showReinvitePrompt: Boolean = false,
+ enableVoiceMessages: Boolean = true,
+ callState: RoomCallState = RoomCallState.ENABLED,
+ eventSink: (MessagesEvents) -> Unit = {},
+) = MessagesState(
+ roomId = RoomId("!id:domain"),
+ roomName = roomName,
+ roomAvatar = roomAvatar,
+ userHasPermissionToSendMessage = userHasPermissionToSendMessage,
+ userHasPermissionToRedactOwn = false,
+ userHasPermissionToRedactOther = false,
+ userHasPermissionToSendReaction = true,
+ composerState = composerState,
+ voiceMessageComposerState = voiceMessageComposerState,
+ timelineState = aTimelineState(
timelineItems = aTimelineItemList(aTimelineItemTextContent()),
),
+ typingNotificationState = aTypingNotificationState(),
retrySendMenuState = RetrySendMenuState(
selectedEvent = null,
eventSink = {},
@@ -106,23 +127,32 @@ fun aMessagesState() = MessagesState(
selectedEvent = null,
eventSink = {},
),
- actionListState = anActionListState(),
- customReactionState = CustomReactionState(
- target = CustomReactionState.Target.None,
- eventSink = {},
- selectedEmoji = persistentSetOf(),
- ),
- reactionSummaryState = ReactionSummaryState(
- target = null,
- eventSink = {},
- ),
- hasNetworkConnection = true,
+ actionListState = actionListState,
+ customReactionState = customReactionState,
+ reactionSummaryState = reactionSummaryState,
+ hasNetworkConnection = hasNetworkConnection,
snackbarMessage = null,
inviteProgress = AsyncData.Uninitialized,
- showReinvitePrompt = false,
+ showReinvitePrompt = showReinvitePrompt,
enableTextFormatting = true,
- enableVoiceMessages = true,
- callState = RoomCallState.ENABLED,
+ enableVoiceMessages = enableVoiceMessages,
+ callState = callState,
appName = "Element",
- eventSink = {}
+ eventSink = eventSink,
+)
+
+fun aReactionSummaryState(
+ target: ReactionSummaryState.Summary? = null,
+ eventSink: (ReactionSummaryEvents) -> Unit = {}
+) = ReactionSummaryState(
+ target = target,
+ eventSink = eventSink,
+)
+
+fun aCustomReactionState(
+ eventSink: (CustomReactionEvents) -> Unit = {},
+) = CustomReactionState(
+ target = CustomReactionState.Target.None,
+ selectedEmoji = persistentSetOf(),
+ eventSink = eventSink,
)
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 be3afb6660..fd1c6bf19b 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
@@ -102,7 +102,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.TopAppBar
import io.element.android.libraries.designsystem.utils.KeepScreenOn
-import io.element.android.libraries.designsystem.utils.LogCompositions
import io.element.android.libraries.designsystem.utils.OnLifecycleEvent
import io.element.android.libraries.designsystem.utils.snackbar.SnackbarHost
import io.element.android.libraries.designsystem.utils.snackbar.rememberSnackbarHostState
@@ -126,9 +125,8 @@ fun MessagesView(
onCreatePollClicked: () -> Unit,
onJoinCallClicked: () -> Unit,
modifier: Modifier = Modifier,
+ forceJumpToBottomVisibility: Boolean = false
) {
- LogCompositions(tag = "MessagesScreen", msg = "Root")
-
OnLifecycleEvent { _, event ->
state.voiceMessageComposerState.eventSink(VoiceMessageComposerEvents.LifecycleEvent(event))
}
@@ -146,8 +144,6 @@ fun MessagesView(
// This is needed because the composer is inside an AndroidView that can't be affected by the FocusManager in Compose
val localView = LocalView.current
- LogCompositions(tag = "MessagesScreen", msg = "Content")
-
fun onMessageClicked(event: TimelineItem.Event) {
Timber.v("OnMessageClicked= ${event.id}")
val hideKeyboard = onEventClicked(event)
@@ -229,6 +225,7 @@ fun MessagesView(
onSwipeToReply = { targetEvent ->
state.eventSink(MessagesEvents.HandleAction(TimelineItemAction.Reply, targetEvent))
},
+ forceJumpToBottomVisibility = forceJumpToBottomVisibility,
)
},
snackbarHost = {
@@ -329,6 +326,7 @@ private fun MessagesViewContent(
onTimestampClicked: (TimelineItem.Event) -> Unit,
onSendLocationClicked: () -> Unit,
onCreatePollClicked: () -> Unit,
+ forceJumpToBottomVisibility: Boolean,
modifier: Modifier = Modifier,
onSwipeToReply: (TimelineItem.Event) -> Unit,
) {
@@ -389,6 +387,7 @@ private fun MessagesViewContent(
modifier = Modifier.padding(paddingValues),
state = state.timelineState,
roomName = state.roomName.dataOrNull(),
+ typingNotificationState = state.typingNotificationState,
onMessageClicked = onMessageClicked,
onMessageLongClicked = onMessageLongClicked,
onUserDataClicked = onUserDataClicked,
@@ -398,6 +397,7 @@ private fun MessagesViewContent(
onMoreReactionsClicked = onMoreReactionsClicked,
onReadReceiptClick = onReadReceiptClick,
onSwipeToReply = onSwipeToReply,
+ forceJumpToBottomVisibility = forceJumpToBottomVisibility,
)
},
sheetContent = { subcomposing: Boolean ->
@@ -417,10 +417,9 @@ private fun MessagesViewContent(
private fun MessagesViewComposerBottomSheetContents(
subcomposing: Boolean,
state: MessagesState,
- modifier: Modifier = Modifier,
) {
if (state.userHasPermissionToSendMessage) {
- Column(modifier = modifier.fillMaxWidth()) {
+ Column(modifier = Modifier.fillMaxWidth()) {
MentionSuggestionsPickerView(
modifier = Modifier
.heightIn(max = 230.dp)
@@ -448,7 +447,7 @@ private fun MessagesViewComposerBottomSheetContents(
)
}
} else {
- CantSendMessageBanner(modifier = modifier)
+ CantSendMessageBanner()
}
}
@@ -461,10 +460,8 @@ private fun MessagesViewTopBar(
onRoomDetailsClicked: () -> Unit,
onJoinCallClicked: () -> Unit,
onBackPressed: () -> Unit,
- modifier: Modifier = Modifier,
) {
TopAppBar(
- modifier = modifier,
navigationIcon = {
BackButton(onClick = onBackPressed)
},
@@ -502,7 +499,6 @@ private fun MessagesViewTopBar(
@Composable
private fun JoinCallMenuItem(
- modifier: Modifier = Modifier,
onJoinCallClicked: () -> Unit,
) {
Material3Button(
@@ -512,7 +508,7 @@ private fun JoinCallMenuItem(
containerColor = ElementTheme.colors.iconAccentTertiary
),
contentPadding = PaddingValues(horizontal = 10.dp, vertical = 0.dp),
- modifier = modifier.heightIn(min = 36.dp),
+ modifier = Modifier.heightIn(min = 36.dp),
) {
Icon(
modifier = Modifier.size(20.dp),
@@ -550,11 +546,9 @@ private fun RoomAvatarAndNameRow(
}
@Composable
-private fun CantSendMessageBanner(
- modifier: Modifier = Modifier,
-) {
+private fun CantSendMessageBanner() {
Row(
- modifier = modifier
+ modifier = Modifier
.fillMaxWidth()
.background(MaterialTheme.colorScheme.secondary)
.padding(16.dp),
@@ -584,5 +578,6 @@ internal fun MessagesViewPreview(@PreviewParameter(MessagesStateProvider::class)
onSendLocationClicked = {},
onCreatePollClicked = {},
onJoinCallClicked = {},
+ forceJumpToBottomVisibility = true,
)
}
diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/actionlist/ActionListStateProvider.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/actionlist/ActionListStateProvider.kt
index e33f54de3e..10952058b5 100644
--- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/actionlist/ActionListStateProvider.kt
+++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/actionlist/ActionListStateProvider.kt
@@ -122,9 +122,12 @@ open class ActionListStateProvider : PreviewParameterProvider {
}
}
-fun anActionListState() = ActionListState(
- target = ActionListState.Target.None,
- eventSink = {}
+fun anActionListState(
+ target: ActionListState.Target = ActionListState.Target.None,
+ eventSink: (ActionListEvents) -> Unit = {},
+) = ActionListState(
+ target = target,
+ eventSink = eventSink
)
fun aTimelineItemActionList(): ImmutableList {
diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/actionlist/ActionListView.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/actionlist/ActionListView.kt
index 3db91fd67c..11b1922fcd 100644
--- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/actionlist/ActionListView.kt
+++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/actionlist/ActionListView.kt
@@ -337,7 +337,6 @@ private fun EmojiButton(
emoji: String,
isHighlighted: Boolean,
onClicked: (String) -> Unit,
- modifier: Modifier = Modifier,
) {
val backgroundColor = if (isHighlighted) {
ElementTheme.colors.bgActionPrimaryRest
@@ -350,7 +349,7 @@ private fun EmojiButton(
stringResource(id = CommonStrings.a11y_react_with, emoji)
}
Box(
- modifier = modifier
+ modifier = Modifier
.size(48.dp)
.background(backgroundColor, CircleShape)
.clearAndSetSemantics {
diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/attachments/preview/AttachmentsPreviewView.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/attachments/preview/AttachmentsPreviewView.kt
index b18d36d61d..45f83568a3 100644
--- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/attachments/preview/AttachmentsPreviewView.kt
+++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/attachments/preview/AttachmentsPreviewView.kt
@@ -118,10 +118,9 @@ private fun AttachmentPreviewContent(
attachment: Attachment,
onSendClicked: () -> Unit,
onDismiss: () -> Unit,
- modifier: Modifier = Modifier,
) {
Column(
- modifier = modifier
+ modifier = Modifier
.fillMaxSize()
.padding(top = 24.dp)
) {
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 af268856e9..7108363ffd 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
@@ -101,10 +101,9 @@ private fun AttachmentSourcePickerMenu(
onSendLocationClicked: () -> Unit,
onCreatePollClicked: () -> Unit,
enableTextFormatting: Boolean,
- modifier: Modifier = Modifier,
) {
Column(
- modifier = modifier
+ modifier = Modifier
.navigationBarsPadding()
.imePadding()
) {
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 4fea2ee046..b98f5fcb39 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
@@ -23,6 +23,7 @@ import androidx.compose.runtime.Composable
import androidx.compose.runtime.DisposableEffect
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.MutableState
+import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateListOf
import androidx.compose.runtime.mutableStateOf
@@ -37,6 +38,7 @@ 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.preferences.api.store.SessionPreferencesStore
import io.element.android.libraries.architecture.Presenter
import io.element.android.libraries.designsystem.utils.snackbar.SnackbarDispatcher
import io.element.android.libraries.designsystem.utils.snackbar.SnackbarMessage
@@ -86,6 +88,7 @@ class MessageComposerPresenter @Inject constructor(
private val room: MatrixRoom,
private val mediaPickerProvider: PickerProvider,
private val featureFlagService: FeatureFlagService,
+ private val sessionPreferencesStore: SessionPreferencesStore,
private val localMediaFactory: LocalMediaFactory,
private val mediaSender: MediaSender,
private val snackbarDispatcher: SnackbarDispatcher,
@@ -147,6 +150,8 @@ class MessageComposerPresenter @Inject constructor(
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 ->
@@ -212,7 +217,9 @@ class MessageComposerPresenter @Inject constructor(
// Declare that the user is not typing anymore when the composer is disposed
onDispose {
appCoroutineScope.launch {
- room.typingNotice(false)
+ if (sendTypingNotifications) {
+ room.typingNotice(false)
+ }
}
}
}
@@ -310,8 +317,10 @@ class MessageComposerPresenter @Inject constructor(
analyticsService.trackError(event.error)
}
is MessageComposerEvents.TypingNotice -> {
- localCoroutineScope.launch {
- room.typingNotice(event.isTyping)
+ if (sendTypingNotifications) {
+ localCoroutineScope.launch {
+ room.typingNotice(event.isTyping)
+ }
}
}
is MessageComposerEvents.SuggestionReceived -> {
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 a542cb772d..da3c0c8af7 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
@@ -32,7 +32,7 @@ open class MessageComposerStateProvider : PreviewParameterProvider = persistentListOf(),
) = MessageComposerState(
- richTextEditorState = composerState,
+ richTextEditorState = richTextEditorState,
isFullScreen = isFullScreen,
mode = mode,
showTextFormatting = showTextFormatting,
diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/TimelineEvents.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/TimelineEvents.kt
index 2fdcb947b4..cf02664a98 100644
--- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/TimelineEvents.kt
+++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/TimelineEvents.kt
@@ -22,16 +22,27 @@ sealed interface TimelineEvents {
data object LoadMore : TimelineEvents
data class SetHighlightedEvent(val eventId: EventId?) : TimelineEvents
data class OnScrollFinished(val firstIndex: Int) : TimelineEvents
+
+ /**
+ * Events coming from a timeline item.
+ */
+ sealed interface EventFromTimelineItem : TimelineEvents
+
+ /**
+ * Events coming from a poll item.
+ */
+ sealed interface TimelineItemPollEvents : EventFromTimelineItem
+
data class PollAnswerSelected(
val pollStartId: EventId,
val answerId: String
- ) : TimelineEvents
+ ) : TimelineItemPollEvents
data class PollEndClicked(
val pollStartId: EventId,
- ) : TimelineEvents
+ ) : TimelineItemPollEvents
data class PollEditClicked(
val pollStartId: EventId,
- ) : TimelineEvents
+ ) : TimelineItemPollEvents
}
diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/TimelinePresenter.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/TimelinePresenter.kt
index a0d7ebf771..c044d96f5c 100644
--- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/TimelinePresenter.kt
+++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/TimelinePresenter.kt
@@ -97,7 +97,7 @@ class TimelinePresenter @AssistedInject constructor(
val paginationState by timeline.paginationState.collectAsState()
val syncUpdateFlow = room.syncUpdateFlow.collectAsState()
val userHasPermissionToSendMessage by room.canSendMessageAsState(type = MessageEventType.ROOM_MESSAGE, updateKey = syncUpdateFlow.value)
- val userHasPermissionToSendReaction by room.canSendMessageAsState(type = MessageEventType.REACTION_SENT, updateKey = syncUpdateFlow.value)
+ val userHasPermissionToSendReaction by room.canSendMessageAsState(type = MessageEventType.REACTION, updateKey = syncUpdateFlow.value)
val prevMostRecentItemId = rememberSaveable { mutableStateOf(null) }
val newItemState = remember { mutableStateOf(NewEventState.None) }
@@ -106,6 +106,7 @@ class TimelinePresenter @AssistedInject constructor(
val keyBackupState by encryptionService.backupStateStateFlow.collectAsState()
val isSendPublicReadReceiptsEnabled by sessionPreferencesStore.isSendPublicReadReceiptsEnabled().collectAsState(initial = true)
+ val renderReadReceipts by sessionPreferencesStore.isRenderReadReceiptsEnabled().collectAsState(initial = true)
val sessionState by remember {
derivedStateOf {
@@ -154,12 +155,12 @@ class TimelinePresenter @AssistedInject constructor(
LaunchedEffect(Unit) {
combine(timeline.timelineItems, room.membersStateFlow) { items, membersState ->
- timelineItemsFactory.replaceWith(
- timelineItems = items,
- roomMembers = membersState.roomMembers().orEmpty()
- )
- items
- }
+ timelineItemsFactory.replaceWith(
+ timelineItems = items,
+ roomMembers = membersState.roomMembers().orEmpty()
+ )
+ items
+ }
.onEach { timelineItems ->
if (timelineItems.isEmpty()) {
paginateBackwards()
@@ -183,6 +184,7 @@ class TimelinePresenter @AssistedInject constructor(
highlightedEventId = highlightedEventId.value,
paginationState = paginationState,
timelineItems = timelineItems,
+ renderReadReceipts = renderReadReceipts,
newEventState = newItemState.value,
sessionState = sessionState,
eventSink = { handleEvents(it) }
diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/TimelineState.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/TimelineState.kt
index ef25d94ebc..a709aa932f 100644
--- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/TimelineState.kt
+++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/TimelineState.kt
@@ -28,6 +28,7 @@ import kotlinx.collections.immutable.ImmutableList
data class TimelineState(
val timelineItems: ImmutableList,
val timelineRoomInfo: TimelineRoomInfo,
+ val renderReadReceipts: Boolean,
val highlightedEventId: EventId?,
val paginationState: MatrixTimeline.PaginationState,
val newEventState: NewEventState,
diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/TimelineStateProvider.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/TimelineStateProvider.kt
index 3012a095e8..449e13e314 100644
--- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/TimelineStateProvider.kt
+++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/TimelineStateProvider.kt
@@ -45,23 +45,36 @@ import kotlinx.collections.immutable.toPersistentList
import java.util.UUID
import kotlin.random.Random
-fun aTimelineState(timelineItems: ImmutableList = persistentListOf()) = TimelineState(
+fun aTimelineState(
+ timelineItems: ImmutableList = persistentListOf(),
+ paginationState: MatrixTimeline.PaginationState = aPaginationState(),
+ eventSink: (TimelineEvents) -> Unit = {},
+) = TimelineState(
timelineItems = timelineItems,
timelineRoomInfo = aTimelineRoomInfo(),
- paginationState = MatrixTimeline.PaginationState(
- isBackPaginating = false,
- hasMoreToLoadBackwards = true,
- beginningOfRoomReached = false,
- ),
+ paginationState = paginationState,
+ renderReadReceipts = false,
highlightedEventId = null,
newEventState = NewEventState.None,
sessionState = aSessionState(
isSessionVerified = true,
isKeyBackupEnabled = true,
),
- eventSink = {},
+ eventSink = eventSink,
)
+fun aPaginationState(
+ isBackPaginating: Boolean = false,
+ hasMoreToLoadBackwards: Boolean = true,
+ beginningOfRoomReached: Boolean = false,
+): MatrixTimeline.PaginationState {
+ return MatrixTimeline.PaginationState(
+ isBackPaginating = isBackPaginating,
+ hasMoreToLoadBackwards = hasMoreToLoadBackwards,
+ beginningOfRoomReached = beginningOfRoomReached,
+ )
+}
+
internal fun aTimelineItemList(content: TimelineItemEventContent): ImmutableList {
return persistentListOf(
// 3 items (First Middle Last) with isMine = false
diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/TimelineView.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/TimelineView.kt
index 563eb78d78..3c0d7fc67b 100644
--- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/TimelineView.kt
+++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/TimelineView.kt
@@ -47,7 +47,6 @@ import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.alpha
import androidx.compose.ui.draw.rotate
-import androidx.compose.ui.platform.LocalInspectionMode
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.tooling.preview.PreviewParameter
import androidx.compose.ui.unit.dp
@@ -62,6 +61,9 @@ import io.element.android.features.messages.impl.timeline.model.NewEventState
import io.element.android.features.messages.impl.timeline.model.TimelineItem
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemEventContent
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemEventContentProvider
+import io.element.android.features.messages.impl.typing.TypingNotificationState
+import io.element.android.features.messages.impl.typing.TypingNotificationView
+import io.element.android.features.messages.impl.typing.aTypingNotificationState
import io.element.android.libraries.designsystem.animation.alphaAnimation
import io.element.android.libraries.designsystem.preview.ElementPreview
import io.element.android.libraries.designsystem.preview.PreviewsDayNight
@@ -75,6 +77,7 @@ import kotlinx.coroutines.launch
@Composable
fun TimelineView(
state: TimelineState,
+ typingNotificationState: TypingNotificationState,
roomName: String?,
onUserDataClicked: (UserId) -> Unit,
onMessageClicked: (TimelineItem.Event) -> Unit,
@@ -86,6 +89,7 @@ fun TimelineView(
onMoreReactionsClicked: (TimelineItem.Event) -> Unit,
onReadReceiptClick: (TimelineItem.Event) -> Unit,
modifier: Modifier = Modifier,
+ forceJumpToBottomVisibility: Boolean = false
) {
fun onReachedLoadMore() {
state.eventSink(TimelineEvents.LoadMore)
@@ -112,6 +116,9 @@ fun TimelineView(
reverseLayout = true,
contentPadding = PaddingValues(vertical = 8.dp),
) {
+ item {
+ TypingNotificationView(state = typingNotificationState)
+ }
items(
items = state.timelineItems,
contentType = { timelineItem -> timelineItem.contentType() },
@@ -120,6 +127,7 @@ fun TimelineView(
TimelineItemRow(
timelineItem = timelineItem,
timelineRoomInfo = state.timelineRoomInfo,
+ renderReadReceipts = state.renderReadReceipts,
isLastOutgoingMessage = (timelineItem as? TimelineItem.Event)?.isMine == true &&
state.timelineItems.first().identifier() == timelineItem.identifier(),
highlightedItem = state.highlightedEventId?.value,
@@ -156,6 +164,7 @@ fun TimelineView(
TimelineScrollHelper(
isTimelineEmpty = state.timelineItems.isEmpty(),
lazyListState = lazyListState,
+ forceJumpToBottomVisibility = forceJumpToBottomVisibility,
newEventState = state.newEventState,
onScrollFinishedAt = ::onScrollFinishedAt
)
@@ -167,6 +176,7 @@ private fun BoxScope.TimelineScrollHelper(
isTimelineEmpty: Boolean,
lazyListState: LazyListState,
newEventState: NewEventState,
+ forceJumpToBottomVisibility: Boolean,
onScrollFinishedAt: (Int) -> Unit,
) {
val coroutineScope = rememberCoroutineScope()
@@ -204,7 +214,7 @@ private fun BoxScope.TimelineScrollHelper(
JumpToBottomButton(
// Use inverse of canAutoScroll otherwise we might briefly see the before the scroll animation is triggered
- isVisible = !canAutoScroll,
+ isVisible = !canAutoScroll || forceJumpToBottomVisibility,
modifier = Modifier
.align(Alignment.BottomEnd)
.padding(end = 24.dp, bottom = 12.dp),
@@ -220,7 +230,7 @@ private fun JumpToBottomButton(
) {
AnimatedVisibility(
modifier = modifier,
- visible = isVisible || LocalInspectionMode.current,
+ visible = isVisible,
enter = scaleIn(animationSpec = tween(100)),
exit = scaleOut(animationSpec = tween(100)),
) {
@@ -255,6 +265,7 @@ internal fun TimelineViewPreview(
TimelineView(
state = aTimelineState(timelineItems),
roomName = null,
+ typingNotificationState = aTypingNotificationState(),
onMessageClicked = {},
onTimestampClicked = {},
onUserDataClicked = {},
@@ -264,6 +275,7 @@ internal fun TimelineViewPreview(
onMoreReactionsClicked = {},
onSwipeToReply = {},
onReadReceiptClick = {},
+ forceJumpToBottomVisibility = true,
)
}
}
diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/ATimelineItemEventRow.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/ATimelineItemEventRow.kt
index a7c860f46e..a86095b3fc 100644
--- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/ATimelineItemEventRow.kt
+++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/ATimelineItemEventRow.kt
@@ -26,11 +26,13 @@ import io.element.android.features.messages.impl.timeline.model.TimelineItem
internal fun ATimelineItemEventRow(
event: TimelineItem.Event,
timelineRoomInfo: TimelineRoomInfo = aTimelineRoomInfo(),
+ renderReadReceipts: Boolean = false,
isLastOutgoingMessage: Boolean = false,
isHighlighted: Boolean = false,
) = TimelineItemEventRow(
event = event,
timelineRoomInfo = timelineRoomInfo,
+ renderReadReceipts = renderReadReceipts,
isLastOutgoingMessage = isLastOutgoingMessage,
isHighlighted = isHighlighted,
onClick = {},
diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/MessageEventBubble.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/MessageEventBubble.kt
index 14bd831efc..e7ca8116f1 100644
--- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/MessageEventBubble.kt
+++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/MessageEventBubble.kt
@@ -46,6 +46,8 @@ import io.element.android.libraries.designsystem.theme.components.Surface
import io.element.android.libraries.designsystem.theme.components.Text
import io.element.android.libraries.designsystem.theme.messageFromMeBackground
import io.element.android.libraries.designsystem.theme.messageFromOtherBackground
+import io.element.android.libraries.testtags.TestTags
+import io.element.android.libraries.testtags.testTag
private val BUBBLE_RADIUS = 12.dp
internal val BUBBLE_INCOMING_OFFSET = 16.dp
@@ -115,6 +117,7 @@ fun MessageEventBubble(
) {
Surface(
modifier = Modifier
+ .testTag(TestTags.messageBubble)
.widthIn(min = 80.dp)
.clip(bubbleShape)
.combinedClickable(
diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/MessagesReactionButton.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/MessagesReactionButton.kt
index 9b340eee67..fb10d03c39 100644
--- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/MessagesReactionButton.kt
+++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/MessagesReactionButton.kt
@@ -126,9 +126,8 @@ private val ADD_EMOJI_SIZE = 16.dp
@Composable
private fun TextContent(
text: String,
- modifier: Modifier = Modifier,
) = Text(
- modifier = modifier
+ modifier = Modifier
.height(REACTION_EMOJI_LINE_HEIGHT.toDp()),
text = text,
style = ElementTheme.typography.fontBodyMdRegular,
@@ -138,27 +137,24 @@ private fun TextContent(
@Composable
private fun IconContent(
@DrawableRes resourceId: Int,
- modifier: Modifier = Modifier
) = Icon(
resourceId = resourceId,
contentDescription = stringResource(id = R.string.screen_room_timeline_add_reaction),
tint = ElementTheme.materialColors.secondary,
- modifier = modifier
+ modifier = Modifier
.size(ADD_EMOJI_SIZE)
)
@Composable
private fun ReactionContent(
reaction: AggregatedReaction,
- modifier: Modifier = Modifier,
) = Row(
verticalAlignment = Alignment.CenterVertically,
- modifier = modifier,
) {
// Check if this is a custom reaction (MSC4027)
if (reaction.key.startsWith("mxc://")) {
AsyncImage(
- modifier = modifier
+ modifier = Modifier
.heightIn(min = REACTION_EMOJI_LINE_HEIGHT.toDp(), max = REACTION_EMOJI_LINE_HEIGHT.toDp())
.aspectRatio(REACTION_IMAGE_ASPECT_RATIO, false),
model = MediaRequestData(MediaSource(reaction.key), MediaRequestData.Kind.Content),
diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/TimelineItemEventRow.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/TimelineItemEventRow.kt
index 3e23114729..98200e77bd 100644
--- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/TimelineItemEventRow.kt
+++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/TimelineItemEventRow.kt
@@ -114,6 +114,7 @@ import kotlin.math.roundToInt
fun TimelineItemEventRow(
event: TimelineItem.Event,
timelineRoomInfo: TimelineRoomInfo,
+ renderReadReceipts: Boolean,
isLastOutgoingMessage: Boolean,
isHighlighted: Boolean,
onClick: () -> Unit,
@@ -126,7 +127,7 @@ fun TimelineItemEventRow(
onMoreReactionsClick: (eventId: TimelineItem.Event) -> Unit,
onReadReceiptClick: (event: TimelineItem.Event) -> Unit,
onSwipeToReply: () -> Unit,
- eventSink: (TimelineEvents) -> Unit,
+ eventSink: (TimelineEvents.EventFromTimelineItem) -> Unit,
modifier: Modifier = Modifier
) {
val coroutineScope = rememberCoroutineScope()
@@ -223,6 +224,7 @@ fun TimelineItemEventRow(
isLastOutgoingMessage = isLastOutgoingMessage,
receipts = event.readReceiptState.receipts,
),
+ renderReadReceipts = renderReadReceipts,
onReadReceiptsClicked = { onReadReceiptClick(event) },
modifier = Modifier.padding(top = 4.dp),
)
@@ -267,7 +269,7 @@ private fun TimelineItemEventRowContent(
onReactionLongClicked: (emoji: String) -> Unit,
onMoreReactionsClicked: (event: TimelineItem.Event) -> Unit,
onMentionClicked: (Mention) -> Unit,
- eventSink: (TimelineEvents) -> Unit,
+ eventSink: (TimelineEvents.EventFromTimelineItem) -> Unit,
modifier: Modifier = Modifier,
) {
fun ConstrainScope.linkStartOrEnd(event: TimelineItem.Event) = if (event.isMine) {
@@ -412,7 +414,7 @@ private fun MessageEventBubbleContent(
inReplyToClick: () -> Unit,
onTimestampClicked: () -> Unit,
onMentionClicked: (Mention) -> Unit,
- eventSink: (TimelineEvents) -> Unit,
+ eventSink: (TimelineEvents.EventFromTimelineItem) -> Unit,
@SuppressLint("ModifierParameter")
// need to rename this modifier to prevent linter false positives
@Suppress("ModifierNaming")
diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/TimelineItemEventRowWithRRPreview.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/TimelineItemEventRowWithRRPreview.kt
index 0e43e34670..85ff3a77bf 100644
--- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/TimelineItemEventRowWithRRPreview.kt
+++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/TimelineItemEventRowWithRRPreview.kt
@@ -47,6 +47,7 @@ internal fun TimelineItemEventRowWithRRPreview(
timelineItemReactions = aTimelineItemReactions(count = 0),
readReceiptState = TimelineItemReadReceipts(state.receipts),
),
+ renderReadReceipts = true,
isLastOutgoingMessage = false,
)
// A message from current user
@@ -60,6 +61,7 @@ internal fun TimelineItemEventRowWithRRPreview(
timelineItemReactions = aTimelineItemReactions(count = 0),
readReceiptState = TimelineItemReadReceipts(state.receipts),
),
+ renderReadReceipts = true,
isLastOutgoingMessage = false,
)
// Another message from current user
@@ -73,6 +75,7 @@ internal fun TimelineItemEventRowWithRRPreview(
timelineItemReactions = aTimelineItemReactions(count = 0),
readReceiptState = TimelineItemReadReceipts(state.receipts),
),
+ renderReadReceipts = true,
isLastOutgoingMessage = true,
)
}
diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/TimelineItemGroupedEventsRow.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/TimelineItemGroupedEventsRow.kt
index 5ca78adee6..a2a691cbcf 100644
--- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/TimelineItemGroupedEventsRow.kt
+++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/TimelineItemGroupedEventsRow.kt
@@ -43,6 +43,7 @@ import io.element.android.libraries.matrix.api.core.UserId
fun TimelineItemGroupedEventsRow(
timelineItem: TimelineItem.GroupedEvents,
timelineRoomInfo: TimelineRoomInfo,
+ renderReadReceipts: Boolean,
isLastOutgoingMessage: Boolean,
highlightedItem: String?,
sessionState: SessionState,
@@ -55,7 +56,7 @@ fun TimelineItemGroupedEventsRow(
onReactionLongClick: (key: String, TimelineItem.Event) -> Unit,
onMoreReactionsClick: (TimelineItem.Event) -> Unit,
onReadReceiptClick: (TimelineItem.Event) -> Unit,
- eventSink: (TimelineEvents) -> Unit,
+ eventSink: (TimelineEvents.EventFromTimelineItem) -> Unit,
modifier: Modifier = Modifier
) {
val isExpanded = rememberSaveable(key = timelineItem.identifier()) { mutableStateOf(false) }
@@ -70,6 +71,7 @@ fun TimelineItemGroupedEventsRow(
timelineItem = timelineItem,
timelineRoomInfo = timelineRoomInfo,
highlightedItem = highlightedItem,
+ renderReadReceipts = renderReadReceipts,
isLastOutgoingMessage = isLastOutgoingMessage,
sessionState = sessionState,
onClick = onClick,
@@ -93,6 +95,7 @@ private fun TimelineItemGroupedEventsRowContent(
timelineItem: TimelineItem.GroupedEvents,
timelineRoomInfo: TimelineRoomInfo,
highlightedItem: String?,
+ renderReadReceipts: Boolean,
isLastOutgoingMessage: Boolean,
sessionState: SessionState,
onClick: (TimelineItem.Event) -> Unit,
@@ -104,7 +107,7 @@ private fun TimelineItemGroupedEventsRowContent(
onReactionLongClick: (key: String, TimelineItem.Event) -> Unit,
onMoreReactionsClick: (TimelineItem.Event) -> Unit,
onReadReceiptClick: (TimelineItem.Event) -> Unit,
- eventSink: (TimelineEvents) -> Unit,
+ eventSink: (TimelineEvents.EventFromTimelineItem) -> Unit,
modifier: Modifier = Modifier,
) {
Column(modifier = modifier.animateContentSize()) {
@@ -124,6 +127,7 @@ private fun TimelineItemGroupedEventsRowContent(
TimelineItemRow(
timelineItem = subGroupEvent,
timelineRoomInfo = timelineRoomInfo,
+ renderReadReceipts = renderReadReceipts,
isLastOutgoingMessage = isLastOutgoingMessage,
highlightedItem = highlightedItem,
sessionState = sessionState,
@@ -141,13 +145,14 @@ private fun TimelineItemGroupedEventsRowContent(
)
}
}
- } else {
+ } else if (renderReadReceipts) {
TimelineItemReadReceiptView(
state = ReadReceiptViewState(
sendState = null,
isLastOutgoingMessage = false,
receipts = timelineItem.aggregatedReadReceipts,
),
+ renderReadReceipts = true,
onReadReceiptsClicked = onExpandGroupClick
)
}
@@ -163,6 +168,7 @@ internal fun TimelineItemGroupedEventsRowContentExpandedPreview() = ElementPrevi
timelineItem = aGroupedEvents(withReadReceipts = true),
timelineRoomInfo = aTimelineRoomInfo(),
highlightedItem = null,
+ renderReadReceipts = true,
isLastOutgoingMessage = false,
sessionState = aSessionState(),
onClick = {},
@@ -187,6 +193,7 @@ internal fun TimelineItemGroupedEventsRowContentCollapsePreview() = ElementPrevi
timelineItem = aGroupedEvents(withReadReceipts = true),
timelineRoomInfo = aTimelineRoomInfo(),
highlightedItem = null,
+ renderReadReceipts = true,
isLastOutgoingMessage = false,
sessionState = aSessionState(),
onClick = {},
diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/TimelineItemRow.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/TimelineItemRow.kt
index 2fe1080743..adf37d6d8f 100644
--- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/TimelineItemRow.kt
+++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/TimelineItemRow.kt
@@ -30,6 +30,7 @@ import io.element.android.libraries.matrix.api.core.UserId
internal fun TimelineItemRow(
timelineItem: TimelineItem,
timelineRoomInfo: TimelineRoomInfo,
+ renderReadReceipts: Boolean,
isLastOutgoingMessage: Boolean,
highlightedItem: String?,
sessionState: SessionState,
@@ -43,7 +44,7 @@ internal fun TimelineItemRow(
onReadReceiptClick: (TimelineItem.Event) -> Unit,
onTimestampClicked: (TimelineItem.Event) -> Unit,
onSwipeToReply: (TimelineItem.Event) -> Unit,
- eventSink: (TimelineEvents) -> Unit,
+ eventSink: (TimelineEvents.EventFromTimelineItem) -> Unit,
modifier: Modifier = Modifier
) {
when (timelineItem) {
@@ -58,6 +59,7 @@ internal fun TimelineItemRow(
if (timelineItem.content is TimelineItemStateContent) {
TimelineItemStateEventRow(
event = timelineItem,
+ renderReadReceipts = renderReadReceipts,
isLastOutgoingMessage = isLastOutgoingMessage,
isHighlighted = highlightedItem == timelineItem.identifier(),
onClick = { onClick(timelineItem) },
@@ -70,6 +72,7 @@ internal fun TimelineItemRow(
TimelineItemEventRow(
event = timelineItem,
timelineRoomInfo = timelineRoomInfo,
+ renderReadReceipts = renderReadReceipts,
isLastOutgoingMessage = isLastOutgoingMessage,
isHighlighted = highlightedItem == timelineItem.identifier(),
onClick = { onClick(timelineItem) },
@@ -91,6 +94,7 @@ internal fun TimelineItemRow(
TimelineItemGroupedEventsRow(
timelineItem = timelineItem,
timelineRoomInfo = timelineRoomInfo,
+ renderReadReceipts = renderReadReceipts,
isLastOutgoingMessage = isLastOutgoingMessage,
highlightedItem = highlightedItem,
sessionState = sessionState,
diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/TimelineItemStateEventRow.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/TimelineItemStateEventRow.kt
index 85eba29bc1..e0132ea75f 100644
--- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/TimelineItemStateEventRow.kt
+++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/TimelineItemStateEventRow.kt
@@ -47,12 +47,13 @@ import kotlinx.collections.immutable.toPersistentList
@Composable
fun TimelineItemStateEventRow(
event: TimelineItem.Event,
+ renderReadReceipts: Boolean,
isLastOutgoingMessage: Boolean,
isHighlighted: Boolean,
onClick: () -> Unit,
onLongClick: () -> Unit,
onReadReceiptsClick: (event: TimelineItem.Event) -> Unit,
- eventSink: (TimelineEvents) -> Unit,
+ eventSink: (TimelineEvents.EventFromTimelineItem) -> Unit,
modifier: Modifier = Modifier
) {
val interactionSource = remember { MutableInteractionSource() }
@@ -90,6 +91,7 @@ fun TimelineItemStateEventRow(
isLastOutgoingMessage = isLastOutgoingMessage,
receipts = event.readReceiptState.receipts,
),
+ renderReadReceipts = renderReadReceipts,
onReadReceiptsClicked = { onReadReceiptsClick(event) },
)
}
@@ -107,6 +109,7 @@ internal fun TimelineItemStateEventRowPreview() = ElementPreview {
receipts = listOf(aReadReceiptData(0)).toPersistentList(),
)
),
+ renderReadReceipts = true,
isLastOutgoingMessage = false,
isHighlighted = false,
onClick = {},
diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/event/TimelineItemEventContentView.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/event/TimelineItemEventContentView.kt
index e7dbf678af..d0aae12beb 100644
--- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/event/TimelineItemEventContentView.kt
+++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/event/TimelineItemEventContentView.kt
@@ -43,7 +43,7 @@ import io.element.android.libraries.architecture.Presenter
fun TimelineItemEventContentView(
content: TimelineItemEventContent,
onLinkClicked: (url: String) -> Unit,
- eventSink: (TimelineEvents) -> Unit,
+ eventSink: (TimelineEvents.EventFromTimelineItem) -> Unit,
modifier: Modifier = Modifier,
onContentLayoutChanged: (ContentAvoidingLayoutData) -> Unit = {},
) {
diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/event/TimelineItemPollView.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/event/TimelineItemPollView.kt
index 91dd5b99d3..47f4aa7da6 100644
--- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/event/TimelineItemPollView.kt
+++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/event/TimelineItemPollView.kt
@@ -31,7 +31,7 @@ import kotlinx.collections.immutable.toImmutableList
@Composable
fun TimelineItemPollView(
content: TimelineItemPollContent,
- eventSink: (TimelineEvents) -> Unit,
+ eventSink: (TimelineEvents.TimelineItemPollEvents) -> Unit,
modifier: Modifier = Modifier,
) {
fun onAnswerSelected(pollStartId: EventId, answerId: String) {
diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/reactionsummary/ReactionSummaryView.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/reactionsummary/ReactionSummaryView.kt
index e58f614234..c21d0deaa5 100644
--- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/reactionsummary/ReactionSummaryView.kt
+++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/reactionsummary/ReactionSummaryView.kt
@@ -26,6 +26,7 @@ import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.aspectRatio
import androidx.compose.foundation.layout.fillMaxHeight
+import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.heightIn
import androidx.compose.foundation.layout.padding
@@ -106,7 +107,6 @@ fun ReactionSummaryView(
@Composable
private fun SheetContent(
summary: ReactionSummaryState.Summary,
- modifier: Modifier = Modifier,
) {
val animationScope = rememberCoroutineScope()
var selectedReactionKey: String by rememberSaveable { mutableStateOf(summary.selectedKey) }
@@ -127,9 +127,8 @@ private fun SheetContent(
}
Column(
- modifier = modifier
- .fillMaxWidth()
- .fillMaxHeight()
+ modifier = Modifier
+ .fillMaxSize()
) {
LazyRow(
state = reactionListState,
@@ -172,7 +171,6 @@ private fun AggregatedReactionButton(
reaction: AggregatedReaction,
isHighlighted: Boolean,
onClick: () -> Unit,
- modifier: Modifier = Modifier,
) {
val buttonColor = if (isHighlighted) {
ElementTheme.colors.bgActionPrimaryRest
@@ -188,7 +186,7 @@ private fun AggregatedReactionButton(
val roundedCornerShape = RoundedCornerShape(corner = CornerSize(percent = 50))
Surface(
- modifier = modifier
+ modifier = Modifier
.background(buttonColor, roundedCornerShape)
.clip(roundedCornerShape)
.clickable(onClick = onClick)
@@ -238,10 +236,9 @@ private fun SenderRow(
name: String,
userId: String,
sentTime: String,
- modifier: Modifier = Modifier,
) {
Row(
- modifier = modifier
+ modifier = Modifier
.fillMaxWidth()
.heightIn(min = 56.dp)
.padding(start = 16.dp, top = 4.dp, end = 16.dp, bottom = 4.dp),
diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/receipt/TimelineItemReadReceiptView.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/receipt/TimelineItemReadReceiptView.kt
index b8f5dc3ca9..8f3d8f3710 100644
--- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/receipt/TimelineItemReadReceiptView.kt
+++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/receipt/TimelineItemReadReceiptView.kt
@@ -58,20 +58,23 @@ import kotlinx.collections.immutable.ImmutableList
@Composable
fun TimelineItemReadReceiptView(
state: ReadReceiptViewState,
+ renderReadReceipts: Boolean,
onReadReceiptsClicked: () -> Unit,
modifier: Modifier = Modifier,
) {
if (state.receipts.isNotEmpty()) {
- ReadReceiptsRow(modifier = modifier) {
- ReadReceiptsAvatars(
- receipts = state.receipts,
- modifier = Modifier
- .clip(RoundedCornerShape(4.dp))
- .clickable {
- onReadReceiptsClicked()
- }
- .padding(2.dp)
- )
+ if (renderReadReceipts) {
+ ReadReceiptsRow(modifier = modifier) {
+ ReadReceiptsAvatars(
+ receipts = state.receipts,
+ modifier = Modifier
+ .clip(RoundedCornerShape(4.dp))
+ .clickable {
+ onReadReceiptsClicked()
+ }
+ .padding(2.dp)
+ )
+ }
}
} else {
when (state.sendState) {
@@ -206,6 +209,7 @@ internal fun TimelineItemReactionsViewPreview(
) = ElementPreview {
TimelineItemReadReceiptView(
state = state,
+ renderReadReceipts = true,
onReadReceiptsClicked = {},
)
}
diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/debug/EventDebugInfoView.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/debug/EventDebugInfoView.kt
index 443451f565..72974b067c 100644
--- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/debug/EventDebugInfoView.kt
+++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/debug/EventDebugInfoView.kt
@@ -125,11 +125,10 @@ fun EventDebugInfoView(
private fun CollapsibleSection(
title: String,
text: String,
- modifier: Modifier = Modifier,
initiallyExpanded: Boolean = false,
) {
var isExpanded by remember { mutableStateOf(initiallyExpanded) }
- Column(modifier = modifier.fillMaxWidth()) {
+ Column(modifier = Modifier.fillMaxWidth()) {
Row(
modifier = Modifier
.clickable { isExpanded = !isExpanded }
diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/typing/MessagesViewWithTypingPreview.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/typing/MessagesViewWithTypingPreview.kt
new file mode 100644
index 0000000000..3dbc21cb15
--- /dev/null
+++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/typing/MessagesViewWithTypingPreview.kt
@@ -0,0 +1,46 @@
+/*
+ * 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.messages.impl.typing
+
+import androidx.compose.runtime.Composable
+import io.element.android.features.messages.impl.MessagesView
+import io.element.android.features.messages.impl.aMessagesState
+import io.element.android.libraries.designsystem.preview.ElementPreview
+import io.element.android.libraries.designsystem.preview.PreviewsDayNight
+
+@PreviewsDayNight
+@Composable
+internal fun MessagesViewWithTypingPreview() = ElementPreview {
+ MessagesView(
+ state = aMessagesState().copy(
+ typingNotificationState = aTypingNotificationState(
+ typingMembers = listOf(
+ aTypingRoomMember(displayName = "Alice"),
+ aTypingRoomMember(displayName = "Bob"),
+ ),
+ ),
+ ),
+ onBackPressed = {},
+ onRoomDetailsClicked = {},
+ onEventClicked = { false },
+ onPreviewAttachments = {},
+ onUserDataClicked = {},
+ onSendLocationClicked = {},
+ onCreatePollClicked = {},
+ onJoinCallClicked = {},
+ )
+}
diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/typing/TypingNotificationPresenter.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/typing/TypingNotificationPresenter.kt
new file mode 100644
index 0000000000..92cae4c4d9
--- /dev/null
+++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/typing/TypingNotificationPresenter.kt
@@ -0,0 +1,96 @@
+/*
+ * 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.messages.impl.typing
+
+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
+import androidx.compose.runtime.remember
+import io.element.android.features.preferences.api.store.SessionPreferencesStore
+import io.element.android.libraries.architecture.Presenter
+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.RoomMember
+import io.element.android.libraries.matrix.api.room.RoomMembershipState
+import io.element.android.libraries.matrix.api.room.roomMembers
+import kotlinx.collections.immutable.toImmutableList
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.flow.combine
+import kotlinx.coroutines.flow.distinctUntilChanged
+import kotlinx.coroutines.flow.launchIn
+import kotlinx.coroutines.flow.onEach
+import javax.inject.Inject
+
+class TypingNotificationPresenter @Inject constructor(
+ private val room: MatrixRoom,
+ private val sessionPreferencesStore: SessionPreferencesStore,
+) : Presenter {
+ @Composable
+ override fun present(): TypingNotificationState {
+ val typingMembersState = remember { mutableStateOf(emptyList()) }
+ val renderTypingNotifications by sessionPreferencesStore.isRenderTypingNotificationsEnabled().collectAsState(initial = true)
+ LaunchedEffect(renderTypingNotifications) {
+ if (renderTypingNotifications) {
+ observeRoomTypingMembers(typingMembersState)
+ } else {
+ typingMembersState.value = emptyList()
+ }
+ }
+
+ return TypingNotificationState(
+ renderTypingNotifications = renderTypingNotifications,
+ typingMembers = typingMembersState.value.toImmutableList(),
+ )
+ }
+
+ private fun CoroutineScope.observeRoomTypingMembers(typingMembersState: MutableState>) {
+ combine(room.roomTypingMembersFlow, room.membersStateFlow) { typingMembers, membersState ->
+ typingMembers
+ .map { userId ->
+ membersState.roomMembers()
+ ?.firstOrNull { roomMember -> roomMember.userId == userId }
+ ?: createDefaultRoomMemberForTyping(userId)
+ }
+ }
+ .distinctUntilChanged()
+ .onEach { members ->
+ typingMembersState.value = members
+ }
+ .launchIn(this)
+ }
+}
+
+/**
+ * Create a default [RoomMember] for typing events.
+ * In this case, only the userId will be used for rendering, other fields are not used, but keep them
+ * as close as possible to the actual data.
+ */
+private fun createDefaultRoomMemberForTyping(userId: UserId): RoomMember {
+ return RoomMember(
+ userId = userId,
+ displayName = null,
+ avatarUrl = null,
+ membership = RoomMembershipState.JOIN,
+ isNameAmbiguous = false,
+ powerLevel = 0,
+ normalizedPowerLevel = 0,
+ isIgnored = false,
+ )
+}
diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/typing/TypingNotificationState.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/typing/TypingNotificationState.kt
new file mode 100644
index 0000000000..380586f9c7
--- /dev/null
+++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/typing/TypingNotificationState.kt
@@ -0,0 +1,25 @@
+/*
+ * Copyright (c) 2024 New Vector Ltd
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package io.element.android.features.messages.impl.typing
+
+import io.element.android.libraries.matrix.api.room.RoomMember
+import kotlinx.collections.immutable.ImmutableList
+
+data class TypingNotificationState(
+ val renderTypingNotifications: Boolean,
+ val typingMembers: ImmutableList,
+)
diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/typing/TypingNotificationStateProvider.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/typing/TypingNotificationStateProvider.kt
new file mode 100644
index 0000000000..92d7e357d2
--- /dev/null
+++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/typing/TypingNotificationStateProvider.kt
@@ -0,0 +1,96 @@
+/*
+ * Copyright (c) 2023 New Vector Ltd
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package io.element.android.features.messages.impl.typing
+
+import androidx.compose.ui.tooling.preview.PreviewParameterProvider
+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 kotlinx.collections.immutable.toImmutableList
+
+class TypingNotificationStateProvider : PreviewParameterProvider {
+ override val values: Sequence
+ get() = sequenceOf(
+ aTypingNotificationState(),
+ aTypingNotificationState(
+ typingMembers = listOf(
+ aTypingRoomMember(),
+ ),
+ ),
+ aTypingNotificationState(
+ typingMembers = listOf(
+ aTypingRoomMember(displayName = "Alice"),
+ ),
+ ),
+ aTypingNotificationState(
+ typingMembers = listOf(
+ aTypingRoomMember(displayName = "Alice", isNameAmbiguous = true),
+ ),
+ ),
+ aTypingNotificationState(
+ typingMembers = listOf(
+ aTypingRoomMember(displayName = "Alice"),
+ aTypingRoomMember(displayName = "Bob"),
+ ),
+ ),
+ aTypingNotificationState(
+ typingMembers = listOf(
+ aTypingRoomMember(displayName = "Alice"),
+ aTypingRoomMember(displayName = "Bob"),
+ aTypingRoomMember(displayName = "Charlie"),
+ ),
+ ),
+ aTypingNotificationState(
+ typingMembers = listOf(
+ aTypingRoomMember(displayName = "Alice"),
+ aTypingRoomMember(displayName = "Bob"),
+ aTypingRoomMember(displayName = "Charlie"),
+ aTypingRoomMember(displayName = "Dan"),
+ aTypingRoomMember(displayName = "Eve"),
+ ),
+ ),
+ aTypingNotificationState(
+ typingMembers = listOf(
+ aTypingRoomMember(displayName = "Alice with a very long display name which means that it will be truncated"),
+ ),
+ ),
+ )
+}
+
+internal fun aTypingNotificationState(
+ typingMembers: List = emptyList(),
+) = TypingNotificationState(
+ renderTypingNotifications = true,
+ typingMembers = typingMembers.toImmutableList(),
+)
+
+internal fun aTypingRoomMember(
+ userId: UserId = UserId("@alice:example.com"),
+ displayName: String? = null,
+ isNameAmbiguous: Boolean = false,
+): RoomMember {
+ return RoomMember(
+ userId = userId,
+ displayName = displayName,
+ avatarUrl = null,
+ membership = RoomMembershipState.JOIN,
+ isNameAmbiguous = isNameAmbiguous,
+ powerLevel = 0,
+ normalizedPowerLevel = 0,
+ isIgnored = false,
+ )
+}
diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/typing/TypingNotificationView.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/typing/TypingNotificationView.kt
new file mode 100644
index 0000000000..47200132d8
--- /dev/null
+++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/typing/TypingNotificationView.kt
@@ -0,0 +1,104 @@
+/*
+ * 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.messages.impl.typing
+
+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.res.pluralStringResource
+import androidx.compose.ui.res.stringResource
+import androidx.compose.ui.text.AnnotatedString
+import androidx.compose.ui.text.SpanStyle
+import androidx.compose.ui.text.buildAnnotatedString
+import androidx.compose.ui.text.font.FontWeight
+import androidx.compose.ui.text.style.TextOverflow
+import androidx.compose.ui.text.withStyle
+import androidx.compose.ui.tooling.preview.PreviewParameter
+import androidx.compose.ui.unit.dp
+import io.element.android.compound.theme.ElementTheme
+import io.element.android.features.messages.impl.R
+import io.element.android.libraries.designsystem.preview.ElementPreview
+import io.element.android.libraries.designsystem.preview.PreviewsDayNight
+import io.element.android.libraries.designsystem.theme.components.Text
+import io.element.android.libraries.matrix.api.room.RoomMember
+import kotlinx.collections.immutable.ImmutableList
+
+@Composable
+fun TypingNotificationView(
+ state: TypingNotificationState,
+ modifier: Modifier = Modifier,
+) {
+ if (state.typingMembers.isEmpty() || !state.renderTypingNotifications) return
+ val typingNotificationText = computeTypingNotificationText(state.typingMembers)
+ Text(
+ modifier = modifier
+ .fillMaxWidth()
+ .padding(horizontal = 24.dp, vertical = 2.dp),
+ text = typingNotificationText,
+ overflow = TextOverflow.Ellipsis,
+ maxLines = 1,
+ style = ElementTheme.typography.fontBodySmRegular,
+ color = ElementTheme.colors.textSecondary,
+ )
+}
+
+@Composable
+private fun computeTypingNotificationText(typingMembers: ImmutableList): AnnotatedString {
+ val names = when (typingMembers.size) {
+ 0 -> "" // Cannot happen
+ 1 -> typingMembers[0].disambiguatedDisplayName
+ 2 -> stringResource(
+ id = R.string.screen_room_typing_two_members,
+ typingMembers[0].disambiguatedDisplayName,
+ typingMembers[1].disambiguatedDisplayName,
+ )
+ else -> pluralStringResource(
+ id = R.plurals.screen_room_typing_many_members,
+ count = typingMembers.size - 2,
+ typingMembers[0].disambiguatedDisplayName,
+ typingMembers[1].disambiguatedDisplayName,
+ typingMembers.size - 2,
+ )
+ }
+ // Get the translated string with a fake pattern
+ val tmpString = pluralStringResource(
+ id = R.plurals.screen_room_typing_notification,
+ count = typingMembers.size,
+ "<>",
+ )
+ // Split the string in 3 parts
+ val parts = tmpString.split("<>")
+ // And rebuild the string with the names
+ return buildAnnotatedString {
+ append(parts[0])
+ withStyle(SpanStyle(fontWeight = FontWeight.Bold)) {
+ append(names)
+ }
+ append(parts[1])
+ }
+}
+
+@PreviewsDayNight
+@Composable
+internal fun TypingNotificationViewPreview(
+ @PreviewParameter(TypingNotificationStateProvider::class) state: TypingNotificationState,
+) = ElementPreview {
+ TypingNotificationView(
+ state = state,
+ )
+}
diff --git a/features/messages/impl/src/main/res/values-be/translations.xml b/features/messages/impl/src/main/res/values-be/translations.xml
new file mode 100644
index 0000000000..5bef3e7fac
--- /dev/null
+++ b/features/messages/impl/src/main/res/values-be/translations.xml
@@ -0,0 +1,62 @@
+
+
+ "Актыўнасці"
+ "Сцягі"
+ "Ежа & Напоі"
+ "Жывёлы & Прырода"
+ "Аб\'екты"
+ "Усмешкі & Людзі"
+ "Падарожжы & Месцы"
+ "Сімвалы"
+
+ - "%1$d змена ў пакоі"
+ - "%1$d змен у пакоі"
+ - "%1$d змен у пакоі"
+
+ "Гэтае паведамленне будзе перададзена адміністратару вашага хатняга сервера. Яны не змогуць прачытаць зашыфраваныя паведамленні."
+ "Прычына, па якой вы паскардзіліся на гэты змест"
+ "Гэта пачатак %1$s."
+ "Гэта пачатак гэтай размовы."
+ "Новы"
+ "Апавясціць увесь пакой"
+ "Адзначце, ці жадаеце вы схаваць усе бягучыя і будучыя паведамленні ад гэтага карыстальніка"
+ "Камера"
+ "Запісаць відэа"
+ "Далучэнне"
+ "Фота & Відэа Бібліятэка"
+ "Месцазнаходжанне"
+ "Апытанне"
+ "Фармаціраванне тэксту"
+ "Гісторыя паведамленняў зараз недаступна."
+ "Гісторыя паведамленняў у гэтым пакоі недаступная. Праверце гэтую прыладу, каб убачыць гісторыю паведамленняў."
+ "Не ўдалося атрымаць інфармацыю пра карыстальніка"
+ "Вы жадаеце запрасіць іх назад?"
+ "Вы адзін у гэтым чаце"
+ "Паведамленне скапіравана"
+ "У вас няма дазволу публікаваць паведамленні ў гэтым пакоі"
+ "Дазволіць карыстальніцкую наладу"
+ "Калі гэта ўключыць, ваша налада па змаўчанні будзе адменена"
+ "Апавяшчаць мяне ў гэтым чаце для"
+ "Вы можаце змяніць яго ў сваім %1$s."
+ "глабальныя налады"
+ "Налада па змаўчанні"
+ "Выдаліць карыстальніцкую наладу"
+ "Падчас загрузкі налад апавяшчэнняў адбылася памылка."
+ "Не атрымалася аднавіць рэжым па змаўчанні, паспрабуйце яшчэ раз."
+ "Не ўдалося наладзіць рэжым, паспрабуйце яшчэ раз."
+ "Ваш хатні сервер не падтрымлівае гэту опцыю ў зашыфраваных пакоях, вы не атрымаеце апавяшчэнне ў гэтым пакоі."
+ "Усе паведамленні"
+ "У гэтым пакоі паведаміце мяне пра"
+ "Паказаць менш"
+ "Паказаць больш"
+ "Адправіць зноў"
+ "Не ўдалося адправіць ваша паведамленне"
+ "Дадаць эмодзі"
+ "Паказаць менш"
+ "Утрымлівайце для запісу"
+ "Усе"
+ "Заблакіраваць карыстальніка"
+ "Зрабіць фота"
+ "Не атрымалася апрацаваць медыяфайл для загрузкі, паспрабуйце яшчэ раз."
+ "Толькі згадванні і ключавыя словы"
+
diff --git a/features/messages/impl/src/main/res/values-cs/translations.xml b/features/messages/impl/src/main/res/values-cs/translations.xml
index 62a5ceb29b..bad37ba26b 100644
--- a/features/messages/impl/src/main/res/values-cs/translations.xml
+++ b/features/messages/impl/src/main/res/values-cs/translations.xml
@@ -13,6 +13,16 @@
- "%1$d změny místnosti"
- "%1$d změn místnosti"
+
+ - "%1$s, %2$s a %3$d další"
+ - "%1$s, %2$s a %3$d další"
+ - "%1$s, %2$s a %3$d dalších"
+
+
+ - "%1$s píše"
+ - "%1$s píší"
+ - "%1$s píše"
+
"Tato zpráva bude nahlášena správci vašeho domovského serveru. Nebude si moci přečíst žádné šifrované zprávy."
"Důvod nahlášení tohoto obsahu"
"Toto je začátek %1$s."
@@ -21,7 +31,6 @@
"Informujte celou místnost"
"Zaškrtněte, pokud chcete skrýt všechny aktuální a budoucí zprávy od tohoto uživatele"
"Fotoaparát"
- "Vyfotit"
"Natočit video"
"Příloha"
"Knihovna fotografií a videí"
@@ -54,9 +63,11 @@
"Vaši zprávu se nepodařilo odeslat"
"Přidat emoji"
"Zobrazit méně"
+ "%1$s a %2$s"
"Držte pro nahrávání"
"Všichni"
"Zablokovat uživatele"
+ "Vyfotit"
"Nahrání média se nezdařilo, zkuste to prosím znovu."
"Pouze zmínky a klíčová slova"
diff --git a/features/messages/impl/src/main/res/values-de/translations.xml b/features/messages/impl/src/main/res/values-de/translations.xml
index 2ecb2a31a8..1bf50dae29 100644
--- a/features/messages/impl/src/main/res/values-de/translations.xml
+++ b/features/messages/impl/src/main/res/values-de/translations.xml
@@ -12,6 +12,14 @@
- "%1$d Raumänderung"
- "%1$d Raumänderungen"
+
+ - "%1$s, %2$s und %3$d weitere Person"
+ - "%1$s, %2$s und %3$d weitere Person"
+
+
+ - "%1$s schreibt…"
+ - "%1$s schreiben…"
+
"Diese Meldung wird an den Administrator deines Homeservers weitergeleitet. Dieser kann keine verschlüsselten Nachrichten lesen."
"Grund für die Meldung dieses Inhalts"
"Dies ist der Anfang von %1$s."
@@ -20,7 +28,6 @@
"Den ganzen Raum benachrichtigen"
"Prüfe, ob du alle aktuellen und zukünftigen Nachrichten dieses Benutzers ausblenden möchtest"
"Kamera"
- "Foto aufnehmen"
"Video aufnehmen"
"Anhang"
"Foto- und Videobibliothek"
@@ -53,9 +60,11 @@
"Deine Nachricht konnte nicht gesendet werden"
"Emoji hinzufügen"
"Weniger anzeigen"
+ "%1$s und %2$s"
"Zum Aufnehmen gedrückt halten"
"Alle"
"Benutzer blockieren"
+ "Foto aufnehmen"
"Fehler beim Verarbeiten des hochgeladenen Mediums. Bitte versuche es erneut."
"Nur Erwähnungen und Schlüsselwörter"
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 02710138f4..d61d7c1c5a 100644
--- a/features/messages/impl/src/main/res/values-es/translations.xml
+++ b/features/messages/impl/src/main/res/values-es/translations.xml
@@ -20,7 +20,6 @@
"Notificar a toda la sala"
"Marque si quieres ocultar todos los mensajes actuales y futuros de este usuario"
"Cámara"
- "Hacer foto"
"Grabar video"
"Archivo adjunto"
"Biblioteca de fotos y vídeos"
@@ -56,6 +55,7 @@
"Mantén pulsado para grabar"
"Todos"
"Bloquear usuario"
+ "Hacer foto"
"Error al procesar el contenido multimedia, por favor inténtalo de nuevo."
"Únicamente Menciones y Palabras clave"
diff --git a/features/messages/impl/src/main/res/values-fr/translations.xml b/features/messages/impl/src/main/res/values-fr/translations.xml
index 1358ce802b..e6f6f0e0d7 100644
--- a/features/messages/impl/src/main/res/values-fr/translations.xml
+++ b/features/messages/impl/src/main/res/values-fr/translations.xml
@@ -12,6 +12,14 @@
- "%1$d changement dans le salon"
- "%1$d changements dans le salon"
+
+ - "%1$s, %2$s et %3$d autre"
+ - "%1$s, %2$s et %3$d autres"
+
+
+ - "%1$s écrit"
+ - "%1$s écrivent"
+
"Ce message sera signalé à l’administrateur de votre serveur d’accueil. Il ne pourra lire aucun message chiffré."
"Raison du signalement de ce contenu"
"Ceci est le début de %1$s."
@@ -20,7 +28,6 @@
"Notifier tout le salon"
"Cochez si vous souhaitez masquer tous les messages actuels et futurs de cet utilisateur."
"Appareil photo"
- "Prendre une photo"
"Enregistrer une vidéo"
"Pièce jointe"
"Galerie Photo et Vidéo"
@@ -53,9 +60,11 @@
"Votre message n’a pas pu être envoyé"
"Ajouter un émoji"
"Afficher moins"
+ "%1$s et %2$s"
"Maintenir pour enregistrer"
"Tout le monde"
"Bloquer l’utilisateur"
+ "Prendre une photo"
"Échec du traitement des médias à télécharger, veuillez réessayer."
"Mentions et mots clés uniquement"
diff --git a/features/messages/impl/src/main/res/values-hu/translations.xml b/features/messages/impl/src/main/res/values-hu/translations.xml
index 4917430141..4f260a2fc4 100644
--- a/features/messages/impl/src/main/res/values-hu/translations.xml
+++ b/features/messages/impl/src/main/res/values-hu/translations.xml
@@ -12,15 +12,22 @@
- "%1$d szobaváltozás"
- "%1$d szobaváltozás"
+
+ - "%1$s, %2$s és %3$d további felhasználó"
+ - "%1$s, %2$s és %3$d további felhasználó"
+
+
+ - "%1$s éppen ír…"
+ - "%1$s éppen ír…"
+
"Ez az üzenet jelentve lesz a Matrix-kiszolgáló rendszergazdájának. Nem fogja tudni elolvasni a titkosított üzeneteket."
"A tartalom jelentésének oka"
"Ez a(z) %1$s kezdete."
"Ez a beszélgetés kezdete."
"Új"
- "Teljes szoba értesítése"
+ "Az egész szoba értesítése"
"Jelölje be, ha el akarja rejteni az összes jelenlegi és jövőbeli üzenetet ettől a felhasználótól"
"Kamera"
- "Fénykép készítése"
"Videó rögzítése"
"Melléklet"
"Fénykép- és videótár"
@@ -53,9 +60,11 @@
"Az üzenet elküldése sikertelen"
"Emodzsi hozzáadása"
"Kevesebb megjelenítése"
+ "%1$s és %2$s"
"Tartsa a rögzítéshez"
"Mindenki"
"Felhasználó letiltása"
+ "Fénykép készítése"
"Nem sikerült feldolgozni a feltöltendő médiát, próbálja újra."
"Csak említések és kulcsszavak"
diff --git a/features/messages/impl/src/main/res/values-in/translations.xml b/features/messages/impl/src/main/res/values-in/translations.xml
index 3e792da48f..af2a60da68 100644
--- a/features/messages/impl/src/main/res/values-in/translations.xml
+++ b/features/messages/impl/src/main/res/values-in/translations.xml
@@ -19,7 +19,6 @@
"Beri tahu seluruh ruangan"
"Centang jika Anda ingin menyembunyikan semua pesan saat ini dan yang akan datang dari pengguna ini"
"Kamera"
- "Ambil foto"
"Rekam video"
"Lampiran"
"Pustaka Foto & Video"
@@ -55,6 +54,7 @@
"Tahan untuk merekam"
"Semua orang"
"Blokir pengguna"
+ "Ambil foto"
"Gagal memproses media untuk diunggah, silakan coba lagi."
"Sebutan dan Kata Kunci saja"
diff --git a/features/messages/impl/src/main/res/values-it/translations.xml b/features/messages/impl/src/main/res/values-it/translations.xml
index 0dd03afae2..9bccc57825 100644
--- a/features/messages/impl/src/main/res/values-it/translations.xml
+++ b/features/messages/impl/src/main/res/values-it/translations.xml
@@ -12,6 +12,14 @@
- "%1$d modifica alla stanza"
- "%1$d modifiche alla stanza"
+
+ - "%1$s, %2$s e %3$d altro"
+ - "%1$s, %2$s e altri %3$d"
+
+
+ - "%1$s sta scrivendo"
+ - "%1$s stanno scrivendo"
+
"Questo messaggio verrà segnalato all\'amministratore dell\'homeserver. Questi non sarà in grado di leggere i messaggi criptati."
"Motivo della segnalazione di questo contenuto"
"Questo è l\'inizio di %1$s."
@@ -20,7 +28,6 @@
"Avvisa l\'intera stanza"
"Seleziona se vuoi nascondere tutti i messaggi attuali e futuri di questo utente"
"Fotocamera"
- "Scatta foto"
"Registra video"
"Allegato"
"Libreria di foto e video"
@@ -53,9 +60,11 @@
"Il tuo messaggio non è stato inviato"
"Aggiungi emoji"
"Mostra meno"
+ "%1$s e %2$s"
"Tieni premuto per registrare"
"Tutti"
"Blocca utente"
+ "Scatta foto"
"Elaborazione del file multimediale da caricare fallita, riprova."
"Solo menzioni e parole chiave"
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 c15a465976..07b43375af 100644
--- a/features/messages/impl/src/main/res/values-ro/translations.xml
+++ b/features/messages/impl/src/main/res/values-ro/translations.xml
@@ -20,7 +20,6 @@
"Nou"
"Confirmați că doriți să ascundeți toate mesajele curente și viitoare de la acest utilizator"
"Cameră foto"
- "Faceți o fotografie"
"Înregistrați un videoclip"
"Atașament"
"Bibliotecă foto și video"
@@ -52,6 +51,7 @@
"Adăugați emoji"
"Afișați mai puțin"
"Blocați utilizatorul"
+ "Faceți o fotografie"
"Procesarea datelor media a eșuat, vă rugăm să încercați din nou."
"Numai mențiuni și cuvinte cheie"
diff --git a/features/messages/impl/src/main/res/values-ru/translations.xml b/features/messages/impl/src/main/res/values-ru/translations.xml
index c3175d9a53..8d797c6b09 100644
--- a/features/messages/impl/src/main/res/values-ru/translations.xml
+++ b/features/messages/impl/src/main/res/values-ru/translations.xml
@@ -13,6 +13,16 @@
- "%1$d изменения в комнате"
- "%1$d изменений в комнате"
+
+ - "%1$s, %2$s и %3$d"
+ - "%1$s, %2$s и другие %3$d"
+ - "%1$s, %2$s и другие %3$d"
+
+
+ - "%1$s набирает сообщение"
+ - "%1$s набирают сообщения"
+ - "%1$s набирают сообщения"
+
"Это сообщение будет передано администратору вашего домашнего сервера. Они не смогут прочитать зашифрованные сообщения."
"Причина, по которой вы пожаловались на этот контент"
"Это начало %1$s."
@@ -21,7 +31,6 @@
"Уведомить всю комнату"
"Отметьте, хотите ли вы скрыть все текущие и будущие сообщения от этого пользователя"
"Камера"
- "Сделать фото"
"Записать видео"
"Вложение"
"Фото и видео"
@@ -54,9 +63,11 @@
"Не удалось отправить ваше сообщение"
"Добавить эмодзи"
"Показать меньше"
+ "%1$s и %2$s"
"Удерживайте для записи"
"Для всех"
"Заблокировать пользователя"
+ "Сделать фото"
"Не удалось обработать медиафайл для загрузки, попробуйте еще раз."
"Только упоминания и ключевые слова"
diff --git a/features/messages/impl/src/main/res/values-sk/translations.xml b/features/messages/impl/src/main/res/values-sk/translations.xml
index 0bdf008fc2..b4dc86aa86 100644
--- a/features/messages/impl/src/main/res/values-sk/translations.xml
+++ b/features/messages/impl/src/main/res/values-sk/translations.xml
@@ -13,6 +13,16 @@
- "%1$d zmeny miestnosti"
- "%1$d zmien miestnosti"
+
+ - "%1$s, %2$s a %3$d ďalší"
+ - "%1$s, %2$s a %3$d ďalší"
+ - "%1$s, %2$s a %3$d ďalší"
+
+
+ - "%1$s píše"
+ - "%1$s píšu"
+ - "%1$s píšu"
+
"Táto správa bude nahlásená správcovi vášho domovského servera. Nebude môcť prečítať žiadne šifrované správy."
"Dôvod nahlásenia tohto obsahu"
"Toto je začiatok %1$s."
@@ -21,7 +31,6 @@
"Informovať celú miestnosť"
"Označte, či chcete skryť všetky aktuálne a budúce správy od tohto používateľa"
"Kamera"
- "Odfotiť"
"Nahrať video"
"Príloha"
"Knižnica fotografií a videí"
@@ -54,9 +63,11 @@
"Vašu správu sa nepodarilo odoslať"
"Pridať emoji"
"Zobraziť menej"
+ "%1$s a %2$s"
"Podržaním nahrajte"
"Všetci"
"Zablokovať používateľa"
+ "Urobiť fotku"
"Nepodarilo sa spracovať médiá na odoslanie, skúste to prosím znova."
"Iba zmienky a kľúčové slová"
diff --git a/features/messages/impl/src/main/res/values-zh-rTW/translations.xml b/features/messages/impl/src/main/res/values-zh-rTW/translations.xml
index 4f75bf4b0d..71ca37eed4 100644
--- a/features/messages/impl/src/main/res/values-zh-rTW/translations.xml
+++ b/features/messages/impl/src/main/res/values-zh-rTW/translations.xml
@@ -14,7 +14,6 @@
"檢舉這個內容的原因"
"新訊息"
"照相機"
- "拍照"
"錄影"
"附件"
"照片與影片庫"
@@ -38,5 +37,6 @@
"較少"
"所有人"
"封鎖使用者"
+ "拍照"
"僅限提及與關鍵字"
diff --git a/features/messages/impl/src/main/res/values/localazy.xml b/features/messages/impl/src/main/res/values/localazy.xml
index d9c5fce030..ae91b144da 100644
--- a/features/messages/impl/src/main/res/values/localazy.xml
+++ b/features/messages/impl/src/main/res/values/localazy.xml
@@ -12,6 +12,14 @@
- "%1$d room change"
- "%1$d room changes"
+
+ - "%1$s, %2$s and %3$d other"
+ - "%1$s, %2$s and %3$d others"
+
+
+ - "%1$s is typing"
+ - "%1$s are typing"
+
"This message will be reported to your homeserver’s administrator. They will not be able to read any encrypted messages."
"Reason for reporting this content"
"This is the beginning of %1$s."
@@ -20,7 +28,6 @@
"Notify the whole room"
"Check if you want to hide all current and future messages from this user"
"Camera"
- "Take photo"
"Record video"
"Attachment"
"Photo & Video Library"
@@ -53,9 +60,11 @@
"Your message failed to send"
"Add emoji"
"Show less"
+ "%1$s and %2$s"
"Hold to record"
"Everyone"
"Block user"
+ "Take photo"
"Failed processing media to upload, please try again."
"Mentions and Keywords only"
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 1c10cb97e8..44dc96d804 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
@@ -42,6 +42,7 @@ import io.element.android.features.messages.impl.timeline.model.event.TimelineIt
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemTextContent
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemVideoContent
import io.element.android.features.messages.impl.timeline.model.event.aTimelineItemPollContent
+import io.element.android.features.messages.impl.typing.TypingNotificationPresenter
import io.element.android.features.messages.impl.voicemessages.composer.VoiceMessageComposerPlayer
import io.element.android.features.messages.impl.voicemessages.composer.VoiceMessageComposerPresenter
import io.element.android.features.messages.impl.voicemessages.timeline.FakeRedactedVoiceMessageManager
@@ -96,7 +97,9 @@ import io.element.android.tests.testutils.consumeItemsUntilTimeout
import io.element.android.tests.testutils.testCoroutineDispatchers
import io.mockk.mockk
import kotlinx.collections.immutable.persistentListOf
+import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.test.TestScope
+import kotlinx.coroutines.test.runCurrent
import kotlinx.coroutines.test.runTest
import org.junit.Rule
import org.junit.Test
@@ -129,6 +132,21 @@ class MessagesPresenterTest {
}
}
+ @OptIn(ExperimentalCoroutinesApi::class)
+ @Test
+ fun `present - check that the room is marked as read`() = runTest {
+ val room = FakeMatrixRoom()
+ assertThat(room.markAsReadCalls).isEmpty()
+ val presenter = createMessagesPresenter(matrixRoom = room)
+ moleculeFlow(RecompositionMode.Immediate) {
+ presenter.present()
+ }.test {
+ runCurrent()
+ assertThat(room.markAsReadCalls).isEqualTo(listOf(null))
+ cancelAndIgnoreRemainingEvents()
+ }
+ }
+
@Test
fun `present - call is disabled if user cannot join it even if there is an ongoing call`() = runTest {
val room = FakeMatrixRoom().apply {
@@ -675,6 +693,7 @@ class MessagesPresenterTest {
room = matrixRoom,
mediaPickerProvider = FakePickerProvider(),
featureFlagService = FakeFeatureFlagService(mapOf(FeatureFlags.NotificationSettings.key to true)),
+ sessionPreferencesStore = InMemorySessionPreferencesStore(),
localMediaFactory = FakeLocalMediaFactory(mockMediaUrl),
mediaSender = mediaSender,
snackbarDispatcher = SnackbarDispatcher(),
@@ -712,6 +731,10 @@ class MessagesPresenterTest {
}
}
val actionListPresenter = ActionListPresenter(appPreferencesStore = appPreferencesStore)
+ val typingNotificationPresenter = TypingNotificationPresenter(
+ room = matrixRoom,
+ sessionPreferencesStore = sessionPreferencesStore,
+ )
val readReceiptBottomSheetPresenter = ReadReceiptBottomSheetPresenter()
val customReactionPresenter = CustomReactionPresenter(emojibaseProvider = FakeEmojibaseProvider())
val reactionSummaryPresenter = ReactionSummaryPresenter(room = matrixRoom)
@@ -721,6 +744,7 @@ class MessagesPresenterTest {
composerPresenter = messageComposerPresenter,
voiceMessageComposerPresenter = voiceMessageComposerPresenter,
timelinePresenterFactory = timelinePresenterFactory,
+ typingNotificationPresenter = typingNotificationPresenter,
actionListPresenter = actionListPresenter,
customReactionPresenter = customReactionPresenter,
reactionSummaryPresenter = reactionSummaryPresenter,
diff --git a/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/MessagesViewTest.kt b/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/MessagesViewTest.kt
new file mode 100644
index 0000000000..449abc3f46
--- /dev/null
+++ b/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/MessagesViewTest.kt
@@ -0,0 +1,288 @@
+/*
+ * 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.messages.impl
+
+import androidx.activity.ComponentActivity
+import androidx.compose.runtime.CompositionLocalProvider
+import androidx.compose.ui.platform.LocalInspectionMode
+import androidx.compose.ui.test.junit4.AndroidComposeTestRule
+import androidx.compose.ui.test.junit4.createAndroidComposeRule
+import androidx.compose.ui.test.longClick
+import androidx.compose.ui.test.onAllNodesWithContentDescription
+import androidx.compose.ui.test.onAllNodesWithTag
+import androidx.compose.ui.test.onAllNodesWithText
+import androidx.compose.ui.test.onFirst
+import androidx.compose.ui.test.onNodeWithContentDescription
+import androidx.compose.ui.test.onNodeWithText
+import androidx.compose.ui.test.performClick
+import androidx.compose.ui.test.performTouchInput
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import io.element.android.features.messages.impl.actionlist.ActionListState
+import io.element.android.features.messages.impl.actionlist.anActionListState
+import io.element.android.features.messages.impl.actionlist.model.TimelineItemAction
+import io.element.android.features.messages.impl.attachments.Attachment
+import io.element.android.features.messages.impl.messagecomposer.aMessageComposerState
+import io.element.android.features.messages.impl.timeline.components.customreaction.CustomReactionEvents
+import io.element.android.features.messages.impl.timeline.components.reactionsummary.ReactionSummaryEvents
+import io.element.android.features.messages.impl.timeline.model.TimelineItem
+import io.element.android.libraries.matrix.api.core.UserId
+import io.element.android.libraries.testtags.TestTags
+import io.element.android.libraries.ui.strings.CommonStrings
+import io.element.android.tests.testutils.EnsureCalledOnceWithParam
+import io.element.android.tests.testutils.EnsureNeverCalled
+import io.element.android.tests.testutils.EnsureNeverCalledWithParam
+import io.element.android.tests.testutils.EnsureNeverCalledWithParamAndResult
+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.ensureCalledOnceWithParam
+import io.element.android.tests.testutils.pressBack
+import kotlinx.collections.immutable.ImmutableList
+import kotlinx.collections.immutable.persistentListOf
+import org.junit.Rule
+import org.junit.Test
+import org.junit.rules.TestRule
+import org.junit.runner.RunWith
+
+@RunWith(AndroidJUnit4::class)
+class MessagesViewTest {
+ @get:Rule val rule = createAndroidComposeRule()
+
+ @Test
+ fun `clicking on back invoke expected callback`() {
+ val eventsRecorder = EventsRecorder(expectEvents = false)
+ val state = aMessagesState(
+ eventSink = eventsRecorder
+ )
+ ensureCalledOnce { callback ->
+ rule.setMessagesView(
+ state = state,
+ onBackPressed = callback,
+ )
+ rule.pressBack()
+ }
+ }
+
+ @Test
+ fun `clicking on room name invoke expected callback`() {
+ val eventsRecorder = EventsRecorder(expectEvents = false)
+ val state = aMessagesState(
+ eventSink = eventsRecorder
+ )
+ ensureCalledOnce { callback ->
+ rule.setMessagesView(
+ state = state,
+ onRoomDetailsClicked = callback,
+ )
+ rule.onNodeWithText(state.roomName.dataOrNull().orEmpty()).performClick()
+ }
+ }
+
+ @Test
+ fun `clicking on join call invoke expected callback`() {
+ val eventsRecorder = EventsRecorder(expectEvents = false)
+ val state = aMessagesState(
+ eventSink = eventsRecorder
+ )
+ ensureCalledOnce { callback ->
+ rule.setMessagesView(
+ state = state,
+ onJoinCallClicked = callback,
+ )
+ val joinCallContentDescription = rule.activity.getString(CommonStrings.a11y_start_call)
+ rule.onNodeWithContentDescription(joinCallContentDescription).performClick()
+ }
+ }
+
+ @Test
+ fun `clicking on an Event invoke expected callback`() {
+ val eventsRecorder = EventsRecorder(expectEvents = false)
+ val state = aMessagesState(
+ eventSink = eventsRecorder
+ )
+ val timelineItem = state.timelineState.timelineItems.first()
+ val callback = EnsureCalledOnceWithParam(
+ expectedParam = timelineItem,
+ result = true,
+ )
+ rule.setMessagesView(
+ state = state,
+ onEventClicked = callback,
+ )
+ // Cannot perform click on "Text", it's not detected. Use tag instead
+ rule.onAllNodesWithTag(TestTags.messageBubble.value).onFirst().performClick()
+ callback.assertSuccess()
+ }
+
+ @Test
+ fun `clicking on send location invoke expected callback`() {
+ val eventsRecorder = EventsRecorder(expectEvents = false)
+ val state = aMessagesState(
+ composerState = aMessageComposerState(
+ showAttachmentSourcePicker = true
+ ),
+ eventSink = eventsRecorder
+ )
+ ensureCalledOnce { callback ->
+ rule.setMessagesView(
+ state = state,
+ onSendLocationClicked = callback,
+ )
+ rule.clickOn(R.string.screen_room_attachment_source_location)
+ }
+ }
+
+ @Test
+ fun `clicking on create poll invoke expected callback`() {
+ val eventsRecorder = EventsRecorder(expectEvents = false)
+ val state = aMessagesState(
+ composerState = aMessageComposerState(
+ showAttachmentSourcePicker = true
+ ),
+ eventSink = eventsRecorder
+ )
+ ensureCalledOnce { callback ->
+ rule.setMessagesView(
+ state = state,
+ onCreatePollClicked = callback,
+ )
+ // Then click on the poll action
+ rule.clickOn(R.string.screen_room_attachment_source_poll)
+ }
+ }
+
+ @Test
+ fun `clicking on the sender of an Event invoke expected callback`() {
+ val eventsRecorder = EventsRecorder(expectEvents = false)
+ val state = aMessagesState(
+ eventSink = eventsRecorder
+ )
+ val timelineItem = state.timelineState.timelineItems.first()
+ ensureCalledOnceWithParam(
+ param = (timelineItem as TimelineItem.Event).senderId
+ ) { callback ->
+ rule.setMessagesView(
+ state = state,
+ onUserDataClicked = callback,
+ )
+ val senderName = (timelineItem as? TimelineItem.Event)?.senderDisplayName.orEmpty()
+ rule.onNodeWithText(senderName).performClick()
+ }
+ }
+
+ @Test
+ fun `selecting a action on a message emits the expected Event`() {
+ val eventsRecorder = EventsRecorder()
+ val state = aMessagesState(
+ eventSink = eventsRecorder
+ )
+ val timelineItem = state.timelineState.timelineItems.first() as TimelineItem.Event
+ val stateWithMessageAction = state.copy(
+ actionListState = anActionListState(
+ target = ActionListState.Target.Success(
+ event = timelineItem,
+ displayEmojiReactions = true,
+ actions = persistentListOf(TimelineItemAction.Edit),
+ )
+ ),
+ )
+ rule.setMessagesView(
+ state = stateWithMessageAction,
+ )
+ rule.clickOn(CommonStrings.action_edit)
+ // Give time for the close animation to complete
+ rule.mainClock.advanceTimeBy(milliseconds = 1_000)
+ eventsRecorder.assertSingle(MessagesEvents.HandleAction(TimelineItemAction.Edit, timelineItem))
+ }
+
+ @Test
+ fun `clicking on a reaction emits the expected Event`() {
+ val eventsRecorder = EventsRecorder()
+ val state = aMessagesState(
+ eventSink = eventsRecorder
+ )
+ val timelineItem = state.timelineState.timelineItems.first() as TimelineItem.Event
+ rule.setMessagesView(
+ state = state,
+ )
+ rule.onAllNodesWithText("👍️").onFirst().performClick()
+ eventsRecorder.assertSingle(MessagesEvents.ToggleReaction("👍️", timelineItem.eventId!!))
+ }
+
+ @Test
+ fun `long clicking on a reaction emits the expected Event`() {
+ val eventsRecorder = EventsRecorder()
+ val state = aMessagesState(
+ reactionSummaryState = aReactionSummaryState(
+ target = null,
+ eventSink = eventsRecorder,
+ ),
+ )
+ val timelineItem = state.timelineState.timelineItems.first() as TimelineItem.Event
+ rule.setMessagesView(
+ state = state,
+ )
+ rule.onAllNodesWithText("👍️").onFirst().performTouchInput { longClick() }
+ eventsRecorder.assertSingle(ReactionSummaryEvents.ShowReactionSummary(timelineItem.eventId!!, timelineItem.reactionsState.reactions, "👍️"))
+ }
+
+ @Test
+ fun `clicking on more reaction emits the expected Event`() {
+ val eventsRecorder = EventsRecorder()
+ val state = aMessagesState(
+ customReactionState = aCustomReactionState(
+ eventSink = eventsRecorder,
+ ),
+ )
+ val timelineItem = state.timelineState.timelineItems.first() as TimelineItem.Event
+ rule.setMessagesView(
+ state = state,
+ )
+ val moreReactionContentDescription = rule.activity.getString(R.string.screen_room_timeline_add_reaction)
+ rule.onAllNodesWithContentDescription(moreReactionContentDescription).onFirst().performClick()
+ eventsRecorder.assertSingle(CustomReactionEvents.ShowCustomReactionSheet(timelineItem))
+ }
+}
+
+private fun AndroidComposeTestRule.setMessagesView(
+ state: MessagesState,
+ onBackPressed: () -> Unit = EnsureNeverCalled(),
+ onRoomDetailsClicked: () -> Unit = EnsureNeverCalled(),
+ onEventClicked: (event: TimelineItem.Event) -> Boolean = EnsureNeverCalledWithParamAndResult(),
+ onUserDataClicked: (UserId) -> Unit = EnsureNeverCalledWithParam(),
+ onPreviewAttachments: (ImmutableList) -> Unit = EnsureNeverCalledWithParam(),
+ onSendLocationClicked: () -> Unit = EnsureNeverCalled(),
+ onCreatePollClicked: () -> Unit = EnsureNeverCalled(),
+ onJoinCallClicked: () -> Unit = EnsureNeverCalled(),
+) {
+ setContent {
+ // Cannot use the RichTextEditor, so simulate a LocalInspectionMode
+ CompositionLocalProvider(LocalInspectionMode provides true) {
+ MessagesView(
+ state = state,
+ onBackPressed = onBackPressed,
+ onRoomDetailsClicked = onRoomDetailsClicked,
+ onEventClicked = onEventClicked,
+ onUserDataClicked = onUserDataClicked,
+ onPreviewAttachments = onPreviewAttachments,
+ onSendLocationClicked = onSendLocationClicked,
+ onCreatePollClicked = onCreatePollClicked,
+ onJoinCallClicked = onJoinCallClicked,
+ )
+ }
+ }
+}
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 d4b3c33cb1..c189e28c13 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
@@ -32,11 +32,13 @@ import io.element.android.features.messages.impl.messagecomposer.MessageComposer
import io.element.android.features.messages.impl.messagecomposer.MessageComposerEvents
import io.element.android.features.messages.impl.messagecomposer.MessageComposerPresenter
import io.element.android.features.messages.impl.messagecomposer.MessageComposerState
+import io.element.android.features.preferences.api.store.SessionPreferencesStore
import io.element.android.libraries.core.mimetype.MimeTypes
import io.element.android.libraries.designsystem.utils.snackbar.SnackbarDispatcher
import io.element.android.libraries.featureflag.api.FeatureFlagService
import io.element.android.libraries.featureflag.api.FeatureFlags
import io.element.android.libraries.featureflag.test.FakeFeatureFlagService
+import io.element.android.libraries.featureflag.test.InMemorySessionPreferencesStore
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.media.ImageInfo
@@ -888,6 +890,24 @@ class MessageComposerPresenterTest {
}
}
+ @Test
+ fun `present - handle typing notice event when sending typing notice is disabled`() = runTest {
+ val room = FakeMatrixRoom()
+ val store = InMemorySessionPreferencesStore(
+ isSendTypingNotificationsEnabled = false
+ )
+ val presenter = createPresenter(room = room, sessionPreferencesStore = store, coroutineScope = this)
+ moleculeFlow(RecompositionMode.Immediate) {
+ presenter.present()
+ }.test {
+ val initialState = awaitFirstItem()
+ assertThat(room.typingRecord).isEmpty()
+ initialState.eventSink.invoke(MessageComposerEvents.TypingNotice(true))
+ initialState.eventSink.invoke(MessageComposerEvents.TypingNotice(false))
+ assertThat(room.typingRecord).isEmpty()
+ }
+ }
+
private suspend fun ReceiveTurbine.backToNormalMode(state: MessageComposerState, skipCount: Int = 0): MessageComposerState {
state.eventSink.invoke(MessageComposerEvents.CloseSpecialMode)
skipItems(skipCount)
@@ -901,6 +921,7 @@ class MessageComposerPresenterTest {
room: MatrixRoom = FakeMatrixRoom(),
pickerProvider: PickerProvider = this.pickerProvider,
featureFlagService: FeatureFlagService = this.featureFlagService,
+ sessionPreferencesStore: SessionPreferencesStore = InMemorySessionPreferencesStore(),
mediaPreProcessor: MediaPreProcessor = this.mediaPreProcessor,
snackbarDispatcher: SnackbarDispatcher = this.snackbarDispatcher,
permissionPresenter: PermissionsPresenter = FakePermissionsPresenter(),
@@ -909,6 +930,7 @@ class MessageComposerPresenterTest {
room,
pickerProvider,
featureFlagService,
+ sessionPreferencesStore,
localMediaFactory,
MediaSender(mediaPreProcessor, room),
snackbarDispatcher,
diff --git a/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/timeline/TimelineViewTest.kt b/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/timeline/TimelineViewTest.kt
new file mode 100644
index 0000000000..78cd671e3f
--- /dev/null
+++ b/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/timeline/TimelineViewTest.kt
@@ -0,0 +1,86 @@
+/*
+ * 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.messages.impl.timeline
+
+import androidx.activity.ComponentActivity
+import androidx.compose.ui.test.junit4.createAndroidComposeRule
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import io.element.android.features.messages.impl.typing.aTypingNotificationState
+import io.element.android.tests.testutils.EnsureNeverCalledWithParam
+import io.element.android.tests.testutils.EnsureNeverCalledWithTwoParams
+import io.element.android.tests.testutils.EventsRecorder
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@RunWith(AndroidJUnit4::class)
+class TimelineViewTest {
+ @get:Rule val rule = createAndroidComposeRule()
+
+ @Test
+ fun `reaching the end of the timeline with more events to load emits a LoadMore event`() {
+ val eventsRecorder = EventsRecorder()
+ rule.setContent {
+ TimelineView(
+ aTimelineState(
+ eventSink = eventsRecorder,
+ paginationState = aPaginationState(
+ hasMoreToLoadBackwards = true,
+ )
+ ),
+ typingNotificationState = aTypingNotificationState(),
+ roomName = null,
+ onUserDataClicked = EnsureNeverCalledWithParam(),
+ onMessageClicked = EnsureNeverCalledWithParam(),
+ onMessageLongClicked = EnsureNeverCalledWithParam(),
+ onTimestampClicked = EnsureNeverCalledWithParam(),
+ onSwipeToReply = EnsureNeverCalledWithParam(),
+ onReactionClicked = EnsureNeverCalledWithTwoParams(),
+ onReactionLongClicked = EnsureNeverCalledWithTwoParams(),
+ onMoreReactionsClicked = EnsureNeverCalledWithParam(),
+ onReadReceiptClick = EnsureNeverCalledWithParam(),
+ )
+ }
+ eventsRecorder.assertSingle(TimelineEvents.LoadMore)
+ }
+
+ @Test
+ fun `reaching the end of the timeline does not send a LoadMore event`() {
+ val eventsRecorder = EventsRecorder(expectEvents = false)
+ rule.setContent {
+ TimelineView(
+ aTimelineState(
+ eventSink = eventsRecorder,
+ paginationState = aPaginationState(
+ hasMoreToLoadBackwards = false,
+ )
+ ),
+ typingNotificationState = aTypingNotificationState(),
+ roomName = null,
+ onUserDataClicked = EnsureNeverCalledWithParam(),
+ onMessageClicked = EnsureNeverCalledWithParam(),
+ onMessageLongClicked = EnsureNeverCalledWithParam(),
+ onTimestampClicked = EnsureNeverCalledWithParam(),
+ onSwipeToReply = EnsureNeverCalledWithParam(),
+ onReactionClicked = EnsureNeverCalledWithTwoParams(),
+ onReactionLongClicked = EnsureNeverCalledWithTwoParams(),
+ onMoreReactionsClicked = EnsureNeverCalledWithParam(),
+ onReadReceiptClick = EnsureNeverCalledWithParam(),
+ )
+ }
+ }
+}
diff --git a/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/timeline/components/event/TimelineItemPollViewTest.kt b/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/timeline/components/event/TimelineItemPollViewTest.kt
new file mode 100644
index 0000000000..4ea16a26b0
--- /dev/null
+++ b/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/timeline/components/event/TimelineItemPollViewTest.kt
@@ -0,0 +1,98 @@
+/*
+ * 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.messages.impl.timeline.components.event
+
+import androidx.activity.ComponentActivity
+import androidx.compose.ui.test.hasText
+import androidx.compose.ui.test.junit4.createAndroidComposeRule
+import androidx.compose.ui.test.performClick
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import io.element.android.features.messages.impl.timeline.TimelineEvents
+import io.element.android.features.messages.impl.timeline.model.event.aTimelineItemPollContent
+import io.element.android.libraries.testtags.TestTags
+import io.element.android.libraries.ui.strings.CommonStrings
+import io.element.android.tests.testutils.EventsRecorder
+import io.element.android.tests.testutils.clickOn
+import io.element.android.tests.testutils.pressTag
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@RunWith(AndroidJUnit4::class)
+class TimelineItemPollViewTest {
+ @get:Rule val rule = createAndroidComposeRule()
+
+ @Test
+ fun `answering a poll with first answer should emit a PollAnswerSelected event`() {
+ testAnswer(answerIndex = 0)
+ }
+
+ @Test
+ fun `answering a poll with second answer should emit a PollAnswerSelected event`() {
+ testAnswer(answerIndex = 1)
+ }
+
+ private fun testAnswer(answerIndex: Int) {
+ val eventsRecorder = EventsRecorder()
+ val content = aTimelineItemPollContent()
+ rule.setContent {
+ TimelineItemPollView(
+ content = content,
+ eventSink = eventsRecorder
+ )
+ }
+ val answer = content.answerItems[answerIndex].answer
+ rule.onNode(hasText(answer.text)).performClick()
+ eventsRecorder.assertSingle(TimelineEvents.PollAnswerSelected(content.eventId!!, answer.id))
+ }
+
+ @Test
+ fun `editing a poll should emit a PollEditClicked event`() {
+ val eventsRecorder = EventsRecorder()
+ val content = aTimelineItemPollContent(
+ isMine = true,
+ isEditable = true,
+ )
+ rule.setContent {
+ TimelineItemPollView(
+ content = content,
+ eventSink = eventsRecorder
+ )
+ }
+ rule.clickOn(CommonStrings.action_edit_poll)
+ eventsRecorder.assertSingle(TimelineEvents.PollEditClicked(content.eventId!!))
+ }
+
+ @Test
+ fun `closing a poll should emit a PollEndClicked event`() {
+ val eventsRecorder = EventsRecorder()
+ val content = aTimelineItemPollContent(
+ isMine = true,
+ )
+ rule.setContent {
+ TimelineItemPollView(
+ content = content,
+ eventSink = eventsRecorder
+ )
+ }
+ rule.clickOn(CommonStrings.action_end_poll)
+ // A confirmation dialog should be shown
+ eventsRecorder.assertEmpty()
+ rule.pressTag(TestTags.dialogPositive.value)
+ eventsRecorder.assertSingle(TimelineEvents.PollEndClicked(content.eventId!!))
+ }
+}
diff --git a/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/typing/TypingNotificationPresenterTest.kt b/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/typing/TypingNotificationPresenterTest.kt
new file mode 100644
index 0000000000..485c318e93
--- /dev/null
+++ b/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/typing/TypingNotificationPresenterTest.kt
@@ -0,0 +1,211 @@
+/*
+ * 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.messages.impl.typing
+
+import app.cash.molecule.RecompositionMode
+import app.cash.molecule.moleculeFlow
+import app.cash.turbine.test
+import com.google.common.truth.Truth.assertThat
+import io.element.android.features.preferences.api.store.SessionPreferencesStore
+import io.element.android.libraries.featureflag.test.InMemorySessionPreferencesStore
+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.RoomMember
+import io.element.android.libraries.matrix.api.room.RoomMembershipState
+import io.element.android.libraries.matrix.test.A_USER_ID
+import io.element.android.libraries.matrix.test.A_USER_ID_2
+import io.element.android.libraries.matrix.test.A_USER_ID_3
+import io.element.android.libraries.matrix.test.A_USER_ID_4
+import io.element.android.libraries.matrix.test.room.FakeMatrixRoom
+import io.element.android.libraries.matrix.test.room.aRoomInfo
+import io.element.android.tests.testutils.WarmUpRule
+import kotlinx.collections.immutable.toImmutableList
+import kotlinx.coroutines.test.runTest
+import org.junit.Rule
+import org.junit.Test
+
+@Suppress("LargeClass")
+class TypingNotificationPresenterTest {
+ @get:Rule
+ val warmUpRule = WarmUpRule()
+
+ @Test
+ fun `present - initial state`() = runTest {
+ val presenter = createPresenter()
+ moleculeFlow(RecompositionMode.Immediate) {
+ presenter.present()
+ }.test {
+ val initialState = awaitItem()
+ assertThat(initialState.renderTypingNotifications).isTrue()
+ assertThat(initialState.typingMembers).isEmpty()
+ }
+ }
+
+ @Test
+ fun `present - typing notification disabled`() = runTest {
+ val aDefaultRoomMember = createDefaultRoomMember(A_USER_ID_2)
+ val room = FakeMatrixRoom()
+ val sessionPreferencesStore = InMemorySessionPreferencesStore(
+ isRenderTypingNotificationsEnabled = false
+ )
+ val presenter = createPresenter(
+ matrixRoom = room,
+ sessionPreferencesStore = sessionPreferencesStore,
+ )
+ moleculeFlow(RecompositionMode.Immediate) {
+ presenter.present()
+ }.test {
+ skipItems(1)
+ val initialState = awaitItem()
+ assertThat(initialState.renderTypingNotifications).isFalse()
+ assertThat(initialState.typingMembers).isEmpty()
+ room.givenRoomTypingMembers(listOf(A_USER_ID_2))
+ expectNoEvents()
+ // Preferences changes
+ sessionPreferencesStore.setRenderTypingNotifications(true)
+ skipItems(1)
+ val oneMemberTypingState = awaitItem()
+ assertThat(oneMemberTypingState.renderTypingNotifications).isTrue()
+ assertThat(oneMemberTypingState.typingMembers.size).isEqualTo(1)
+ assertThat(oneMemberTypingState.typingMembers.first()).isEqualTo(aDefaultRoomMember)
+ // Preferences changes again
+ sessionPreferencesStore.setRenderTypingNotifications(false)
+ skipItems(1)
+ val finalState = awaitItem()
+ assertThat(finalState.renderTypingNotifications).isFalse()
+ assertThat(finalState.typingMembers).isEmpty()
+ }
+ }
+
+ @Test
+ fun `present - state is updated when a member is typing, member is not known`() = runTest {
+ val aDefaultRoomMember = createDefaultRoomMember(A_USER_ID_2)
+ val room = FakeMatrixRoom()
+ val presenter = createPresenter(matrixRoom = room)
+ moleculeFlow(RecompositionMode.Immediate) {
+ presenter.present()
+ }.test {
+ val initialState = awaitItem()
+ assertThat(initialState.typingMembers).isEmpty()
+ room.givenRoomTypingMembers(listOf(A_USER_ID_2))
+ val oneMemberTypingState = awaitItem()
+ assertThat(oneMemberTypingState.typingMembers.size).isEqualTo(1)
+ assertThat(oneMemberTypingState.typingMembers.first()).isEqualTo(aDefaultRoomMember)
+ // User stops typing
+ room.givenRoomTypingMembers(emptyList())
+ val finalState = awaitItem()
+ assertThat(finalState.typingMembers).isEmpty()
+ }
+ }
+
+ @Test
+ fun `present - state is updated when a member is typing, member is known`() = runTest {
+ val aKnownRoomMember = createKnownRoomMember(userId = A_USER_ID_2)
+ val room = FakeMatrixRoom().apply {
+ givenRoomMembersState(
+ MatrixRoomMembersState.Ready(
+ listOf(
+ createKnownRoomMember(A_USER_ID),
+ aKnownRoomMember,
+ createKnownRoomMember(A_USER_ID_3),
+ createKnownRoomMember(A_USER_ID_4),
+ ).toImmutableList()
+ )
+ )
+ }
+ val presenter = createPresenter(matrixRoom = room)
+ moleculeFlow(RecompositionMode.Immediate) {
+ presenter.present()
+ }.test {
+ val initialState = awaitItem()
+ assertThat(initialState.typingMembers).isEmpty()
+ room.givenRoomTypingMembers(listOf(A_USER_ID_2))
+ val oneMemberTypingState = awaitItem()
+ assertThat(oneMemberTypingState.typingMembers.size).isEqualTo(1)
+ assertThat(oneMemberTypingState.typingMembers.first()).isEqualTo(aKnownRoomMember)
+ // User stops typing
+ room.givenRoomTypingMembers(emptyList())
+ val finalState = awaitItem()
+ assertThat(finalState.typingMembers).isEmpty()
+ }
+ }
+
+ @Test
+ fun `present - state is updated when a member is typing, member is not known, then known`() = runTest {
+ val aDefaultRoomMember = createDefaultRoomMember(A_USER_ID_2)
+ val aKnownRoomMember = createKnownRoomMember(A_USER_ID_2)
+ val room = FakeMatrixRoom()
+ val presenter = createPresenter(matrixRoom = room)
+ moleculeFlow(RecompositionMode.Immediate) {
+ presenter.present()
+ }.test {
+ val initialState = awaitItem()
+ assertThat(initialState.typingMembers).isEmpty()
+ room.givenRoomTypingMembers(listOf(A_USER_ID_2))
+ val oneMemberTypingState = awaitItem()
+ assertThat(oneMemberTypingState.typingMembers.size).isEqualTo(1)
+ assertThat(oneMemberTypingState.typingMembers.first()).isEqualTo(aDefaultRoomMember)
+ // User is getting known
+ room.givenRoomMembersState(
+ MatrixRoomMembersState.Ready(
+ listOf(aKnownRoomMember).toImmutableList()
+ )
+ )
+ val finalState = awaitItem()
+ assertThat(finalState.typingMembers.first()).isEqualTo(aKnownRoomMember)
+ }
+ }
+
+ private fun createPresenter(
+ matrixRoom: MatrixRoom = FakeMatrixRoom().apply {
+ givenRoomInfo(aRoomInfo(id = roomId.value, name = ""))
+ },
+ sessionPreferencesStore: SessionPreferencesStore = InMemorySessionPreferencesStore(
+ isRenderTypingNotificationsEnabled = true
+ ),
+ ) = TypingNotificationPresenter(
+ room = matrixRoom,
+ sessionPreferencesStore = sessionPreferencesStore,
+ )
+
+ private fun createDefaultRoomMember(
+ userId: UserId,
+ ) = RoomMember(
+ userId = userId,
+ displayName = null,
+ avatarUrl = null,
+ membership = RoomMembershipState.JOIN,
+ isNameAmbiguous = false,
+ powerLevel = 0,
+ normalizedPowerLevel = 0,
+ isIgnored = false,
+ )
+
+ private fun createKnownRoomMember(
+ userId: UserId,
+ ) = RoomMember(
+ userId = userId,
+ displayName = "Alice Doe",
+ avatarUrl = "an_avatar_url",
+ membership = RoomMembershipState.JOIN,
+ isNameAmbiguous = true,
+ powerLevel = 0,
+ normalizedPowerLevel = 0,
+ isIgnored = false,
+ )
+}
diff --git a/features/networkmonitor/api/src/main/kotlin/io/element/android/features/networkmonitor/api/ui/ConnectivityIndicatorView.kt b/features/networkmonitor/api/src/main/kotlin/io/element/android/features/networkmonitor/api/ui/ConnectivityIndicatorView.kt
index 67721cab56..844f23f6c8 100644
--- a/features/networkmonitor/api/src/main/kotlin/io/element/android/features/networkmonitor/api/ui/ConnectivityIndicatorView.kt
+++ b/features/networkmonitor/api/src/main/kotlin/io/element/android/features/networkmonitor/api/ui/ConnectivityIndicatorView.kt
@@ -37,7 +37,6 @@ import io.element.android.libraries.designsystem.preview.PreviewsDayNight
@Composable
fun ConnectivityIndicatorView(
isOnline: Boolean,
- modifier: Modifier = Modifier,
) {
val isIndicatorVisible = remember { MutableTransitionState(!isOnline) }.apply { targetState = !isOnline }
val isStatusBarPaddingVisible = remember { MutableTransitionState(isOnline) }.apply { targetState = isOnline }
@@ -48,7 +47,7 @@ fun ConnectivityIndicatorView(
enter = fadeIn() + expandVertically(),
exit = fadeOut() + shrinkVertically(),
) {
- Indicator(modifier)
+ Indicator()
}
// Show missing status bar padding when the indicator is not visible
@@ -57,7 +56,7 @@ fun ConnectivityIndicatorView(
enter = fadeIn() + expandVertically(),
exit = fadeOut() + shrinkVertically(),
) {
- StatusBarPaddingSpacer(modifier)
+ StatusBarPaddingSpacer()
}
}
diff --git a/features/onboarding/impl/src/main/kotlin/io/element/android/features/onboarding/impl/OnBoardingView.kt b/features/onboarding/impl/src/main/kotlin/io/element/android/features/onboarding/impl/OnBoardingView.kt
index c4b4e2d6b4..a7073f8388 100644
--- a/features/onboarding/impl/src/main/kotlin/io/element/android/features/onboarding/impl/OnBoardingView.kt
+++ b/features/onboarding/impl/src/main/kotlin/io/element/android/features/onboarding/impl/OnBoardingView.kt
@@ -93,10 +93,9 @@ fun OnBoardingView(
private fun OnBoardingContent(
state: OnBoardingState,
onOpenDeveloperSettings: () -> Unit,
- modifier: Modifier = Modifier
) {
Box(
- modifier = modifier.fillMaxSize(),
+ modifier = Modifier.fillMaxSize(),
) {
Box(
modifier = Modifier.fillMaxSize(),
@@ -158,9 +157,8 @@ private fun OnBoardingButtons(
onSignIn: () -> Unit,
onCreateAccount: () -> Unit,
onReportProblem: () -> Unit,
- modifier: Modifier = Modifier,
) {
- ButtonColumnMolecule(modifier = modifier) {
+ ButtonColumnMolecule {
val signInButtonStringRes = if (state.canLoginWithQrCode || state.canCreateAccount) {
R.string.screen_onboarding_sign_in_manually
} else {
@@ -190,11 +188,10 @@ private fun OnBoardingButtons(
.fillMaxWidth()
)
}
- Spacer(modifier = Modifier.height(16.dp))
// Add a report problem text button. Use a Text since we need a special theme here.
Text(
modifier = Modifier
- .padding(8.dp)
+ .padding(16.dp)
.clickable(onClick = onReportProblem),
text = stringResource(id = CommonStrings.common_report_a_problem),
style = ElementTheme.typography.fontBodySmRegular,
diff --git a/features/onboarding/impl/src/main/res/values-be/translations.xml b/features/onboarding/impl/src/main/res/values-be/translations.xml
new file mode 100644
index 0000000000..f39880e97e
--- /dev/null
+++ b/features/onboarding/impl/src/main/res/values-be/translations.xml
@@ -0,0 +1,7 @@
+
+
+ "Увайдзіце ўручную"
+ "Увайдзіце з QR-кодам"
+ "Стварыць уліковы запіс"
+ "Сардэчна запрашаем у самы хуткі Element. Перавага ў хуткасці і прастаце."
+
diff --git a/features/poll/api/src/main/kotlin/io/element/android/features/poll/api/pollcontent/PollContentView.kt b/features/poll/api/src/main/kotlin/io/element/android/features/poll/api/pollcontent/PollContentView.kt
index 7b19c5da7e..63a5db3e0d 100644
--- a/features/poll/api/src/main/kotlin/io/element/android/features/poll/api/pollcontent/PollContentView.kt
+++ b/features/poll/api/src/main/kotlin/io/element/android/features/poll/api/pollcontent/PollContentView.kt
@@ -143,10 +143,8 @@ fun PollContentView(
private fun PollTitle(
title: String,
isPollEnded: Boolean,
- modifier: Modifier = Modifier
) {
Row(
- modifier = modifier,
horizontalArrangement = Arrangement.spacedBy(12.dp),
) {
if (isPollEnded) {
@@ -173,10 +171,9 @@ private fun PollTitle(
private fun PollAnswers(
answerItems: ImmutableList,
onAnswerSelected: (PollAnswer) -> Unit,
- modifier: Modifier = Modifier,
) {
Column(
- modifier = modifier.selectableGroup(),
+ modifier = Modifier.selectableGroup(),
verticalArrangement = Arrangement.spacedBy(16.dp),
) {
answerItems.forEach {
@@ -197,10 +194,9 @@ private fun PollAnswers(
@Composable
private fun ColumnScope.DisclosedPollBottomNotice(
votesCount: Int,
- modifier: Modifier = Modifier
) {
Text(
- modifier = modifier.align(Alignment.End),
+ modifier = Modifier.align(Alignment.End),
style = ElementTheme.typography.fontBodyXsRegular,
color = ElementTheme.colors.textSecondary,
text = stringResource(CommonStrings.common_poll_total_votes, votesCount),
@@ -208,11 +204,9 @@ private fun ColumnScope.DisclosedPollBottomNotice(
}
@Composable
-private fun ColumnScope.UndisclosedPollBottomNotice(
- modifier: Modifier = Modifier
-) {
+private fun ColumnScope.UndisclosedPollBottomNotice() {
Text(
- modifier = modifier
+ modifier = Modifier
.align(Alignment.Start)
.padding(start = 34.dp),
style = ElementTheme.typography.fontBodyXsRegular,
diff --git a/features/poll/impl/src/main/res/values-be/translations.xml b/features/poll/impl/src/main/res/values-be/translations.xml
new file mode 100644
index 0000000000..474de08d6e
--- /dev/null
+++ b/features/poll/impl/src/main/res/values-be/translations.xml
@@ -0,0 +1,19 @@
+
+
+ "Дадаць варыянт"
+ "Паказаць вынікі толькі пасля заканчэння апытання"
+ "Схаваць галасы"
+ "Варыянт %1$d"
+ "Вашы змены не былі захаваны. Вы ўпэўнены, што жадаеце вярнуцца?"
+ "Пытанне або тэма"
+ "Пра што апытанне?"
+ "Стварэнне апытання"
+ "Вы ўпэўнены, што жадаеце выдаліць гэтае апытанне?"
+ "Немагчыма знайсці бягучыя апытанні."
+ "Немагчыма знайсці мінулыя апытанні."
+ "Бягучыя"
+ "Мінулыя"
+ "Апытанні"
+ "Выдаліць апытанне"
+ "Рэдагаваць апытанне"
+
diff --git a/features/poll/impl/src/main/res/values-cs/translations.xml b/features/poll/impl/src/main/res/values-cs/translations.xml
index ac1ebfb8dd..43da9e54be 100644
--- a/features/poll/impl/src/main/res/values-cs/translations.xml
+++ b/features/poll/impl/src/main/res/values-cs/translations.xml
@@ -9,11 +9,11 @@
"Čeho se hlasování týká?"
"Vytvořit hlasování"
"Opravdu chcete odstranit toto hlasování?"
- "Odstranit hlasování"
- "Upravit hlasování"
"Nelze najít žádná probíhající hlasování."
"Nelze najít žádná minulá hlasování."
"Probíhající"
"Minulé"
"Hlasování"
+ "Odstranit hlasování"
+ "Upravit hlasování"
diff --git a/features/poll/impl/src/main/res/values-de/translations.xml b/features/poll/impl/src/main/res/values-de/translations.xml
index 99520079e6..3bdd314a8c 100644
--- a/features/poll/impl/src/main/res/values-de/translations.xml
+++ b/features/poll/impl/src/main/res/values-de/translations.xml
@@ -9,11 +9,11 @@
"Worum geht es bei der Umfrage?"
"Umfrage erstellen"
"Bist du dir sicher, dass du diese Umfrage löschen möchtest?"
- "Umfrage löschen"
- "Umfrage bearbeiten"
"Keine laufenden Umfragen vorhanden."
"Keine vergangenen Umfragen vorhanden."
"Aktuell"
"Vergangene"
"Umfragen"
+ "Umfrage löschen"
+ "Umfrage bearbeiten"
diff --git a/features/poll/impl/src/main/res/values-es/translations.xml b/features/poll/impl/src/main/res/values-es/translations.xml
index 2789740859..f48255bf31 100644
--- a/features/poll/impl/src/main/res/values-es/translations.xml
+++ b/features/poll/impl/src/main/res/values-es/translations.xml
@@ -9,11 +9,11 @@
"¿De qué trata la encuesta?"
"Crear una Encuesta"
"¿Seguro que quieres eliminar esta encuesta?"
- "Eliminar encuesta"
- "Editar encuesta"
"No se pudo encontrar ninguna encuesta en curso."
"No se pudo encontrar ninguna encuesta anterior."
"En curso"
"Anteriores"
"Encuestas"
+ "Eliminar encuesta"
+ "Editar encuesta"
diff --git a/features/poll/impl/src/main/res/values-fr/translations.xml b/features/poll/impl/src/main/res/values-fr/translations.xml
index 081b5e53b1..b8050c2067 100644
--- a/features/poll/impl/src/main/res/values-fr/translations.xml
+++ b/features/poll/impl/src/main/res/values-fr/translations.xml
@@ -9,11 +9,11 @@
"Quel est le sujet du sondage ?"
"Créer un sondage"
"Êtes-vous certain de vouloir supprimer ce sondage?"
- "Supprimer le sondage"
- "Modifier le sondage"
"Impossible de trouver des sondages en cours."
"Impossible de trouver des sondages terminés."
"En cours"
"Terminés"
"Sondages"
+ "Supprimer le sondage"
+ "Modifier le sondage"
diff --git a/features/poll/impl/src/main/res/values-hu/translations.xml b/features/poll/impl/src/main/res/values-hu/translations.xml
index 74b83c8942..142044c486 100644
--- a/features/poll/impl/src/main/res/values-hu/translations.xml
+++ b/features/poll/impl/src/main/res/values-hu/translations.xml
@@ -9,11 +9,11 @@
"Miről szól ez a szavazás?"
"Szavazás létrehozása"
"Biztos, hogy törli ezt a szavazást?"
- "Szavazás törlése"
- "Szavazás szerkesztése"
"Nem találhatók folyamatban lévő szavazások."
"Nem található korábbi szavazás."
"Folyamatban"
"Korábbi"
"Szavazások"
+ "Szavazás törlése"
+ "Szavazás szerkesztése"
diff --git a/features/poll/impl/src/main/res/values-in/translations.xml b/features/poll/impl/src/main/res/values-in/translations.xml
index f55dccd75d..c947c56295 100644
--- a/features/poll/impl/src/main/res/values-in/translations.xml
+++ b/features/poll/impl/src/main/res/values-in/translations.xml
@@ -9,11 +9,11 @@
"Tentang apa pemungutan suara ini?"
"Buat pemungutan suara"
"Apakah Anda yakin ingin menghapus pemungutan suara ini?"
- "Hapus pemungutan suara"
- "Sunting pemungutan suara"
"Tidak dapat menemukan pemungutan suara yang sedang berlangsung."
"Tidak dapat menemukan pemungutan suara sebelumnya."
"Sedang berlangsung"
"Masa lalu"
"Pemungutan suara"
+ "Hapus pemungutan suara"
+ "Sunting pemungutan suara"
diff --git a/features/poll/impl/src/main/res/values-it/translations.xml b/features/poll/impl/src/main/res/values-it/translations.xml
index bf7190db23..25a7cda088 100644
--- a/features/poll/impl/src/main/res/values-it/translations.xml
+++ b/features/poll/impl/src/main/res/values-it/translations.xml
@@ -9,11 +9,11 @@
"Di cosa parla il sondaggio?"
"Crea sondaggio"
"Vuoi davvero eliminare questo sondaggio?"
- "Elimina sondaggio"
- "Modifica sondaggio"
"Impossibile trovare sondaggi in corso."
"Impossibile trovare sondaggi passati."
"In corso"
"Passato"
"Sondaggi"
+ "Elimina sondaggio"
+ "Modifica sondaggio"
diff --git a/features/poll/impl/src/main/res/values-ru/translations.xml b/features/poll/impl/src/main/res/values-ru/translations.xml
index 2ed319bbeb..2035cc2988 100644
--- a/features/poll/impl/src/main/res/values-ru/translations.xml
+++ b/features/poll/impl/src/main/res/values-ru/translations.xml
@@ -9,11 +9,11 @@
"Тема опроса?"
"Создать опрос"
"Вы уверены, что хотите удалить этот опрос?"
- "Удалить опрос"
- "Редактировать опрос"
"Не найдено текущих опросов."
"Не найдено предыдущих опросов."
"Текущие"
"Прошлые"
"Опросы"
+ "Удалить опрос"
+ "Редактировать опрос"
diff --git a/features/poll/impl/src/main/res/values-sk/translations.xml b/features/poll/impl/src/main/res/values-sk/translations.xml
index cbc6b8582c..bb42d0d684 100644
--- a/features/poll/impl/src/main/res/values-sk/translations.xml
+++ b/features/poll/impl/src/main/res/values-sk/translations.xml
@@ -9,11 +9,11 @@
"O čom je anketa?"
"Vytvoriť anketu"
"Ste si istý, že chcete odstrániť túto anketu?"
- "Odstrániť anketu"
- "Upraviť anketu"
"Nepodarilo sa nájsť žiadne prebiehajúce ankety."
"Nie je možné nájsť žiadne predchádzajúce ankety."
"Prebiehajúce"
"Minulé"
"Ankety"
+ "Odstrániť anketu"
+ "Upraviť anketu"
diff --git a/features/poll/impl/src/main/res/values/localazy.xml b/features/poll/impl/src/main/res/values/localazy.xml
index 7a7a15ea3c..9c2ca6449c 100644
--- a/features/poll/impl/src/main/res/values/localazy.xml
+++ b/features/poll/impl/src/main/res/values/localazy.xml
@@ -9,11 +9,11 @@
"What is the poll about?"
"Create Poll"
"Are you sure you want to delete this poll?"
- "Delete Poll"
- "Edit poll"
"Can\'t find any ongoing polls."
"Can\'t find any past polls."
"Ongoing"
"Past"
"Polls"
+ "Delete Poll"
+ "Edit poll"
diff --git a/features/preferences/impl/build.gradle.kts b/features/preferences/impl/build.gradle.kts
index e6a605f5e4..ee0658ddc6 100644
--- a/features/preferences/impl/build.gradle.kts
+++ b/features/preferences/impl/build.gradle.kts
@@ -55,6 +55,7 @@ dependencies {
implementation(projects.features.analytics.api)
implementation(projects.features.ftue.api)
implementation(projects.features.logout.api)
+ implementation(projects.features.roomlist.api)
implementation(projects.services.analytics.api)
implementation(projects.services.toolbox.api)
implementation(libs.datetime)
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 d67a594dd2..8ee433f630 100644
--- a/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/advanced/AdvancedSettingsEvents.kt
+++ b/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/advanced/AdvancedSettingsEvents.kt
@@ -21,7 +21,7 @@ import io.element.android.compound.theme.Theme
sealed interface AdvancedSettingsEvents {
data class SetRichTextEditorEnabled(val enabled: Boolean) : AdvancedSettingsEvents
data class SetDeveloperModeEnabled(val enabled: Boolean) : AdvancedSettingsEvents
- data class SetSendPublicReadReceiptsEnabled(val enabled: Boolean) : AdvancedSettingsEvents
+ data class SetSharePresenceEnabled(val enabled: Boolean) : AdvancedSettingsEvents
data object ChangeTheme : AdvancedSettingsEvents
data object CancelChangeTheme : AdvancedSettingsEvents
data class SetTheme(val theme: Theme) : AdvancedSettingsEvents
diff --git a/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/advanced/AdvancedSettingsPresenter.kt b/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/advanced/AdvancedSettingsPresenter.kt
index 2ac5b664b5..2f0c2b7417 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
@@ -44,8 +44,8 @@ class AdvancedSettingsPresenter @Inject constructor(
val isDeveloperModeEnabled by appPreferencesStore
.isDeveloperModeEnabledFlow()
.collectAsState(initial = false)
- val isSendPublicReadReceiptsEnabled by sessionPreferencesStore
- .isSendPublicReadReceiptsEnabled()
+ val isSharePresenceEnabled by sessionPreferencesStore
+ .isSharePresenceEnabled()
.collectAsState(initial = true)
val theme by remember {
appPreferencesStore.getThemeFlow().mapToTheme()
@@ -60,8 +60,8 @@ class AdvancedSettingsPresenter @Inject constructor(
is AdvancedSettingsEvents.SetDeveloperModeEnabled -> localCoroutineScope.launch {
appPreferencesStore.setDeveloperModeEnabled(event.enabled)
}
- is AdvancedSettingsEvents.SetSendPublicReadReceiptsEnabled -> localCoroutineScope.launch {
- sessionPreferencesStore.setSendPublicReadReceipts(event.enabled)
+ is AdvancedSettingsEvents.SetSharePresenceEnabled -> localCoroutineScope.launch {
+ sessionPreferencesStore.setSharePresence(event.enabled)
}
AdvancedSettingsEvents.CancelChangeTheme -> showChangeThemeDialog = false
AdvancedSettingsEvents.ChangeTheme -> showChangeThemeDialog = true
@@ -75,7 +75,7 @@ class AdvancedSettingsPresenter @Inject constructor(
return AdvancedSettingsState(
isRichTextEditorEnabled = isRichTextEditorEnabled,
isDeveloperModeEnabled = isDeveloperModeEnabled,
- isSendPublicReadReceiptsEnabled = isSendPublicReadReceiptsEnabled,
+ isSharePresenceEnabled = isSharePresenceEnabled,
theme = theme,
showChangeThemeDialog = showChangeThemeDialog,
eventSink = { handleEvents(it) }
diff --git a/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/advanced/AdvancedSettingsState.kt b/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/advanced/AdvancedSettingsState.kt
index 0ea04185f7..469f8a630c 100644
--- a/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/advanced/AdvancedSettingsState.kt
+++ b/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/advanced/AdvancedSettingsState.kt
@@ -21,7 +21,7 @@ import io.element.android.compound.theme.Theme
data class AdvancedSettingsState(
val isRichTextEditorEnabled: Boolean,
val isDeveloperModeEnabled: Boolean,
- val isSendPublicReadReceiptsEnabled: Boolean,
+ val isSharePresenceEnabled: Boolean,
val theme: Theme,
val showChangeThemeDialog: Boolean,
val eventSink: (AdvancedSettingsEvents) -> Unit
diff --git a/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/advanced/AdvancedSettingsStateProvider.kt b/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/advanced/AdvancedSettingsStateProvider.kt
index acfd9bb026..5e255fc091 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
@@ -38,7 +38,7 @@ fun aAdvancedSettingsState(
) = AdvancedSettingsState(
isRichTextEditorEnabled = isRichTextEditorEnabled,
isDeveloperModeEnabled = isDeveloperModeEnabled,
- isSendPublicReadReceiptsEnabled = isSendPublicReadReceiptsEnabled,
+ isSharePresenceEnabled = isSendPublicReadReceiptsEnabled,
theme = Theme.System,
showChangeThemeDialog = showChangeThemeDialog,
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 7079a4daea..9e739c3a00 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
@@ -83,15 +83,15 @@ fun AdvancedSettingsView(
)
ListItem(
headlineContent = {
- Text(text = stringResource(id = R.string.screen_advanced_settings_send_read_receipts))
+ Text(text = stringResource(id = R.string.screen_advanced_settings_share_presence))
},
supportingContent = {
- Text(text = stringResource(id = R.string.screen_advanced_settings_send_read_receipts_description))
+ Text(text = stringResource(id = R.string.screen_advanced_settings_share_presence_description))
},
trailingContent = ListItemContent.Switch(
- checked = state.isSendPublicReadReceiptsEnabled,
+ checked = state.isSharePresenceEnabled,
),
- onClick = { state.eventSink(AdvancedSettingsEvents.SetSendPublicReadReceiptsEnabled(!state.isSendPublicReadReceiptsEnabled)) }
+ onClick = { state.eventSink(AdvancedSettingsEvents.SetSharePresenceEnabled(!state.isSharePresenceEnabled)) }
)
}
diff --git a/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/developer/DeveloperSettingsView.kt b/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/developer/DeveloperSettingsView.kt
index ae20933871..5a40534b87 100644
--- a/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/developer/DeveloperSettingsView.kt
+++ b/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/developer/DeveloperSettingsView.kt
@@ -92,9 +92,8 @@ fun DeveloperSettingsView(
@Composable
private fun ElementCallCategory(
state: DeveloperSettingsState,
- modifier: Modifier = Modifier,
) {
- PreferenceCategory(modifier = modifier, title = "Element Call", showDivider = true) {
+ PreferenceCategory(title = "Element Call", showDivider = true) {
val callUrlState = state.customElementCallBaseUrlState
fun isUsingDefaultUrl(value: String?): Boolean {
return value.isNullOrEmpty() || value == callUrlState.defaultUrl
@@ -120,14 +119,12 @@ private fun ElementCallCategory(
@Composable
private fun FeatureListContent(
state: DeveloperSettingsState,
- modifier: Modifier = Modifier
) {
fun onFeatureEnabled(feature: FeatureUiModel, isEnabled: Boolean) {
state.eventSink(DeveloperSettingsEvents.UpdateEnabledFeature(feature, isEnabled))
}
FeatureListView(
- modifier = modifier,
features = state.features,
onCheckedChange = ::onFeatureEnabled,
)
diff --git a/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/developer/tracing/ConfigureTracingView.kt b/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/developer/tracing/ConfigureTracingView.kt
index 71ff1c3d58..628b5b0d2d 100644
--- a/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/developer/tracing/ConfigureTracingView.kt
+++ b/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/developer/tracing/ConfigureTracingView.kt
@@ -141,14 +141,12 @@ fun ConfigureTracingView(
@Composable
private fun CrateListContent(
state: ConfigureTracingState,
- modifier: Modifier = Modifier
) {
fun onLogLevelChange(target: Target, logLevel: LogLevel) {
state.eventSink(ConfigureTracingEvents.UpdateFilter(target, logLevel))
}
TargetAndLogLevelListView(
- modifier = modifier,
data = state.targetsToLogLevel,
onLogLevelChange = ::onLogLevelChange,
)
@@ -158,11 +156,8 @@ private fun CrateListContent(
private fun TargetAndLogLevelListView(
data: ImmutableMap,
onLogLevelChange: (Target, LogLevel) -> Unit,
- modifier: Modifier = Modifier,
) {
- Column(
- modifier = modifier,
- ) {
+ Column {
data.forEach { item ->
fun onLogLevelChange(logLevel: LogLevel) {
onLogLevelChange(item.key, logLevel)
@@ -182,10 +177,8 @@ private fun TargetAndLogLevelView(
target: Target,
logLevel: LogLevel,
onLogLevelChange: (LogLevel) -> Unit,
- modifier: Modifier = Modifier
) {
ListItem(
- modifier = modifier,
headlineContent = { Text(text = target.filter.takeIf { it.isNotEmpty() } ?: "(common)") },
trailingContent = ListItemContent.Custom {
LogLevelDropdownMenu(
@@ -200,10 +193,9 @@ private fun TargetAndLogLevelView(
private fun LogLevelDropdownMenu(
logLevel: LogLevel,
onLogLevelChange: (LogLevel) -> Unit,
- modifier: Modifier = Modifier,
) {
var expanded by remember { mutableStateOf(false) }
- Box(modifier = modifier) {
+ Box {
DropdownMenuItem(
modifier = Modifier.widthIn(max = 120.dp),
text = { Text(text = logLevel.filter) },
diff --git a/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/notifications/NotificationSettingsView.kt b/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/notifications/NotificationSettingsView.kt
index 2226049efe..6dacfd49f7 100644
--- a/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/notifications/NotificationSettingsView.kt
+++ b/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/notifications/NotificationSettingsView.kt
@@ -99,7 +99,6 @@ private fun NotificationSettingsContentView(
// TODO We are removing the call notification toggle until support for call notifications has been added
// onCallsNotificationsChanged: (Boolean) -> Unit,
onInviteForMeNotificationsChanged: (Boolean) -> Unit,
- modifier: Modifier = Modifier,
) {
val context = LocalContext.current
if (systemSettings.appNotificationsEnabled && !systemSettings.systemNotificationsEnabled) {
@@ -117,7 +116,6 @@ private fun NotificationSettingsContentView(
}
PreferenceSwitch(
- modifier = modifier,
title = stringResource(id = R.string.screen_notification_settings_enable_notifications),
isChecked = systemSettings.appNotificationsEnabled,
switchAlignment = Alignment.Top,
@@ -182,10 +180,8 @@ private fun InvalidNotificationSettingsView(
showError: Boolean,
onContinueClicked: () -> Unit,
onDismissError: () -> Unit,
- modifier: Modifier = Modifier
) {
DialogLikeBannerMolecule(
- modifier = modifier,
title = stringResource(R.string.screen_notification_settings_configuration_mismatch),
content = stringResource(R.string.screen_notification_settings_configuration_mismatch_description),
onSubmitClicked = onContinueClicked,
diff --git a/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/tasks/ClearCacheUseCase.kt b/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/tasks/ClearCacheUseCase.kt
index 07ca0716e9..2d590b90c1 100644
--- a/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/tasks/ClearCacheUseCase.kt
+++ b/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/tasks/ClearCacheUseCase.kt
@@ -24,6 +24,7 @@ import coil.annotation.ExperimentalCoilApi
import com.squareup.anvil.annotations.ContributesBinding
import io.element.android.features.ftue.api.state.FtueState
import io.element.android.features.preferences.impl.DefaultCacheService
+import io.element.android.features.roomlist.api.migration.MigrationScreenStore
import io.element.android.libraries.core.coroutine.CoroutineDispatchers
import io.element.android.libraries.di.ApplicationContext
import io.element.android.libraries.di.SessionScope
@@ -45,6 +46,7 @@ class DefaultClearCacheUseCase @Inject constructor(
private val defaultCacheIndexProvider: DefaultCacheService,
private val okHttpClient: Provider,
private val ftueState: FtueState,
+ private val migrationScreenStore: MigrationScreenStore,
) : ClearCacheUseCase {
override suspend fun invoke() = withContext(coroutineDispatchers.io) {
// Clear Matrix cache
@@ -60,6 +62,8 @@ class DefaultClearCacheUseCase @Inject constructor(
context.cacheDir.deleteRecursively()
// Clear some settings
ftueState.reset()
+ // Clear migration screen store
+ migrationScreenStore.reset()
// Ensure the app is restarted
defaultCacheIndexProvider.onClearedCache(matrixClient.sessionId)
}
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 92294f27de..a0d0fcfad6 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
@@ -16,7 +16,6 @@
package io.element.android.features.preferences.impl.user.editprofile
-import androidx.compose.foundation.gestures.detectTapGestures
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxWidth
@@ -34,8 +33,6 @@ import androidx.compose.runtime.Composable
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
-import androidx.compose.ui.focus.FocusManager
-import androidx.compose.ui.input.pointer.pointerInput
import androidx.compose.ui.platform.LocalFocusManager
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.style.TextAlign
@@ -48,6 +45,7 @@ import io.element.android.libraries.designsystem.components.async.AsyncActionVie
import io.element.android.libraries.designsystem.components.async.AsyncActionViewDefaults
import io.element.android.libraries.designsystem.components.avatar.AvatarSize
import io.element.android.libraries.designsystem.components.button.BackButton
+import io.element.android.libraries.designsystem.modifiers.clearFocusOnTap
import io.element.android.libraries.designsystem.preview.ElementPreview
import io.element.android.libraries.designsystem.preview.PreviewsDayNight
import io.element.android.libraries.designsystem.theme.aliasScreenTitle
@@ -166,13 +164,6 @@ fun EditUserProfileView(
)
}
-private fun Modifier.clearFocusOnTap(focusManager: FocusManager): Modifier =
- pointerInput(Unit) {
- detectTapGestures(onTap = {
- focusManager.clearFocus()
- })
- }
-
@PreviewsDayNight
@Composable
internal fun EditUserProfileViewPreview(@PreviewParameter(EditUserProfileStateProvider::class) state: EditUserProfileState) =
diff --git a/features/preferences/impl/src/main/res/values-be/translations.xml b/features/preferences/impl/src/main/res/values-be/translations.xml
new file mode 100644
index 0000000000..2e5ced17ad
--- /dev/null
+++ b/features/preferences/impl/src/main/res/values-be/translations.xml
@@ -0,0 +1,43 @@
+
+
+ "Базавы URL сервера званкоў Element"
+ "Задайце свой сервер Element Call."
+ "Адрас пазначаны няправільна, пераканайцеся, што вы ўказалі пратакол (http/https) і правільны адрас."
+ "Рэжым распрацоўніка"
+ "Падайце распрацоўнікам доступ да функцый і функцыянальным магчымасцям."
+ "Адключыць рэдактар фарматаванага тэксту і ўключыць Markdown."
+ "Уключыце опцыю для прагляду крыніцы паведамлення на часовай шкале."
+ "Бачнае імя"
+ "Ваша бачнае імя"
+ "Узнікла невядомая памылка, і інфармацыю не ўдалося змяніць."
+ "Немагчыма абнавіць профіль"
+ "Рэдагаваць профіль"
+ "Абнаўленне профілю…"
+ "Дадатковыя налады"
+ "Аўдыё і відэа званкі"
+ "Неадпаведнасць канфігурацыі"
+ "Мы спрасцілі налады апавяшчэнняў, каб спрасціць пошук опцый. Некаторыя карыстальніцкія наладкі, абраныя вамі раней, не адлюстроўваюцца ў дадзеным меню, але яны ўсё яшчэ актыўныя.
+
+Калі вы працягнеце, некаторыя налады могуць быць зменены."
+ "Прамыя чаты"
+ "Карыстальніцкія налады для кожнага чата"
+ "Пры абнаўленні налад апавяшчэнняў адбылася памылка."
+ "Усе паведамленні"
+ "Толькі згадванні і ключавыя словы"
+ "Апавяшчаць мяне ў асабістых чатах"
+ "Апавяшчаць мяне ў групавых чатах"
+ "Уключыць апавяшчэнні на гэтай прыладзе"
+ "Канфігурацыя не была выпраўлена, паспрабуйце яшчэ раз."
+ "Групавыя чаты"
+ "Запрашэнні"
+ "Ваш хатні сервер не падтрымлівае гэтую опцыю ў зашыфраваных пакоях, вы можаце не атрымаць апавяшчэнне ў некаторых пакоях."
+ "Згадванні"
+ "Усе"
+ "Згадванні"
+ "Апавясціць мяне"
+ "Апавясціць мяне ў @room"
+ "Каб атрымліваць апавяшчэнні, змяніце свой %1$s."
+ "налады сістэмы"
+ "Сістэмныя апавяшчэнні выключаны"
+ "Апавяшчэнні"
+
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 96aa762e00..015a3382e4 100644
--- a/features/preferences/impl/src/main/res/values-cs/translations.xml
+++ b/features/preferences/impl/src/main/res/values-cs/translations.xml
@@ -8,6 +8,8 @@
"Vypněte editor formátovaného textu pro ruční zadání Markdown."
"Potvrzení o přečtení"
"Pokud je vypnuto, potvrzení o přečtení se nikomu neodesílají. Stále budete dostávat potvrzení o přečtení od ostatních uživatelů."
+ "Sdílejte přítomnost"
+ "Pokud je tato funkce vypnutá, nebudete moci odesílat ani přijímat potvrzení o přečtení ani upozornění na psaní"
"Povolit možnost zobrazení zdroje zprávy na časové ose."
"Zobrazované jméno"
"Vaše zobrazované jméno"
diff --git a/features/preferences/impl/src/main/res/values-de/translations.xml b/features/preferences/impl/src/main/res/values-de/translations.xml
index fd5d203471..4962ad31e0 100644
--- a/features/preferences/impl/src/main/res/values-de/translations.xml
+++ b/features/preferences/impl/src/main/res/values-de/translations.xml
@@ -6,6 +6,8 @@
"Entwickler-Modus"
"Aktivieren, um Zugriff auf Features und Funktionen für Entwickler zu aktivieren."
"Deaktiviere den Rich-Text-Editor, um Markdown manuell einzugeben."
+ "Lesebestätigungen"
+ "Wenn diese Option deaktiviert ist, werden Ihre Lesebestätigungen an niemanden gesendet. Du erhältst weiterhin Lesebestätigungen von anderen Benutzern."
"Option aktiveren, um Nachrichtenquelle in der Zeitleiste anzuzeigen."
"Anzeigename"
"Dein Anzeigename"
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 5abf6a83f8..32b7c4e63d 100644
--- a/features/preferences/impl/src/main/res/values-hu/translations.xml
+++ b/features/preferences/impl/src/main/res/values-hu/translations.xml
@@ -6,7 +6,11 @@
"Fejlesztői mód"
"Engedélyezd, hogy elérd a fejlesztőknek szánt funkciókat."
"A formázott szöveges szerkesztő letiltása, hogy kézzel írhass Markdownt."
- "Engedélyezze a beállítást az üzenet forrásának megjelenítéséhez az idővonalon."
+ "Olvasási visszaigazolások"
+ "Ha ki van kapcsolva, az olvasási visszaigazolások nem lesznek elküldve senkinek. A többi felhasználó olvasási visszaigazolását továbbra is meg fogja kapni."
+ "Jelenlét megosztása"
+ "Ha ki van kapcsolva, nem tud olvasási visszaigazolást vagy írási értesítést küldeni és fogadni"
+ "Engedélyezd a beállítást az üzenet forrásának megjelenítéséhez az idővonalon."
"Megjelenítendő név"
"Saját megjelenítendő név"
"Ismeretlen hiba történt, és az információ módosítása nem sikerült."
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 a77e35738a..26c7cacd2d 100644
--- a/features/preferences/impl/src/main/res/values-it/translations.xml
+++ b/features/preferences/impl/src/main/res/values-it/translations.xml
@@ -6,6 +6,8 @@
"Modalità sviluppatore"
"Attiva per avere accesso a caratteristiche e funzionalità per sviluppatori."
"Disattiva l\'editor in rich text per digitare Markdown manualmente."
+ "Conferme di lettura"
+ "Se disattivato, le tue conferme di lettura non verranno inviate a nessuno. Riceverai comunque conferme di lettura da altri utenti."
"Attiva l\'opzione per visualizzare il sorgente del messaggio nella linea temporale."
"Nome da mostrare"
"Il tuo nome da mostrare"
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 979644cec9..9d9a9a636e 100644
--- a/features/preferences/impl/src/main/res/values-ru/translations.xml
+++ b/features/preferences/impl/src/main/res/values-ru/translations.xml
@@ -6,6 +6,10 @@
"Режим разработчика"
"Предоставьте разработчикам доступ к функциям и функциональным возможностям."
"Отключить редактор форматированного текста и включить Markdown."
+ "Уведомления о прочтении"
+ "Если этот параметр выключен, ваш статус о прочтении не будет отображаться. Вы по-прежнему будете видеть статус о прочтении от других пользователей."
+ "Поделиться присутствием"
+ "Если выключено, вы не сможете отправлять, получать уведомления о прочтении и наборе текста"
"Включить опцию просмотра источника сообщения в ленте."
"Отображаемое имя"
"Ваше отображаемое имя"
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 ad0a77b61e..7115a87501 100644
--- a/features/preferences/impl/src/main/res/values-sk/translations.xml
+++ b/features/preferences/impl/src/main/res/values-sk/translations.xml
@@ -8,6 +8,8 @@
"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."
+ "Zdieľať prítomnosť"
+ "Ak je vypnuté, nebudete môcť odosielať ani prijímať potvrdenia o prečítaní alebo písať upozornenia"
"Povoliť možnosť zobrazenia zdroja správy na časovej osi."
"Zobrazované meno"
"Vaše zobrazované meno"
diff --git a/features/preferences/impl/src/main/res/values/localazy.xml b/features/preferences/impl/src/main/res/values/localazy.xml
index 607329332f..70a1b032a9 100644
--- a/features/preferences/impl/src/main/res/values/localazy.xml
+++ b/features/preferences/impl/src/main/res/values/localazy.xml
@@ -8,6 +8,8 @@
"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."
+ "Share presence"
+ "If turned off, you won’t be able to send or receive read receipts or typing notifications"
"Enable option to view message source in the timeline."
"Display name"
"Your display name"
diff --git a/features/preferences/impl/src/test/kotlin/io/element/android/features/preferences/impl/advanced/AdvancedSettingsPresenterTest.kt b/features/preferences/impl/src/test/kotlin/io/element/android/features/preferences/impl/advanced/AdvancedSettingsPresenterTest.kt
index a042d792b8..1745d57396 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
@@ -43,7 +43,7 @@ class AdvancedSettingsPresenterTest {
assertThat(initialState.isDeveloperModeEnabled).isFalse()
assertThat(initialState.isRichTextEditorEnabled).isFalse()
assertThat(initialState.showChangeThemeDialog).isFalse()
- assertThat(initialState.isSendPublicReadReceiptsEnabled).isTrue()
+ assertThat(initialState.isSharePresenceEnabled).isTrue()
assertThat(initialState.theme).isEqualTo(Theme.System)
}
}
@@ -79,17 +79,17 @@ class AdvancedSettingsPresenterTest {
}
@Test
- fun `present - send public read receipts off on`() = runTest {
+ fun `present - share presence off on`() = runTest {
val presenter = createAdvancedSettingsPresenter()
moleculeFlow(RecompositionMode.Immediate) {
presenter.present()
}.test {
val initialState = awaitLastSequentialItem()
- assertThat(initialState.isSendPublicReadReceiptsEnabled).isTrue()
- initialState.eventSink.invoke(AdvancedSettingsEvents.SetSendPublicReadReceiptsEnabled(false))
- assertThat(awaitItem().isSendPublicReadReceiptsEnabled).isFalse()
- initialState.eventSink.invoke(AdvancedSettingsEvents.SetSendPublicReadReceiptsEnabled(true))
- assertThat(awaitItem().isSendPublicReadReceiptsEnabled).isTrue()
+ assertThat(initialState.isSharePresenceEnabled).isTrue()
+ initialState.eventSink.invoke(AdvancedSettingsEvents.SetSharePresenceEnabled(false))
+ assertThat(awaitItem().isSharePresenceEnabled).isFalse()
+ initialState.eventSink.invoke(AdvancedSettingsEvents.SetSharePresenceEnabled(true))
+ assertThat(awaitItem().isSharePresenceEnabled).isTrue()
}
}
diff --git a/features/rageshake/api/src/main/kotlin/io/element/android/features/rageshake/api/crash/CrashDetectionState.kt b/features/rageshake/api/src/main/kotlin/io/element/android/features/rageshake/api/crash/CrashDetectionState.kt
index 96fb558de6..39ddfa8213 100644
--- a/features/rageshake/api/src/main/kotlin/io/element/android/features/rageshake/api/crash/CrashDetectionState.kt
+++ b/features/rageshake/api/src/main/kotlin/io/element/android/features/rageshake/api/crash/CrashDetectionState.kt
@@ -20,6 +20,7 @@ import androidx.compose.runtime.Immutable
@Immutable
data class CrashDetectionState(
+ val appName: String,
val crashDetected: Boolean,
val eventSink: (CrashDetectionEvents) -> Unit
)
diff --git a/features/rageshake/api/src/main/kotlin/io/element/android/features/rageshake/api/crash/CrashDetectionStateProvider.kt b/features/rageshake/api/src/main/kotlin/io/element/android/features/rageshake/api/crash/CrashDetectionStateProvider.kt
index 184d0ecbbc..b93637010c 100644
--- a/features/rageshake/api/src/main/kotlin/io/element/android/features/rageshake/api/crash/CrashDetectionStateProvider.kt
+++ b/features/rageshake/api/src/main/kotlin/io/element/android/features/rageshake/api/crash/CrashDetectionStateProvider.kt
@@ -17,6 +17,7 @@
package io.element.android.features.rageshake.api.crash
fun aCrashDetectionState() = CrashDetectionState(
+ appName = "Element",
crashDetected = false,
eventSink = {}
)
diff --git a/features/rageshake/api/src/main/kotlin/io/element/android/features/rageshake/api/crash/CrashDetectionView.kt b/features/rageshake/api/src/main/kotlin/io/element/android/features/rageshake/api/crash/CrashDetectionView.kt
index 48c10a75c4..5af36b5ad8 100644
--- a/features/rageshake/api/src/main/kotlin/io/element/android/features/rageshake/api/crash/CrashDetectionView.kt
+++ b/features/rageshake/api/src/main/kotlin/io/element/android/features/rageshake/api/crash/CrashDetectionView.kt
@@ -22,7 +22,6 @@ import io.element.android.features.rageshake.api.R
import io.element.android.libraries.designsystem.components.dialogs.ConfirmationDialog
import io.element.android.libraries.designsystem.preview.ElementPreview
import io.element.android.libraries.designsystem.preview.PreviewsDayNight
-import io.element.android.libraries.designsystem.utils.LogCompositions
import io.element.android.libraries.ui.strings.CommonStrings
@Composable
@@ -30,17 +29,13 @@ fun CrashDetectionView(
state: CrashDetectionState,
onOpenBugReport: () -> Unit = { },
) {
- LogCompositions(
- tag = "Crash",
- msg = "CrashDetectionScreen"
- )
-
fun onPopupDismissed() {
state.eventSink(CrashDetectionEvents.ResetAllCrashData)
}
if (state.crashDetected) {
CrashDetectionContent(
+ appName = state.appName,
onYesClicked = onOpenBugReport,
onNoClicked = ::onPopupDismissed,
onDismiss = ::onPopupDismissed,
@@ -50,14 +45,14 @@ fun CrashDetectionView(
@Composable
private fun CrashDetectionContent(
+ appName: String,
onNoClicked: () -> Unit = { },
onYesClicked: () -> Unit = { },
onDismiss: () -> Unit = { },
) {
ConfirmationDialog(
title = stringResource(id = CommonStrings.action_report_bug),
- // TODO Replace with app name
- content = stringResource(id = R.string.crash_detection_dialog_content, "Element"),
+ content = stringResource(id = R.string.crash_detection_dialog_content, appName),
submitText = stringResource(id = CommonStrings.action_yes),
cancelText = stringResource(id = CommonStrings.action_no),
onCancelClicked = onNoClicked,
diff --git a/features/rageshake/api/src/main/kotlin/io/element/android/features/rageshake/api/detection/RageshakeDetectionView.kt b/features/rageshake/api/src/main/kotlin/io/element/android/features/rageshake/api/detection/RageshakeDetectionView.kt
index e076ceb1a6..6121c684cd 100644
--- a/features/rageshake/api/src/main/kotlin/io/element/android/features/rageshake/api/detection/RageshakeDetectionView.kt
+++ b/features/rageshake/api/src/main/kotlin/io/element/android/features/rageshake/api/detection/RageshakeDetectionView.kt
@@ -31,7 +31,6 @@ import io.element.android.libraries.androidutils.hardware.vibrate
import io.element.android.libraries.designsystem.components.dialogs.ConfirmationDialog
import io.element.android.libraries.designsystem.preview.ElementPreview
import io.element.android.libraries.designsystem.preview.PreviewsDayNight
-import io.element.android.libraries.designsystem.utils.LogCompositions
import io.element.android.libraries.designsystem.utils.OnLifecycleEvent
import io.element.android.libraries.ui.strings.CommonStrings
@@ -40,10 +39,6 @@ fun RageshakeDetectionView(
state: RageshakeDetectionState,
onOpenBugReport: () -> Unit = { },
) {
- LogCompositions(
- tag = "Rageshake",
- msg = "RageshakeDetectionScreen"
- )
val eventSink = state.eventSink
val context = LocalContext.current
OnLifecycleEvent { _, event ->
diff --git a/features/rageshake/api/src/main/res/values-be/translations.xml b/features/rageshake/api/src/main/res/values-be/translations.xml
new file mode 100644
index 0000000000..eccddc73b8
--- /dev/null
+++ b/features/rageshake/api/src/main/res/values-be/translations.xml
@@ -0,0 +1,6 @@
+
+
+ "Пры апошнім выкарыстанні %1$s адбыўся збой. Жадаеце падзяліцца справаздачай аб збоі?"
+ "Падобна, што вы трасеце тэлефон. Жадаеце адкрыць экран паведамлення пра памылку?"
+ "Парог выяўлення"
+
diff --git a/features/rageshake/impl/src/main/kotlin/io/element/android/features/rageshake/impl/bugreport/BugReportFormError.kt b/features/rageshake/impl/src/main/kotlin/io/element/android/features/rageshake/impl/bugreport/BugReportFormError.kt
new file mode 100644
index 0000000000..39d1235ee5
--- /dev/null
+++ b/features/rageshake/impl/src/main/kotlin/io/element/android/features/rageshake/impl/bugreport/BugReportFormError.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.rageshake.impl.bugreport
+
+sealed class BugReportFormError : Exception() {
+ data object DescriptionTooShort : BugReportFormError()
+}
diff --git a/features/rageshake/impl/src/main/kotlin/io/element/android/features/rageshake/impl/bugreport/BugReportPresenter.kt b/features/rageshake/impl/src/main/kotlin/io/element/android/features/rageshake/impl/bugreport/BugReportPresenter.kt
index fea6bc95b1..5e3b3cfeb1 100644
--- a/features/rageshake/impl/src/main/kotlin/io/element/android/features/rageshake/impl/bugreport/BugReportPresenter.kt
+++ b/features/rageshake/impl/src/main/kotlin/io/element/android/features/rageshake/impl/bugreport/BugReportPresenter.kt
@@ -91,7 +91,13 @@ class BugReportPresenter @Inject constructor(
fun handleEvents(event: BugReportEvents) {
when (event) {
- BugReportEvents.SendBugReport -> appCoroutineScope.sendBugReport(formState.value, crashInfo.isNotEmpty(), uploadListener)
+ BugReportEvents.SendBugReport -> {
+ if (formState.value.description.length < 10) {
+ sendingAction.value = AsyncAction.Failure(BugReportFormError.DescriptionTooShort)
+ } else {
+ appCoroutineScope.sendBugReport(formState.value, crashInfo.isNotEmpty(), uploadListener)
+ }
+ }
BugReportEvents.ResetAll -> appCoroutineScope.resetAll()
is BugReportEvents.SetDescription -> updateFormState(formState) {
copy(description = event.description)
diff --git a/features/rageshake/impl/src/main/kotlin/io/element/android/features/rageshake/impl/bugreport/BugReportState.kt b/features/rageshake/impl/src/main/kotlin/io/element/android/features/rageshake/impl/bugreport/BugReportState.kt
index c3bfbec888..16edae46c4 100644
--- a/features/rageshake/impl/src/main/kotlin/io/element/android/features/rageshake/impl/bugreport/BugReportState.kt
+++ b/features/rageshake/impl/src/main/kotlin/io/element/android/features/rageshake/impl/bugreport/BugReportState.kt
@@ -28,8 +28,9 @@ data class BugReportState(
val sending: AsyncAction,
val eventSink: (BugReportEvents) -> Unit
) {
- val submitEnabled =
- formState.description.length > 10 && sending !is AsyncAction.Loading
+ val submitEnabled = sending !is AsyncAction.Loading
+ val isDescriptionInError = sending is AsyncAction.Failure &&
+ sending.error is BugReportFormError.DescriptionTooShort
}
@Parcelize
diff --git a/features/rageshake/impl/src/main/kotlin/io/element/android/features/rageshake/impl/bugreport/BugReportStateProvider.kt b/features/rageshake/impl/src/main/kotlin/io/element/android/features/rageshake/impl/bugreport/BugReportStateProvider.kt
index bb0d273de4..8bda648c4c 100644
--- a/features/rageshake/impl/src/main/kotlin/io/element/android/features/rageshake/impl/bugreport/BugReportStateProvider.kt
+++ b/features/rageshake/impl/src/main/kotlin/io/element/android/features/rageshake/impl/bugreport/BugReportStateProvider.kt
@@ -33,6 +33,7 @@ open class BugReportStateProvider : PreviewParameterProvider {
),
aBugReportState().copy(sending = AsyncAction.Loading),
aBugReportState().copy(sending = AsyncAction.Success(Unit)),
+ aBugReportState().copy(sending = AsyncAction.Failure(BugReportFormError.DescriptionTooShort)),
)
}
diff --git a/features/rageshake/impl/src/main/kotlin/io/element/android/features/rageshake/impl/bugreport/BugReportView.kt b/features/rageshake/impl/src/main/kotlin/io/element/android/features/rageshake/impl/bugreport/BugReportView.kt
index e10e9250e3..f5ffd62fd6 100644
--- a/features/rageshake/impl/src/main/kotlin/io/element/android/features/rageshake/impl/bugreport/BugReportView.kt
+++ b/features/rageshake/impl/src/main/kotlin/io/element/android/features/rageshake/impl/bugreport/BugReportView.kt
@@ -51,7 +51,6 @@ import io.element.android.libraries.designsystem.preview.debugPlaceholderBackgro
import io.element.android.libraries.designsystem.theme.components.Button
import io.element.android.libraries.designsystem.theme.components.OutlinedTextField
import io.element.android.libraries.designsystem.theme.components.Text
-import io.element.android.libraries.designsystem.utils.LogCompositions
import io.element.android.libraries.ui.strings.CommonStrings
@Composable
@@ -62,7 +61,6 @@ fun BugReportView(
onBackPressed: () -> Unit,
modifier: Modifier = Modifier,
) {
- LogCompositions(tag = "Rageshake", msg = "Root")
val eventSink = state.eventSink
Box(modifier = modifier) {
@@ -96,7 +94,7 @@ fun BugReportView(
imeAction = ImeAction.Next
),
minLines = 3,
- // TODO Error text too short
+ isError = state.isDescriptionInError,
)
}
Spacer(modifier = Modifier.height(16.dp))
@@ -167,6 +165,12 @@ fun BugReportView(
eventSink(BugReportEvents.ResetAll)
onDone()
},
+ errorMessage = { error ->
+ when (error) {
+ BugReportFormError.DescriptionTooShort -> stringResource(id = R.string.screen_bug_report_error_description_too_short)
+ else -> error.message ?: error.toString()
+ }
+ },
onErrorDismiss = { eventSink(BugReportEvents.ClearError) },
)
}
diff --git a/features/rageshake/impl/src/main/kotlin/io/element/android/features/rageshake/impl/crash/DefaultCrashDetectionPresenter.kt b/features/rageshake/impl/src/main/kotlin/io/element/android/features/rageshake/impl/crash/DefaultCrashDetectionPresenter.kt
index 1097c79939..9f09f5f35a 100644
--- a/features/rageshake/impl/src/main/kotlin/io/element/android/features/rageshake/impl/crash/DefaultCrashDetectionPresenter.kt
+++ b/features/rageshake/impl/src/main/kotlin/io/element/android/features/rageshake/impl/crash/DefaultCrashDetectionPresenter.kt
@@ -24,13 +24,17 @@ import io.element.android.features.rageshake.api.crash.CrashDataStore
import io.element.android.features.rageshake.api.crash.CrashDetectionEvents
import io.element.android.features.rageshake.api.crash.CrashDetectionPresenter
import io.element.android.features.rageshake.api.crash.CrashDetectionState
+import io.element.android.libraries.core.meta.BuildMeta
import io.element.android.libraries.di.AppScope
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.launch
import javax.inject.Inject
@ContributesBinding(AppScope::class)
-class DefaultCrashDetectionPresenter @Inject constructor(private val crashDataStore: CrashDataStore) :
+class DefaultCrashDetectionPresenter @Inject constructor(
+ private val buildMeta: BuildMeta,
+ private val crashDataStore: CrashDataStore,
+) :
CrashDetectionPresenter {
@Composable
override fun present(): CrashDetectionState {
@@ -45,6 +49,7 @@ class DefaultCrashDetectionPresenter @Inject constructor(private val crashDataSt
}
return CrashDetectionState(
+ appName = buildMeta.applicationName,
crashDetected = crashDetected.value,
eventSink = ::handleEvents
)
diff --git a/features/rageshake/impl/src/main/res/values-be/translations.xml b/features/rageshake/impl/src/main/res/values-be/translations.xml
new file mode 100644
index 0000000000..7d8c8b5327
--- /dev/null
+++ b/features/rageshake/impl/src/main/res/values-be/translations.xml
@@ -0,0 +1,15 @@
+
+
+ "Далучыць здымак экрана"
+ "Вы можаце звязацца са мной, калі ў Вас узнікнуць якія-небудзь дадатковыя пытанні."
+ "Звяжыцеся са мной"
+ "Рэдагаваць здымак экрана"
+ "Калі ласка, апішыце памылку. Што вы зрабілі? Якія паводзіны вы чакалі? Што адбылося насамрэч. Калі ласка, апішыце ўсё як магчыма падрабязней."
+ "Апішыце праблему…"
+ "Калі магчыма, калі ласка, напішыце апісанне на англійскай мове."
+ "Адправіць часопісы збояў"
+ "Дазволіць часопісы"
+ "Адправіць здымак экрана"
+ "Каб пераканацца, што ўсё працуе правільна, у паведамленне будуць уключаны часопісы. Каб адправіць паведамленне без часопісаў, адключыце гэтую наладу."
+ "Пры апошнім выкарыстанні %1$s адбыўся збой. Жадаеце падзяліцца справаздачай аб збоі?"
+
diff --git a/features/rageshake/impl/src/main/res/values-cs/translations.xml b/features/rageshake/impl/src/main/res/values-cs/translations.xml
index 824819e5ee..dbd320b974 100644
--- a/features/rageshake/impl/src/main/res/values-cs/translations.xml
+++ b/features/rageshake/impl/src/main/res/values-cs/translations.xml
@@ -7,6 +7,7 @@
"Popište prosím chybu. Co jste udělali? Co jste očekávali, že se stane? Co se ve skutečnosti stalo? Uveďte co nejvíce podrobností."
"Popište chybu…"
"Pokud je to možné, prosím, napište popis anglicky."
+ "Popis je příliš krátký, uveďte prosím více podrobností o tom, co se stalo. Děkujeme!"
"Odeslat záznamy o selhání"
"Povolit protokoly"
"Odeslat snímek obrazovky"
diff --git a/features/rageshake/impl/src/main/res/values-de/translations.xml b/features/rageshake/impl/src/main/res/values-de/translations.xml
index 95e8c0228b..406c7e0efb 100644
--- a/features/rageshake/impl/src/main/res/values-de/translations.xml
+++ b/features/rageshake/impl/src/main/res/values-de/translations.xml
@@ -11,5 +11,6 @@
"Protokolle zulassen"
"Bildschirmfoto senden"
"Die Protokolle werden deiner Nachricht beigefügt, um sicherzustellen, dass alles ordnungsgemäß funktioniert. Um deine Nachricht ohne Protokolle zu senden, deaktiviere diese Einstellung."
+ "Logs ansehen"
"%1$s ist bei der letzten Nutzung abgestürzt. Möchtest du einen Absturzbericht mit uns teilen?"
diff --git a/features/rageshake/impl/src/main/res/values-hu/translations.xml b/features/rageshake/impl/src/main/res/values-hu/translations.xml
index 85f22f8449..e0ed00018f 100644
--- a/features/rageshake/impl/src/main/res/values-hu/translations.xml
+++ b/features/rageshake/impl/src/main/res/values-hu/translations.xml
@@ -7,9 +7,11 @@
"Írja le a hibát. Mit csinált? Mire számított, hogy mi fog történni? Mi történt valójában? Fogalmazzon a lehető legrészletesebben."
"Írja le a problémát…"
"Ha lehetséges, a leírást angolul írja meg."
+ "A leírás túl rövid, adjon meg további részleteket a történtekről. Köszönjük!"
"Összeomlásnaplók küldése"
"Naplók engedélyezése"
"Képernyőkép küldése"
"A naplók szerepelni fognak az üzenetben, hogy megbizonyosodhassunk arról, hogy minden megfelelően működik-e. Ha naplók nélkül szeretné elküldeni az üzenetet, akkor kapcsolja ki ezt a beállítást."
+ "Naplók megtekintése"
"Az %1$s összeomlott a legutóbbi használata óta. Megosztod velünk az összeomlás-jelentést?"
diff --git a/features/rageshake/impl/src/main/res/values-it/translations.xml b/features/rageshake/impl/src/main/res/values-it/translations.xml
index 852a8f68ff..703e882ad2 100644
--- a/features/rageshake/impl/src/main/res/values-it/translations.xml
+++ b/features/rageshake/impl/src/main/res/values-it/translations.xml
@@ -11,5 +11,6 @@
"Consenti i log"
"Invia istantanea schermo"
"Per verificare che le cose funzionino come previsto, i log verranno inviati con il tuo messaggio. Per inviare solo il tuo messaggio, disattiva questa impostazione."
+ "Visualizza i log"
"%1$s si è chiuso inaspettatamente l\'ultima volta che è stato usato. Vuoi condividere con noi un rapporto sull\'arresto anomalo?"
diff --git a/features/rageshake/impl/src/main/res/values-ru/translations.xml b/features/rageshake/impl/src/main/res/values-ru/translations.xml
index 7c0ea079a3..2de3e3ce67 100644
--- a/features/rageshake/impl/src/main/res/values-ru/translations.xml
+++ b/features/rageshake/impl/src/main/res/values-ru/translations.xml
@@ -7,6 +7,7 @@
"Пожалуйста, опишите ошибку. Что вы сделали? Какое поведение вы ожидали? Что произошло на самом деле. Пожалуйста, опишите все как можно подробнее."
"Опишите проблему…"
"Если возможно, пожалуйста, напишите описание на английском языке."
+ "Описание слишком короткое, пожалуйста, расскажите подробнее о том, что произошло. Спасибо!"
"Отправка журналов сбоев"
"Разрешить ведение журналов"
"Отправить снимок экрана"
diff --git a/features/rageshake/impl/src/main/res/values-sk/translations.xml b/features/rageshake/impl/src/main/res/values-sk/translations.xml
index 8e94848650..2fbd637033 100644
--- a/features/rageshake/impl/src/main/res/values-sk/translations.xml
+++ b/features/rageshake/impl/src/main/res/values-sk/translations.xml
@@ -7,6 +7,7 @@
"Popíšte prosím chybu. Čo ste urobili? Čo ste očakávali, že sa stane? Čo sa skutočne stalo. Prosím, uveďte čo najviac podrobností."
"Popíšte chybu…"
"Ak je to možné, napíšte popis v angličtine."
+ "Popis je príliš krátky, uveďte viac podrobností o tom, čo sa stalo. Ďakujeme!"
"Odoslať záznamy o zlyhaní"
"Povoliť záznamy"
"Odoslať snímku obrazovky"
diff --git a/features/rageshake/impl/src/main/res/values/localazy.xml b/features/rageshake/impl/src/main/res/values/localazy.xml
index 83413c3919..1d1805a386 100644
--- a/features/rageshake/impl/src/main/res/values/localazy.xml
+++ b/features/rageshake/impl/src/main/res/values/localazy.xml
@@ -7,6 +7,7 @@
"Please describe the problem. What did you do? What did you expect to happen? What actually happened. Please go into as much detail as you can."
"Describe the problem…"
"If possible, please write the description in English."
+ "The description is too short, please provide more details about what happened. Thanks!"
"Send crash logs"
"Allow logs"
"Send screenshot"
diff --git a/features/rageshake/impl/src/test/kotlin/io/element/android/features/rageshake/impl/bugreport/BugReportPresenterTest.kt b/features/rageshake/impl/src/test/kotlin/io/element/android/features/rageshake/impl/bugreport/BugReportPresenterTest.kt
index e36cc5b841..7d6f16d412 100644
--- a/features/rageshake/impl/src/test/kotlin/io/element/android/features/rageshake/impl/bugreport/BugReportPresenterTest.kt
+++ b/features/rageshake/impl/src/test/kotlin/io/element/android/features/rageshake/impl/bugreport/BugReportPresenterTest.kt
@@ -20,6 +20,9 @@ import app.cash.molecule.RecompositionMode
import app.cash.molecule.moleculeFlow
import app.cash.turbine.test
import com.google.common.truth.Truth.assertThat
+import io.element.android.features.rageshake.api.crash.CrashDataStore
+import io.element.android.features.rageshake.api.reporter.BugReporter
+import io.element.android.features.rageshake.api.screenshot.ScreenshotHolder
import io.element.android.features.rageshake.test.crash.A_CRASH_DATA
import io.element.android.features.rageshake.test.crash.FakeCrashDataStore
import io.element.android.features.rageshake.test.screenshot.A_SCREENSHOT_URI
@@ -27,6 +30,7 @@ import io.element.android.features.rageshake.test.screenshot.FakeScreenshotHolde
import io.element.android.libraries.architecture.AsyncAction
import io.element.android.libraries.matrix.test.A_FAILURE_REASON
import io.element.android.tests.testutils.WarmUpRule
+import kotlinx.coroutines.test.TestScope
import kotlinx.coroutines.test.runTest
import org.junit.Rule
import org.junit.Test
@@ -40,12 +44,7 @@ class BugReportPresenterTest {
@Test
fun `present - initial state`() = runTest {
- val presenter = BugReportPresenter(
- FakeBugReporter(),
- FakeCrashDataStore(),
- FakeScreenshotHolder(),
- this,
- )
+ val presenter = createPresenter()
moleculeFlow(RecompositionMode.Immediate) {
presenter.present()
}.test {
@@ -55,24 +54,19 @@ class BugReportPresenterTest {
assertThat(initialState.sending).isEqualTo(AsyncAction.Uninitialized)
assertThat(initialState.screenshotUri).isNull()
assertThat(initialState.sendingProgress).isEqualTo(0f)
- assertThat(initialState.submitEnabled).isFalse()
+ assertThat(initialState.submitEnabled).isTrue()
}
}
@Test
fun `present - set description`() = runTest {
- val presenter = BugReportPresenter(
- FakeBugReporter(),
- FakeCrashDataStore(),
- FakeScreenshotHolder(),
- this,
- )
+ val presenter = createPresenter()
moleculeFlow(RecompositionMode.Immediate) {
presenter.present()
}.test {
val initialState = awaitItem()
initialState.eventSink.invoke(BugReportEvents.SetDescription(A_SHORT_DESCRIPTION))
- assertThat(awaitItem().submitEnabled).isFalse()
+ assertThat(awaitItem().submitEnabled).isTrue()
initialState.eventSink.invoke(BugReportEvents.SetDescription(A_LONG_DESCRIPTION))
assertThat(awaitItem().submitEnabled).isTrue()
}
@@ -80,12 +74,7 @@ class BugReportPresenterTest {
@Test
fun `present - can contact`() = runTest {
- val presenter = BugReportPresenter(
- FakeBugReporter(),
- FakeCrashDataStore(),
- FakeScreenshotHolder(),
- this,
- )
+ val presenter = createPresenter()
moleculeFlow(RecompositionMode.Immediate) {
presenter.present()
}.test {
@@ -99,12 +88,7 @@ class BugReportPresenterTest {
@Test
fun `present - send logs`() = runTest {
- val presenter = BugReportPresenter(
- FakeBugReporter(),
- FakeCrashDataStore(),
- FakeScreenshotHolder(),
- this,
- )
+ val presenter = createPresenter()
moleculeFlow(RecompositionMode.Immediate) {
presenter.present()
}.test {
@@ -119,12 +103,7 @@ class BugReportPresenterTest {
@Test
fun `present - send screenshot`() = runTest {
- val presenter = BugReportPresenter(
- FakeBugReporter(),
- FakeCrashDataStore(),
- FakeScreenshotHolder(),
- this,
- )
+ val presenter = createPresenter()
moleculeFlow(RecompositionMode.Immediate) {
presenter.present()
}.test {
@@ -138,11 +117,9 @@ class BugReportPresenterTest {
@Test
fun `present - reset all`() = runTest {
- val presenter = BugReportPresenter(
- FakeBugReporter(),
- FakeCrashDataStore(crashData = A_CRASH_DATA, appHasCrashed = true),
- FakeScreenshotHolder(screenshotUri = A_SCREENSHOT_URI),
- this,
+ val presenter = createPresenter(
+ crashDataStore = FakeCrashDataStore(crashData = A_CRASH_DATA, appHasCrashed = true),
+ screenshotHolder = FakeScreenshotHolder(screenshotUri = A_SCREENSHOT_URI),
)
moleculeFlow(RecompositionMode.Immediate) {
presenter.present()
@@ -160,16 +137,17 @@ class BugReportPresenterTest {
@Test
fun `present - send success`() = runTest {
- val presenter = BugReportPresenter(
+ val presenter = createPresenter(
FakeBugReporter(mode = FakeBugReporterMode.Success),
FakeCrashDataStore(crashData = A_CRASH_DATA, appHasCrashed = true),
FakeScreenshotHolder(screenshotUri = A_SCREENSHOT_URI),
- this,
)
moleculeFlow(RecompositionMode.Immediate) {
presenter.present()
}.test {
val initialState = awaitItem()
+ initialState.eventSink.invoke(BugReportEvents.SetDescription(A_LONG_DESCRIPTION))
+ skipItems(1)
initialState.eventSink.invoke(BugReportEvents.SendBugReport)
skipItems(1)
val progressState = awaitItem()
@@ -185,16 +163,17 @@ class BugReportPresenterTest {
@Test
fun `present - send failure`() = runTest {
- val presenter = BugReportPresenter(
+ val presenter = createPresenter(
FakeBugReporter(mode = FakeBugReporterMode.Failure),
FakeCrashDataStore(crashData = A_CRASH_DATA, appHasCrashed = true),
FakeScreenshotHolder(screenshotUri = A_SCREENSHOT_URI),
- this,
)
moleculeFlow(RecompositionMode.Immediate) {
presenter.present()
}.test {
val initialState = awaitItem()
+ initialState.eventSink.invoke(BugReportEvents.SetDescription(A_LONG_DESCRIPTION))
+ skipItems(1)
initialState.eventSink.invoke(BugReportEvents.SendBugReport)
skipItems(1)
val progressState = awaitItem()
@@ -212,18 +191,38 @@ class BugReportPresenterTest {
}
}
+ @Test
+ fun `present - send failure description too short`() = runTest {
+ val presenter = createPresenter()
+ moleculeFlow(RecompositionMode.Immediate) {
+ presenter.present()
+ }.test {
+ val initialState = awaitItem()
+ initialState.eventSink.invoke(BugReportEvents.SetDescription(A_SHORT_DESCRIPTION))
+ skipItems(1)
+ initialState.eventSink.invoke(BugReportEvents.SendBugReport)
+ val errorState = awaitItem()
+ assertThat(errorState.sending).isEqualTo(AsyncAction.Failure(BugReportFormError.DescriptionTooShort))
+ // Reset failure
+ initialState.eventSink.invoke(BugReportEvents.ClearError)
+ val lastItem = awaitItem()
+ assertThat(lastItem.sending).isInstanceOf(AsyncAction.Uninitialized::class.java)
+ }
+ }
+
@Test
fun `present - send cancel`() = runTest {
- val presenter = BugReportPresenter(
+ val presenter = createPresenter(
FakeBugReporter(mode = FakeBugReporterMode.Cancel),
FakeCrashDataStore(crashData = A_CRASH_DATA, appHasCrashed = true),
FakeScreenshotHolder(screenshotUri = A_SCREENSHOT_URI),
- this,
)
moleculeFlow(RecompositionMode.Immediate) {
presenter.present()
}.test {
val initialState = awaitItem()
+ initialState.eventSink.invoke(BugReportEvents.SetDescription(A_LONG_DESCRIPTION))
+ skipItems(1)
initialState.eventSink.invoke(BugReportEvents.SendBugReport)
skipItems(1)
val progressState = awaitItem()
@@ -235,4 +234,15 @@ class BugReportPresenterTest {
assertThat(awaitItem().sending).isEqualTo(AsyncAction.Uninitialized)
}
}
+
+ private fun TestScope.createPresenter(
+ bugReporter: BugReporter = FakeBugReporter(),
+ crashDataStore: CrashDataStore = FakeCrashDataStore(),
+ screenshotHolder: ScreenshotHolder = FakeScreenshotHolder(),
+ ) = BugReportPresenter(
+ bugReporter,
+ crashDataStore,
+ screenshotHolder,
+ this,
+ )
}
diff --git a/features/rageshake/impl/src/test/kotlin/io/element/android/features/rageshake/impl/crash/ui/CrashDetectionPresenterTest.kt b/features/rageshake/impl/src/test/kotlin/io/element/android/features/rageshake/impl/crash/ui/CrashDetectionPresenterTest.kt
index 917e427d9e..8888cf8763 100644
--- a/features/rageshake/impl/src/test/kotlin/io/element/android/features/rageshake/impl/crash/ui/CrashDetectionPresenterTest.kt
+++ b/features/rageshake/impl/src/test/kotlin/io/element/android/features/rageshake/impl/crash/ui/CrashDetectionPresenterTest.kt
@@ -24,6 +24,8 @@ import io.element.android.features.rageshake.api.crash.CrashDetectionEvents
import io.element.android.features.rageshake.impl.crash.DefaultCrashDetectionPresenter
import io.element.android.features.rageshake.test.crash.A_CRASH_DATA
import io.element.android.features.rageshake.test.crash.FakeCrashDataStore
+import io.element.android.libraries.core.meta.BuildMeta
+import io.element.android.libraries.matrix.test.core.aBuildMeta
import io.element.android.tests.testutils.WarmUpRule
import kotlinx.coroutines.test.runTest
import org.junit.Rule
@@ -35,9 +37,7 @@ class CrashDetectionPresenterTest {
@Test
fun `present - initial state no crash`() = runTest {
- val presenter = DefaultCrashDetectionPresenter(
- FakeCrashDataStore()
- )
+ val presenter = createPresenter()
moleculeFlow(RecompositionMode.Immediate) {
presenter.present()
}.test {
@@ -48,7 +48,7 @@ class CrashDetectionPresenterTest {
@Test
fun `present - initial state crash`() = runTest {
- val presenter = DefaultCrashDetectionPresenter(
+ val presenter = createPresenter(
FakeCrashDataStore(appHasCrashed = true)
)
moleculeFlow(RecompositionMode.Immediate) {
@@ -62,7 +62,7 @@ class CrashDetectionPresenterTest {
@Test
fun `present - reset app has crashed`() = runTest {
- val presenter = DefaultCrashDetectionPresenter(
+ val presenter = createPresenter(
FakeCrashDataStore(appHasCrashed = true)
)
moleculeFlow(RecompositionMode.Immediate) {
@@ -78,7 +78,7 @@ class CrashDetectionPresenterTest {
@Test
fun `present - reset all crash data`() = runTest {
- val presenter = DefaultCrashDetectionPresenter(
+ val presenter = createPresenter(
FakeCrashDataStore(appHasCrashed = true, crashData = A_CRASH_DATA)
)
moleculeFlow(RecompositionMode.Immediate) {
@@ -91,4 +91,12 @@ class CrashDetectionPresenterTest {
assertThat(awaitItem().crashDetected).isFalse()
}
}
+
+ private fun createPresenter(
+ crashDataStore: FakeCrashDataStore = FakeCrashDataStore(),
+ buildMeta: BuildMeta = aBuildMeta(),
+ ) = DefaultCrashDetectionPresenter(
+ buildMeta = buildMeta,
+ crashDataStore = crashDataStore,
+ )
}
diff --git a/features/roomactions/api/src/main/kotlin/io/element/android/features/roomactions/api/SetRoomIsFavoriteAction.kt b/features/roomactions/api/src/main/kotlin/io/element/android/features/roomactions/api/SetRoomIsFavoriteAction.kt
index 04f8bc8223..ecf1bcc4c9 100644
--- a/features/roomactions/api/src/main/kotlin/io/element/android/features/roomactions/api/SetRoomIsFavoriteAction.kt
+++ b/features/roomactions/api/src/main/kotlin/io/element/android/features/roomactions/api/SetRoomIsFavoriteAction.kt
@@ -21,9 +21,13 @@ import io.element.android.libraries.matrix.api.room.MatrixRoom
/**
* Set the favorite status of a room.
- * This will update the notable tags of the room.
+ * Use either the room id or the room instance with the desired favorite status.
*/
interface SetRoomIsFavoriteAction {
+
+ /**
+ * The result of the action?
+ */
sealed interface Result {
data object Success : Result
data object RoomNotFound : Result
diff --git a/features/roomactions/impl/src/main/kotlin/io/element/android/features/roomactions/impl/DefaultSetRoomIsFavoriteAction.kt b/features/roomactions/impl/src/main/kotlin/io/element/android/features/roomactions/impl/DefaultSetRoomIsFavoriteAction.kt
index dab51fa884..94abd618a1 100644
--- a/features/roomactions/impl/src/main/kotlin/io/element/android/features/roomactions/impl/DefaultSetRoomIsFavoriteAction.kt
+++ b/features/roomactions/impl/src/main/kotlin/io/element/android/features/roomactions/impl/DefaultSetRoomIsFavoriteAction.kt
@@ -48,5 +48,4 @@ class DefaultSetRoomIsFavoriteAction @Inject constructor(private val client: Mat
}
)
}
-
}
diff --git a/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/RoomDetailsView.kt b/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/RoomDetailsView.kt
index 401f6d024a..d3dbdb7ba0 100644
--- a/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/RoomDetailsView.kt
+++ b/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/RoomDetailsView.kt
@@ -212,12 +212,10 @@ private fun RoomDetailsTopBar(
goBack: () -> Unit,
onActionClicked: (RoomDetailsAction) -> Unit,
showEdit: Boolean,
- modifier: Modifier = Modifier,
) {
var showMenu by remember { mutableStateOf(false) }
TopAppBar(
- modifier = modifier,
title = { },
navigationIcon = { BackButton(onClick = goBack) },
actions = {
@@ -245,8 +243,14 @@ private fun RoomDetailsTopBar(
}
@Composable
-private fun MainActionsSection(state: RoomDetailsState, onShareRoom: () -> Unit, modifier: Modifier = Modifier) {
- Row(modifier.fillMaxWidth(), horizontalArrangement = Arrangement.Center) {
+private fun MainActionsSection(
+ state: RoomDetailsState,
+ onShareRoom: () -> Unit,
+) {
+ Row(
+ modifier = Modifier.fillMaxWidth(),
+ horizontalArrangement = Arrangement.Center,
+ ) {
val roomNotificationSettings = state.roomNotificationSettings
if (state.canShowNotificationSettings && roomNotificationSettings != null) {
if (roomNotificationSettings.mode == RoomNotificationMode.MUTE) {
@@ -283,10 +287,9 @@ private fun RoomHeaderSection(
roomName: String,
roomAlias: String?,
openAvatarPreview: (url: String) -> Unit,
- modifier: Modifier = Modifier
) {
Column(
- modifier = modifier
+ modifier = Modifier
.fillMaxWidth()
.padding(horizontal = 16.dp),
horizontalAlignment = Alignment.CenterHorizontally,
@@ -320,9 +323,8 @@ private fun RoomHeaderSection(
private fun TopicSection(
roomTopic: RoomTopicState,
onActionClicked: (RoomDetailsAction) -> Unit,
- modifier: Modifier = Modifier
) {
- PreferenceCategory(title = stringResource(CommonStrings.common_topic), modifier = modifier) {
+ PreferenceCategory(title = stringResource(CommonStrings.common_topic)) {
if (roomTopic is RoomTopicState.CanAddTopic) {
PreferenceText(
title = stringResource(R.string.screen_room_details_add_topic_title),
@@ -346,14 +348,13 @@ private fun TopicSection(
private fun NotificationSection(
isDefaultMode: Boolean,
openRoomNotificationSettings: () -> Unit,
- modifier: Modifier = Modifier
) {
val subtitle = if (isDefaultMode) {
stringResource(R.string.screen_room_details_notification_mode_default)
} else {
stringResource(R.string.screen_room_details_notification_mode_custom)
}
- PreferenceCategory(modifier = modifier) {
+ PreferenceCategory {
ListItem(
headlineContent = { Text(text = stringResource(R.string.screen_room_details_notification_title)) },
supportingContent = { Text(text = subtitle) },
@@ -383,9 +384,8 @@ private fun FavoriteSection(
private fun MembersSection(
memberCount: Long,
openRoomMemberList: () -> Unit,
- modifier: Modifier = Modifier,
) {
- PreferenceCategory(modifier = modifier) {
+ PreferenceCategory {
ListItem(
headlineContent = { Text(stringResource(CommonStrings.common_people)) },
leadingContent = ListItemContent.Icon(IconSource.Resource(CommonDrawables.ic_user)),
@@ -398,9 +398,8 @@ private fun MembersSection(
@Composable
private fun InviteSection(
invitePeople: () -> Unit,
- modifier: Modifier = Modifier,
) {
- PreferenceCategory(modifier = modifier) {
+ PreferenceCategory {
ListItem(
headlineContent = { Text(stringResource(R.string.screen_room_details_invite_people_title)) },
leadingContent = ListItemContent.Icon(IconSource.Resource(CommonDrawables.ic_user_add)),
@@ -412,9 +411,8 @@ private fun InviteSection(
@Composable
private fun PollsSection(
openPollHistory: () -> Unit,
- modifier: Modifier = Modifier,
) {
- PreferenceCategory(modifier = modifier) {
+ PreferenceCategory {
ListItem(
headlineContent = { Text(stringResource(R.string.screen_polls_history_title)) },
leadingContent = ListItemContent.Icon(IconSource.Vector(CompoundIcons.Polls)),
@@ -424,8 +422,8 @@ private fun PollsSection(
}
@Composable
-private fun SecuritySection(modifier: Modifier = Modifier) {
- PreferenceCategory(title = stringResource(R.string.screen_room_details_security_title), modifier = modifier) {
+private fun SecuritySection() {
+ PreferenceCategory(title = stringResource(R.string.screen_room_details_security_title)) {
ListItem(
headlineContent = { Text(stringResource(R.string.screen_room_details_encryption_enabled_title)) },
supportingContent = { Text(stringResource(R.string.screen_room_details_encryption_enabled_subtitle)) },
@@ -435,15 +433,17 @@ private fun SecuritySection(modifier: Modifier = Modifier) {
}
@Composable
-private fun OtherActionsSection(isDm: Boolean, onLeaveRoom: () -> Unit, modifier: Modifier = Modifier) {
- PreferenceCategory(showDivider = false, modifier = modifier) {
+private fun OtherActionsSection(isDm: Boolean, onLeaveRoom: () -> Unit) {
+ PreferenceCategory(showDivider = false) {
ListItem(
headlineContent = {
- val leaveText = stringResource(id = if (isDm) {
- R.string.screen_room_details_leave_conversation_title
- } else {
- R.string.screen_room_details_leave_room_title
- })
+ val leaveText = stringResource(
+ id = if (isDm) {
+ R.string.screen_room_details_leave_conversation_title
+ } else {
+ R.string.screen_room_details_leave_room_title
+ }
+ )
Text(leaveText)
},
leadingContent = ListItemContent.Icon(IconSource.Vector(CompoundIcons.Leave)),
diff --git a/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/blockuser/BlockUserSection.kt b/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/blockuser/BlockUserSection.kt
index 7ecf4ef1f9..6c397b9bc2 100644
--- a/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/blockuser/BlockUserSection.kt
+++ b/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/blockuser/BlockUserSection.kt
@@ -39,8 +39,8 @@ import io.element.android.libraries.designsystem.theme.components.Text
import io.element.android.libraries.ui.strings.CommonStrings
@Composable
-internal fun BlockUserSection(state: RoomMemberDetailsState, modifier: Modifier = Modifier) {
- PreferenceCategory(showDivider = false, modifier = modifier) {
+internal fun BlockUserSection(state: RoomMemberDetailsState) {
+ PreferenceCategory(showDivider = false) {
when (state.isBlocked) {
is AsyncData.Failure -> PreferenceBlockUser(isBlocked = state.isBlocked.prevData, isLoading = false, eventSink = state.eventSink)
is AsyncData.Loading -> PreferenceBlockUser(isBlocked = state.isBlocked.prevData, isLoading = true, eventSink = state.eventSink)
@@ -70,7 +70,6 @@ private fun PreferenceBlockUser(
isBlocked: Boolean?,
isLoading: Boolean,
eventSink: (RoomMemberDetailsEvents) -> Unit,
- modifier: Modifier = Modifier,
) {
val loadingCurrentValue = @Composable {
CircularProgressIndicator(
@@ -87,7 +86,6 @@ private fun PreferenceBlockUser(
onClick = { if (!isLoading) eventSink(RoomMemberDetailsEvents.UnblockUser(needsConfirmation = true)) },
trailingContent = if (isLoading) ListItemContent.Custom(loadingCurrentValue) else null,
style = ListItemStyle.Primary,
- modifier = modifier,
)
} else {
ListItem(
@@ -96,7 +94,6 @@ private fun PreferenceBlockUser(
style = ListItemStyle.Destructive,
onClick = { if (!isLoading) eventSink(RoomMemberDetailsEvents.BlockUser(needsConfirmation = true)) },
trailingContent = if (isLoading) ListItemContent.Custom(loadingCurrentValue) else null,
- modifier = modifier,
)
}
}
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 cac6e23878..b93bbd1f47 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
@@ -18,7 +18,6 @@
package io.element.android.features.roomdetails.impl.edit
-import androidx.compose.foundation.gestures.detectTapGestures
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Spacer
@@ -38,8 +37,6 @@ import androidx.compose.material3.MaterialTheme
import androidx.compose.runtime.Composable
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.ui.Modifier
-import androidx.compose.ui.focus.FocusManager
-import androidx.compose.ui.input.pointer.pointerInput
import androidx.compose.ui.platform.LocalFocusManager
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.input.KeyboardCapitalization
@@ -52,6 +49,7 @@ import io.element.android.libraries.designsystem.components.async.AsyncActionVie
import io.element.android.libraries.designsystem.components.async.AsyncActionViewDefaults
import io.element.android.libraries.designsystem.components.avatar.AvatarSize
import io.element.android.libraries.designsystem.components.button.BackButton
+import io.element.android.libraries.designsystem.modifiers.clearFocusOnTap
import io.element.android.libraries.designsystem.preview.ElementPreview
import io.element.android.libraries.designsystem.preview.PreviewsDayNight
import io.element.android.libraries.designsystem.theme.aliasScreenTitle
@@ -193,10 +191,8 @@ fun RoomDetailsEditView(
private fun LabelledReadOnlyField(
title: String,
value: String,
- modifier: Modifier = Modifier
) {
Column(
- modifier = modifier,
verticalArrangement = Arrangement.spacedBy(8.dp),
) {
Text(
@@ -215,13 +211,6 @@ private fun LabelledReadOnlyField(
}
}
-private fun Modifier.clearFocusOnTap(focusManager: FocusManager): Modifier =
- pointerInput(Unit) {
- detectTapGestures(onTap = {
- focusManager.clearFocus()
- })
- }
-
@PreviewsDayNight
@Composable
internal fun RoomDetailsEditViewPreview(@PreviewParameter(RoomDetailsEditStateProvider::class) state: RoomDetailsEditState) = ElementPreview {
diff --git a/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/invite/RoomInviteMembersView.kt b/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/invite/RoomInviteMembersView.kt
index d51e7c0a47..bc94519b3e 100644
--- a/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/invite/RoomInviteMembersView.kt
+++ b/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/invite/RoomInviteMembersView.kt
@@ -115,10 +115,8 @@ private fun RoomInviteMembersTopBar(
canSend: Boolean,
onBackPressed: () -> Unit,
onSubmitPressed: () -> Unit,
- modifier: Modifier = Modifier,
) {
TopAppBar(
- modifier = modifier,
title = {
Text(
text = stringResource(R.string.screen_room_details_invite_people_title),
diff --git a/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/members/RoomMemberListView.kt b/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/members/RoomMemberListView.kt
index 0fe08ef02c..37bfcf870e 100644
--- a/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/members/RoomMemberListView.kt
+++ b/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/members/RoomMemberListView.kt
@@ -194,10 +194,8 @@ private fun RoomMemberListTopBar(
canInvite: Boolean,
onBackPressed: () -> Unit,
onInvitePressed: () -> Unit,
- modifier: Modifier = Modifier,
) {
TopAppBar(
- modifier = modifier,
title = {
Text(
text = stringResource(CommonStrings.common_people),
diff --git a/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/members/details/RoomMemberDetailsView.kt b/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/members/details/RoomMemberDetailsView.kt
index 8463c98ee0..56475f92c2 100644
--- a/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/members/details/RoomMemberDetailsView.kt
+++ b/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/members/details/RoomMemberDetailsView.kt
@@ -108,14 +108,12 @@ fun RoomMemberDetailsView(
@Composable
private fun StartDMSection(
onStartDMClicked: () -> Unit,
- modifier: Modifier = Modifier
) {
ListItem(
headlineContent = { Text(stringResource(CommonStrings.common_direct_chat)) },
leadingContent = ListItemContent.Icon(IconSource.Vector(CompoundIcons.Chat)),
style = ListItemStyle.Primary,
onClick = onStartDMClicked,
- modifier = modifier,
)
}
diff --git a/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/notificationsettings/RoomNotificationSettingsView.kt b/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/notificationsettings/RoomNotificationSettingsView.kt
index f534fb17f4..75dabb9772 100644
--- a/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/notificationsettings/RoomNotificationSettingsView.kt
+++ b/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/notificationsettings/RoomNotificationSettingsView.kt
@@ -178,10 +178,8 @@ private fun RoomSpecificNotificationSettingsView(
@Composable
private fun RoomNotificationSettingsTopBar(
onBackPressed: () -> Unit,
- modifier: Modifier = Modifier,
) {
TopAppBar(
- modifier = modifier,
title = {
Text(
text = stringResource(R.string.screen_room_details_notification_title),
diff --git a/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/notificationsettings/UserDefinedRoomNotificationSettingsView.kt b/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/notificationsettings/UserDefinedRoomNotificationSettingsView.kt
index df1a41ea87..99903b7466 100644
--- a/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/notificationsettings/UserDefinedRoomNotificationSettingsView.kt
+++ b/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/notificationsettings/UserDefinedRoomNotificationSettingsView.kt
@@ -103,10 +103,8 @@ fun UserDefinedRoomNotificationSettingsView(
private fun UserDefinedRoomNotificationSettingsTopBar(
roomName: String,
onBackPressed: () -> Unit,
- modifier: Modifier = Modifier,
) {
TopAppBar(
- modifier = modifier,
title = {
Text(
text = roomName,
diff --git a/features/roomdetails/impl/src/main/res/values-be/translations.xml b/features/roomdetails/impl/src/main/res/values-be/translations.xml
new file mode 100644
index 0000000000..3debaf9166
--- /dev/null
+++ b/features/roomdetails/impl/src/main/res/values-be/translations.xml
@@ -0,0 +1,56 @@
+
+
+
+ - "%1$d карыстальнік"
+ - "%1$d карыстальнікаў"
+ - "%1$d карыстальнікаў"
+
+ "Пры абнаўленні налад апавяшчэнняў адбылася памылка."
+ "Ваш хатні сервер не падтрымлівае гэтую опцыю ў зашыфраваных пакоях, вы можаце не атрымаць апавяшчэнне ў некаторых пакоях."
+ "Апытанні"
+ "Дадаць тэму"
+ "Ужо ўдзельнік"
+ "Ужо запрасілі"
+ "Рэдагаваць пакой"
+ "Адбылася невядомая памылка, і інфармацыю нельга было змяніць."
+ "Немагчыма абнавіць пакой"
+ "Паведамленні абаронены замкамі. Толькі ў вас і атрымальнікаў ёсць унікальныя ключы, каб разблакіраваць іх."
+ "Шыфраванне паведамленняў уключана"
+ "Пры загрузцы налад апавяшчэнняў адбылася памылка."
+ "Не атрымалася адключыць гук у гэтым пакоі, паўтарыце спробу."
+ "Не ўдалося ўключыць гук у гэтым пакоі. Паўтарыце спробу."
+ "Запрасіць людзей"
+ "Карыстальніцкі"
+ "Па змаўчанні"
+ "Апавяшчэнні"
+ "Падзяліцца пакоем"
+ "Ідзе абнаўленне пакоя…"
+ "У чаканні"
+ "Карыстальнікі пакоя"
+ "Дазволіць карыстальніцкую наладу"
+ "Калі гэта ўключыць, ваша налада па змаўчанні будзе адменена"
+ "Апавяшчаць мяне ў гэтым чаце для"
+ "Вы можаце змяніць яго ў сваім %1$s."
+ "глабальныя налады"
+ "Налада па змаўчанні"
+ "Выдаліць карыстальніцкую наладу"
+ "Падчас загрузкі налад апавяшчэнняў адбылася памылка."
+ "Не атрымалася аднавіць рэжым па змаўчанні, паспрабуйце яшчэ раз."
+ "Не ўдалося наладзіць рэжым, паспрабуйце яшчэ раз."
+ "Ваш хатні сервер не падтрымлівае гэту опцыю ў зашыфраваных пакоях, вы не атрымаеце апавяшчэнне ў гэтым пакоі."
+ "Усе паведамленні"
+ "У гэтым пакоі паведаміце мяне пра"
+ "Пры спробе пачаць чат адбылася памылка"
+ "Заблакіраваць"
+ "Заблакіраваныя карыстальнікі не змогуць адпраўляць вам паведамленні, і ўсе іх паведамленні будуць схаваны. Вы можаце разблакіраваць іх у любы час."
+ "Заблакіраваць карыстальніка"
+ "Разблакіраваць"
+ "Вы зноў зможаце ўбачыць усе паведамленні."
+ "Разблакіраваць карыстальніка"
+ "Пакінуць размову"
+ "Пакінуць пакой"
+ "Назва пакоя"
+ "Бяспека"
+ "Тэма"
+ "Толькі згадванні і ключавыя словы"
+
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 e6316cfec1..f8658bd86b 100644
--- a/features/roomdetails/impl/src/main/res/values-cs/translations.xml
+++ b/features/roomdetails/impl/src/main/res/values-cs/translations.xml
@@ -23,7 +23,6 @@
"Vlastní"
"Výchozí"
"Oznámení"
- "Název místnosti"
"Sdílet místnost"
"Aktualizace místnosti…"
"Nevyřízeno"
@@ -50,6 +49,7 @@
"Odblokovat uživatele"
"Opustit konverzaci"
"Opustit místnost"
+ "Název místnosti"
"Zabezpečení"
"Téma"
"Pouze zmínky a klíčová slova"
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 dbf2742e10..c070b7fe3d 100644
--- a/features/roomdetails/impl/src/main/res/values-de/translations.xml
+++ b/features/roomdetails/impl/src/main/res/values-de/translations.xml
@@ -22,7 +22,6 @@
"Benutzerdefiniert"
"Standard"
"Benachrichtigungen"
- "Raumname"
"Raum teilen"
"Raum wird aktualisiert…"
"Ausstehend"
@@ -47,7 +46,9 @@
"Blockierung aufheben"
"Du kannst dann wieder alle Nachrichten von ihnen sehen."
"Blockierung aufheben"
+ "Unterhaltung verlassen"
"Raum verlassen"
+ "Raumname"
"Sicherheit"
"Thema"
"Nur Erwähnungen und Schlüsselwörter"
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 f4e598ed71..2a119d013c 100644
--- a/features/roomdetails/impl/src/main/res/values-es/translations.xml
+++ b/features/roomdetails/impl/src/main/res/values-es/translations.xml
@@ -22,7 +22,6 @@
"Personalizado"
"Por defecto"
"Notificaciones"
- "Nombre de la sala"
"Compartir sala"
"Actualizando la sala…"
"Pendiente"
@@ -48,6 +47,7 @@
"Podrás ver todos sus mensajes de nuevo."
"Desbloquear usuario"
"Salir de la sala"
+ "Nombre de la sala"
"Seguridad"
"Tema"
"Únicamente Menciones y Palabras clave"
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 76e3ea81ec..51d40233d4 100644
--- a/features/roomdetails/impl/src/main/res/values-fr/translations.xml
+++ b/features/roomdetails/impl/src/main/res/values-fr/translations.xml
@@ -22,7 +22,6 @@
"Personnalisé"
"Défaut"
"Notifications"
- "Nom du salon"
"Partager le salon"
"Mise à jour du salon…"
"En attente"
@@ -49,6 +48,7 @@
"Débloquer l’utilisateur"
"Quitter la discussion"
"Quitter le salon"
+ "Nom du salon"
"Sécurité"
"Sujet"
"Mentions et mots clés uniquement"
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 803b493585..2c16665001 100644
--- a/features/roomdetails/impl/src/main/res/values-hu/translations.xml
+++ b/features/roomdetails/impl/src/main/res/values-hu/translations.xml
@@ -22,7 +22,6 @@
"Egyéni"
"Alapértelmezett"
"Értesítések"
- "Szoba neve"
"Szoba megosztása"
"Szoba frissítése…"
"Függőben"
@@ -47,7 +46,9 @@
"Letiltás feloldása"
"Újra láthatja az összes üzenetét."
"Felhasználó kitiltásának feloldása"
+ "Beszélgetés elhagyása"
"Szoba elhagyása"
+ "Szoba neve"
"Biztonság"
"Téma"
"Csak említések és kulcsszavak"
diff --git a/features/roomdetails/impl/src/main/res/values-in/translations.xml b/features/roomdetails/impl/src/main/res/values-in/translations.xml
index d44f24342b..a5f415decc 100644
--- a/features/roomdetails/impl/src/main/res/values-in/translations.xml
+++ b/features/roomdetails/impl/src/main/res/values-in/translations.xml
@@ -21,7 +21,6 @@
"Khusus"
"Bawaan"
"Pemberitahuan"
- "Nama ruangan"
"Bagikan ruangan"
"Memperbarui ruangan…"
"Tertunda"
@@ -47,6 +46,7 @@
"Anda akan dapat melihat semua pesan dari mereka lagi."
"Buka blokir pengguna"
"Tinggalkan ruangan"
+ "Nama ruangan"
"Keamanan"
"Topik"
"Sebutan dan Kata Kunci saja"
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 664c2dbd85..269ee39a2b 100644
--- a/features/roomdetails/impl/src/main/res/values-it/translations.xml
+++ b/features/roomdetails/impl/src/main/res/values-it/translations.xml
@@ -22,7 +22,6 @@
"Personalizzato"
"Predefinito"
"Notifiche"
- "Nome stanza"
"Condividi stanza"
"Aggiornamento della stanza…"
"In attesa"
@@ -49,6 +48,7 @@
"Sblocca utente"
"Abbandona la conversazione"
"Esci dalla stanza"
+ "Nome stanza"
"Sicurezza"
"Oggetto"
"Solo menzioni e parole chiave"
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 be6217d5e9..99581bed6b 100644
--- a/features/roomdetails/impl/src/main/res/values-ro/translations.xml
+++ b/features/roomdetails/impl/src/main/res/values-ro/translations.xml
@@ -20,7 +20,6 @@
"Personalizat"
"Implicit"
"Notificări"
- "Numele camerei"
"Partajați camera"
"Se actualizează camera…"
"În așteptare"
@@ -45,6 +44,7 @@
"La deblocarea utilizatorului, veți putea vedea din nou toate mesajele de la acesta."
"Deblocați utilizatorul"
"Părăsiți camera"
+ "Numele camerei"
"Securitate"
"Subiect"
"Numai mențiuni și cuvinte cheie"
diff --git a/features/roomdetails/impl/src/main/res/values-ru/translations.xml b/features/roomdetails/impl/src/main/res/values-ru/translations.xml
index 4412d7be4d..541592a77f 100644
--- a/features/roomdetails/impl/src/main/res/values-ru/translations.xml
+++ b/features/roomdetails/impl/src/main/res/values-ru/translations.xml
@@ -23,10 +23,11 @@
"Пользовательский"
"По умолчанию"
"Уведомления"
- "Название комнаты"
"Поделиться комнатой"
"Обновление комнаты…"
"В ожидании"
+ "Администратор"
+ "Модератор"
"Участники комнаты"
"Разрешить пользовательские настройки"
"Включение этого параметра отменяет настройки по умолчанию"
@@ -50,6 +51,7 @@
"Разблокировать пользователя"
"Покинуть беседу"
"Покинуть комнату"
+ "Название комнаты"
"Безопасность"
"Тема"
"Только упоминания и ключевые слова"
diff --git a/features/roomdetails/impl/src/main/res/values-sk/translations.xml b/features/roomdetails/impl/src/main/res/values-sk/translations.xml
index c9afe72b80..9821d5ea50 100644
--- a/features/roomdetails/impl/src/main/res/values-sk/translations.xml
+++ b/features/roomdetails/impl/src/main/res/values-sk/translations.xml
@@ -23,10 +23,11 @@
"Vlastné"
"Predvolené"
"Oznámenia"
- "Názov miestnosti"
"Zdieľať miestnosť"
"Aktualizácia miestnosti…"
"Čaká sa"
+ "Administrátor"
+ "Moderátor"
"Členovia miestnosti"
"Povoliť vlastné nastavenie"
"Zapnutím tohto nastavenia sa prepíše vaše predvolené nastavenie"
@@ -50,6 +51,7 @@
"Odblokovať používateľa"
"Opustiť konverzáciu"
"Opustiť miestnosť"
+ "Názov miestnosti"
"Bezpečnosť"
"Téma"
"Iba zmienky a kľúčové slová"
diff --git a/features/roomdetails/impl/src/main/res/values-zh-rTW/translations.xml b/features/roomdetails/impl/src/main/res/values-zh-rTW/translations.xml
index 50202c0e81..1cd51322e5 100644
--- a/features/roomdetails/impl/src/main/res/values-zh-rTW/translations.xml
+++ b/features/roomdetails/impl/src/main/res/values-zh-rTW/translations.xml
@@ -17,7 +17,6 @@
"自訂"
"預設"
"通知"
- "聊天室名稱"
"分享聊天室"
"正在更新聊天室…"
"待定"
@@ -32,6 +31,7 @@
"解除封鎖"
"解除封鎖使用者"
"離開聊天室"
+ "聊天室名稱"
"安全性"
"主題"
"僅限提及與關鍵字"
diff --git a/features/roomdetails/impl/src/main/res/values/localazy.xml b/features/roomdetails/impl/src/main/res/values/localazy.xml
index 2693b40edb..f2d3c16aad 100644
--- a/features/roomdetails/impl/src/main/res/values/localazy.xml
+++ b/features/roomdetails/impl/src/main/res/values/localazy.xml
@@ -22,10 +22,11 @@
"Custom"
"Default"
"Notifications"
- "Room name"
"Share room"
"Updating room…"
"Pending"
+ "Admin"
+ "Moderator"
"Room members"
"Allow custom setting"
"Turning this on will override your default setting"
@@ -49,6 +50,7 @@
"Unblock user"
"Leave conversation"
"Leave room"
+ "Room name"
"Security"
"Topic"
"Mentions and Keywords only"
diff --git a/features/ftue/impl/src/main/kotlin/io/element/android/features/ftue/impl/migration/MigrationScreenStore.kt b/features/roomlist/api/src/main/kotlin/io/element/android/features/roomlist/api/migration/MigrationScreenStore.kt
similarity index 93%
rename from features/ftue/impl/src/main/kotlin/io/element/android/features/ftue/impl/migration/MigrationScreenStore.kt
rename to features/roomlist/api/src/main/kotlin/io/element/android/features/roomlist/api/migration/MigrationScreenStore.kt
index 42eeab673a..6e20b1ad4a 100644
--- a/features/ftue/impl/src/main/kotlin/io/element/android/features/ftue/impl/migration/MigrationScreenStore.kt
+++ b/features/roomlist/api/src/main/kotlin/io/element/android/features/roomlist/api/migration/MigrationScreenStore.kt
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package io.element.android.features.ftue.impl.migration
+package io.element.android.features.roomlist.api.migration
import io.element.android.libraries.matrix.api.core.SessionId
diff --git a/features/roomlist/impl/build.gradle.kts b/features/roomlist/impl/build.gradle.kts
index fdb0e7a3e2..ff14371ced 100644
--- a/features/roomlist/impl/build.gradle.kts
+++ b/features/roomlist/impl/build.gradle.kts
@@ -52,6 +52,7 @@ dependencies {
implementation(projects.libraries.eventformatter.api)
implementation(projects.libraries.indicator.api)
implementation(projects.libraries.deeplink)
+ implementation(projects.libraries.preferences.api)
implementation(projects.features.invitelist.api)
implementation(projects.features.networkmonitor.api)
implementation(projects.features.leaveroom.api)
@@ -60,6 +61,8 @@ dependencies {
api(projects.features.roomlist.api)
ksp(libs.showkase.processor)
+ testImplementation(libs.androidx.compose.ui.test.junit)
+ testReleaseImplementation(libs.androidx.compose.ui.test.manifest)
testImplementation(libs.test.junit)
testImplementation(libs.coroutines.test)
testImplementation(libs.molecule.runtime)
@@ -72,6 +75,7 @@ dependencies {
testImplementation(projects.libraries.eventformatter.test)
testImplementation(projects.libraries.indicator.impl)
testImplementation(projects.libraries.permissions.noop)
+ testImplementation(projects.libraries.preferences.test)
testImplementation(projects.features.invitelist.test)
testImplementation(projects.features.networkmonitor.test)
testImplementation(projects.tests.testutils)
diff --git a/features/roomlist/impl/src/main/kotlin/io/element/android/features/roomlist/impl/RoomListContextMenu.kt b/features/roomlist/impl/src/main/kotlin/io/element/android/features/roomlist/impl/RoomListContextMenu.kt
index dc448a412c..d80cdf15a5 100644
--- a/features/roomlist/impl/src/main/kotlin/io/element/android/features/roomlist/impl/RoomListContextMenu.kt
+++ b/features/roomlist/impl/src/main/kotlin/io/element/android/features/roomlist/impl/RoomListContextMenu.kt
@@ -43,7 +43,7 @@ import io.element.android.libraries.ui.strings.CommonStrings
@Composable
fun RoomListContextMenu(
contextMenu: RoomListState.ContextMenu.Shown,
- eventSink: (RoomListEvents) -> Unit,
+ eventSink: (RoomListEvents.RoomListBottomSheetEvents) -> Unit,
onRoomSettingsClicked: (roomId: RoomId) -> Unit,
) {
ModalBottomSheet(
@@ -51,9 +51,17 @@ fun RoomListContextMenu(
) {
RoomListModalBottomSheetContent(
contextMenu = contextMenu,
+ onRoomMarkReadClicked = {
+ eventSink(RoomListEvents.HideContextMenu)
+ eventSink(RoomListEvents.MarkAsRead(contextMenu.roomId))
+ },
+ onRoomMarkUnreadClicked = {
+ eventSink(RoomListEvents.HideContextMenu)
+ eventSink(RoomListEvents.MarkAsUnread(contextMenu.roomId))
+ },
onRoomSettingsClicked = {
eventSink(RoomListEvents.HideContextMenu)
- onRoomSettingsClicked(it)
+ onRoomSettingsClicked(contextMenu.roomId)
},
onLeaveRoomClicked = {
eventSink(RoomListEvents.HideContextMenu)
@@ -69,9 +77,11 @@ fun RoomListContextMenu(
@Composable
private fun RoomListModalBottomSheetContent(
contextMenu: RoomListState.ContextMenu.Shown,
- onRoomSettingsClicked: (roomId: RoomId) -> Unit,
- onLeaveRoomClicked: (roomId: RoomId) -> Unit,
+ onRoomSettingsClicked: () -> Unit,
+ onLeaveRoomClicked: () -> Unit,
onFavoriteChanged: (isFavorite: Boolean) -> Unit,
+ onRoomMarkReadClicked: () -> Unit,
+ onRoomMarkUnreadClicked: () -> Unit,
) {
Column(
modifier = Modifier.fillMaxWidth()
@@ -84,6 +94,38 @@ private fun RoomListModalBottomSheetContent(
)
}
)
+ if (contextMenu.markAsUnreadFeatureFlagEnabled) {
+ ListItem(
+ headlineContent = {
+ Text(
+ text = stringResource(
+ id = if (contextMenu.hasNewContent) {
+ R.string.screen_roomlist_mark_as_read
+ } else {
+ R.string.screen_roomlist_mark_as_unread
+ }
+ ),
+ style = MaterialTheme.typography.bodyLarge,
+ )
+ },
+ modifier = Modifier.clickable {
+ if (contextMenu.hasNewContent) {
+ onRoomMarkReadClicked()
+ } else {
+ onRoomMarkUnreadClicked()
+ }
+ },
+ /* TODO Design
+ leadingContent = ListItemContent.Icon(
+ iconSource = IconSource.Vector(
+ CompoundIcons.Settings,
+ contentDescription = stringResource(id = CommonStrings.common_settings)
+ )
+ ),
+ */
+ style = ListItemStyle.Primary,
+ )
+ }
ListItem(
headlineContent = {
Text(
@@ -116,7 +158,7 @@ private fun RoomListModalBottomSheetContent(
style = MaterialTheme.typography.bodyLarge,
)
},
- modifier = Modifier.clickable { onRoomSettingsClicked(contextMenu.roomId) },
+ modifier = Modifier.clickable { onRoomSettingsClicked() },
leadingContent = ListItemContent.Icon(
iconSource = IconSource.Vector(
CompoundIcons.Settings,
@@ -136,7 +178,7 @@ private fun RoomListModalBottomSheetContent(
)
Text(text = leaveText)
},
- modifier = Modifier.clickable { onLeaveRoomClicked(contextMenu.roomId) },
+ modifier = Modifier.clickable { onLeaveRoomClicked() },
leadingContent = ListItemContent.Icon(
iconSource = IconSource.Vector(
CompoundIcons.Leave,
@@ -155,12 +197,9 @@ private fun RoomListModalBottomSheetContent(
@Composable
internal fun RoomListModalBottomSheetContentPreview() = ElementPreview {
RoomListModalBottomSheetContent(
- contextMenu = RoomListState.ContextMenu.Shown(
- roomId = RoomId(value = "!aRoom:aDomain"),
- roomName = "aRoom",
- isDm = false,
- isFavorite = AsyncData.Success(false),
- ),
+ contextMenu = aContextMenuShown(hasNewContent = true),
+ onRoomMarkReadClicked = {},
+ onRoomMarkUnreadClicked = {},
onRoomSettingsClicked = {},
onLeaveRoomClicked = {},
onFavoriteChanged = {},
@@ -171,12 +210,9 @@ internal fun RoomListModalBottomSheetContentPreview() = ElementPreview {
@Composable
internal fun RoomListModalBottomSheetContentForDmPreview() = ElementPreview {
RoomListModalBottomSheetContent(
- contextMenu = RoomListState.ContextMenu.Shown(
- roomId = RoomId(value = "!aRoom:aDomain"),
- roomName = "aRoom",
- isDm = true,
- isFavorite = AsyncData.Success(false),
- ),
+ contextMenu = aContextMenuShown(isDm = true),
+ onRoomMarkReadClicked = {},
+ onRoomMarkUnreadClicked = {},
onRoomSettingsClicked = {},
onLeaveRoomClicked = {},
onFavoriteChanged = {},
diff --git a/features/roomlist/impl/src/main/kotlin/io/element/android/features/roomlist/impl/RoomListEvents.kt b/features/roomlist/impl/src/main/kotlin/io/element/android/features/roomlist/impl/RoomListEvents.kt
index b707de4055..8ef496dc94 100644
--- a/features/roomlist/impl/src/main/kotlin/io/element/android/features/roomlist/impl/RoomListEvents.kt
+++ b/features/roomlist/impl/src/main/kotlin/io/element/android/features/roomlist/impl/RoomListEvents.kt
@@ -26,7 +26,11 @@ sealed interface RoomListEvents {
data object DismissRecoveryKeyPrompt : RoomListEvents
data object ToggleSearchResults : RoomListEvents
data class ShowContextMenu(val roomListRoomSummary: RoomListRoomSummary) : RoomListEvents
- data object HideContextMenu : RoomListEvents
- data class LeaveRoom(val roomId: RoomId) : RoomListEvents
- data class SetRoomIsFavorite(val roomId: RoomId, val isFavorite: Boolean) : RoomListEvents
+
+ sealed interface RoomListBottomSheetEvents : RoomListEvents
+ data object HideContextMenu : RoomListBottomSheetEvents
+ data class LeaveRoom(val roomId: RoomId) : RoomListBottomSheetEvents
+ data class MarkAsRead(val roomId: RoomId) : RoomListBottomSheetEvents
+ data class MarkAsUnread(val roomId: RoomId) : RoomListBottomSheetEvents
+ data class SetRoomIsFavorite(val roomId: RoomId, val isFavorite: Boolean) : RoomListBottomSheetEvents
}
diff --git a/features/roomlist/impl/src/main/kotlin/io/element/android/features/roomlist/impl/RoomListPresenter.kt b/features/roomlist/impl/src/main/kotlin/io/element/android/features/roomlist/impl/RoomListPresenter.kt
index 5b8c7a37ab..c9e63029d6 100644
--- a/features/roomlist/impl/src/main/kotlin/io/element/android/features/roomlist/impl/RoomListPresenter.kt
+++ b/features/roomlist/impl/src/main/kotlin/io/element/android/features/roomlist/impl/RoomListPresenter.kt
@@ -23,6 +23,7 @@ import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.derivedStateOf
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
+import androidx.compose.runtime.produceState
import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.runtime.saveable.rememberSaveable
@@ -31,9 +32,11 @@ import io.element.android.features.leaveroom.api.LeaveRoomEvent
import io.element.android.features.leaveroom.api.LeaveRoomPresenter
import io.element.android.features.networkmonitor.api.NetworkMonitor
import io.element.android.features.networkmonitor.api.NetworkStatus
+import io.element.android.features.preferences.api.store.SessionPreferencesStore
import io.element.android.features.roomactions.api.SetRoomIsFavoriteAction
import io.element.android.features.roomlist.impl.datasource.InviteStateDataSource
import io.element.android.features.roomlist.impl.datasource.RoomListDataSource
+import io.element.android.features.roomlist.impl.migration.MigrationScreenPresenter
import io.element.android.libraries.architecture.AsyncData
import io.element.android.libraries.architecture.Presenter
import io.element.android.libraries.architecture.coroutine.cancel
@@ -46,12 +49,14 @@ import io.element.android.libraries.indicator.api.IndicatorService
import io.element.android.libraries.matrix.api.MatrixClient
import io.element.android.libraries.matrix.api.encryption.EncryptionService
import io.element.android.libraries.matrix.api.encryption.RecoveryState
+import io.element.android.libraries.matrix.api.timeline.ReceiptType
import io.element.android.libraries.matrix.api.user.MatrixUser
import io.element.android.libraries.matrix.api.user.getCurrentUser
import io.element.android.libraries.matrix.api.verification.SessionVerificationService
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.collect
import kotlinx.coroutines.flow.distinctUntilChanged
+import kotlinx.coroutines.flow.first
import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.launch
import javax.inject.Inject
@@ -70,23 +75,30 @@ class RoomListPresenter @Inject constructor(
private val featureFlagService: FeatureFlagService,
private val indicatorService: IndicatorService,
private val setRoomIsFavorite: SetRoomIsFavoriteAction,
+ private val migrationScreenPresenter: MigrationScreenPresenter,
+ private val sessionPreferencesStore: SessionPreferencesStore,
) : Presenter {
@Composable
override fun present(): RoomListState {
+ val coroutineScope = rememberCoroutineScope()
val leaveRoomState = leaveRoomPresenter.present()
val matrixUser: MutableState = rememberSaveable {
mutableStateOf(null)
}
- val roomList by roomListDataSource.allRooms.collectAsState()
+ val roomList by produceState(initialValue = AsyncData.Loading()) {
+ roomListDataSource.allRooms.collect { value = AsyncData.Success(it) }
+ }
val filteredRoomList by roomListDataSource.filteredRooms.collectAsState()
val filter by roomListDataSource.filter.collectAsState()
val networkConnectionStatus by networkMonitor.connectivity.collectAsState()
- val coroutineScope = rememberCoroutineScope()
LaunchedEffect(Unit) {
roomListDataSource.launchIn(this)
initialLoad(matrixUser)
}
+
+ val isMigrating = migrationScreenPresenter.present().isMigrating
+
// Session verification status (unknown, not verified, verified)
val canVerifySession by sessionVerificationService.canVerifySessionFlow.collectAsState(initial = false)
var verificationPromptDismissed by rememberSaveable { mutableStateOf(false) }
@@ -133,7 +145,19 @@ class RoomListPresenter @Inject constructor(
contextMenu.value = RoomListState.ContextMenu.Hidden
}
is RoomListEvents.LeaveRoom -> leaveRoomState.eventSink(LeaveRoomEvent.ShowConfirmation(event.roomId))
+
is RoomListEvents.SetRoomIsFavorite -> coroutineScope.setRoomIsFavorite(event)
+ is RoomListEvents.MarkAsRead -> coroutineScope.launch {
+ val receiptType = if (sessionPreferencesStore.isSendPublicReadReceiptsEnabled().first()) {
+ ReceiptType.READ
+ } else {
+ ReceiptType.READ_PRIVATE
+ }
+ client.getRoom(event.roomId)?.markAsRead(receiptType)
+ }
+ is RoomListEvents.MarkAsUnread -> coroutineScope.launch {
+ client.getRoom(event.roomId)?.markAsUnread()
+ }
}
}
@@ -153,6 +177,7 @@ class RoomListPresenter @Inject constructor(
displaySearchResults = displaySearchResults,
contextMenu = contextMenu.value,
leaveRoomState = leaveRoomState,
+ displayMigrationStatus = isMigrating,
eventSink = ::handleEvents
)
}
@@ -167,6 +192,8 @@ class RoomListPresenter @Inject constructor(
roomName = event.roomListRoomSummary.name,
isDm = event.roomListRoomSummary.isDm,
isFavorite = AsyncData.Loading(),
+ markAsUnreadFeatureFlagEnabled = featureFlagService.isFeatureEnabled(FeatureFlags.MarkAsUnread),
+ hasNewContent = event.roomListRoomSummary.hasNewContent
)
contextMenuState.value = initialState
client.getRoom(event.roomListRoomSummary.roomId).use { room ->
diff --git a/features/roomlist/impl/src/main/kotlin/io/element/android/features/roomlist/impl/RoomListState.kt b/features/roomlist/impl/src/main/kotlin/io/element/android/features/roomlist/impl/RoomListState.kt
index 5f5a5fda4c..23911f8eb2 100644
--- a/features/roomlist/impl/src/main/kotlin/io/element/android/features/roomlist/impl/RoomListState.kt
+++ b/features/roomlist/impl/src/main/kotlin/io/element/android/features/roomlist/impl/RoomListState.kt
@@ -29,7 +29,7 @@ import kotlinx.collections.immutable.ImmutableList
data class RoomListState(
val matrixUser: MatrixUser?,
val showAvatarIndicator: Boolean,
- val roomList: ImmutableList,
+ val roomList: AsyncData>,
val filter: String?,
val filteredRoomList: ImmutableList,
val displayVerificationPrompt: Boolean,
@@ -40,6 +40,7 @@ data class RoomListState(
val displaySearchResults: Boolean,
val contextMenu: ContextMenu,
val leaveRoomState: LeaveRoomState,
+ val displayMigrationStatus: Boolean,
val eventSink: (RoomListEvents) -> Unit,
) {
sealed interface ContextMenu {
@@ -49,6 +50,8 @@ data class RoomListState(
val roomName: String,
val isDm: Boolean,
val isFavorite: AsyncData,
+ val markAsUnreadFeatureFlagEnabled: Boolean,
+ val hasNewContent: Boolean,
) : ContextMenu
}
}
diff --git a/features/roomlist/impl/src/main/kotlin/io/element/android/features/roomlist/impl/RoomListStateProvider.kt b/features/roomlist/impl/src/main/kotlin/io/element/android/features/roomlist/impl/RoomListStateProvider.kt
index 7ac34668c7..95eac47dd6 100644
--- a/features/roomlist/impl/src/main/kotlin/io/element/android/features/roomlist/impl/RoomListStateProvider.kt
+++ b/features/roomlist/impl/src/main/kotlin/io/element/android/features/roomlist/impl/RoomListStateProvider.kt
@@ -18,6 +18,7 @@ package io.element.android.features.roomlist.impl
import androidx.compose.ui.tooling.preview.PreviewParameterProvider
import io.element.android.features.leaveroom.api.aLeaveRoomState
+import io.element.android.features.roomlist.impl.datasource.RoomListRoomSummaryFactory
import io.element.android.features.roomlist.impl.model.RoomListRoomSummary
import io.element.android.features.roomlist.impl.model.aRoomListRoomSummary
import io.element.android.libraries.architecture.AsyncData
@@ -42,22 +43,19 @@ open class RoomListStateProvider : PreviewParameterProvider {
aRoomListState().copy(invitesState = InvitesState.NewInvites),
aRoomListState().copy(displaySearchResults = true, filter = "", filteredRoomList = persistentListOf()),
aRoomListState().copy(displaySearchResults = true),
- aRoomListState().copy(
- contextMenu = RoomListState.ContextMenu.Shown(
- roomId = RoomId("!aRoom:aDomain"),
- roomName = "A nice room name",
- isDm = false,
- isFavorite = AsyncData.Success(true),
- )
- ),
+ aRoomListState().copy(contextMenu = aContextMenuShown(roomName = "A nice room name")),
+ aRoomListState().copy(contextMenu = aContextMenuShown(isFavorite = AsyncData.Success(true))),
aRoomListState().copy(displayRecoveryKeyPrompt = true),
+ aRoomListState().copy(roomList = AsyncData.Success(persistentListOf())),
+ aRoomListState().copy(roomList = AsyncData.Loading(prevData = RoomListRoomSummaryFactory.createFakeList())),
+ aRoomListState().copy(matrixUser = null, displayMigrationStatus = true),
)
}
internal fun aRoomListState() = RoomListState(
matrixUser = MatrixUser(userId = UserId("@id:domain"), displayName = "User#1"),
showAvatarIndicator = false,
- roomList = aRoomListRoomSummaryList(),
+ roomList = AsyncData.Success(aRoomListRoomSummaryList()),
filter = "filter",
filteredRoomList = aRoomListRoomSummaryList(),
hasNetworkConnection = true,
@@ -68,6 +66,7 @@ internal fun aRoomListState() = RoomListState(
displaySearchResults = false,
contextMenu = RoomListState.ContextMenu.Hidden,
leaveRoomState = aLeaveRoomState(),
+ displayMigrationStatus = false,
eventSink = {}
)
@@ -99,3 +98,17 @@ internal fun aRoomListRoomSummaryList(): ImmutableList {
),
)
}
+
+internal fun aContextMenuShown(
+ roomName: String = "aRoom",
+ isDm: Boolean = false,
+ hasNewContent: Boolean = false,
+ isFavorite: AsyncData = AsyncData.Success(false),
+) = RoomListState.ContextMenu.Shown(
+ roomId = RoomId("!aRoom:aDomain"),
+ roomName = roomName,
+ isDm = isDm,
+ markAsUnreadFeatureFlagEnabled = true,
+ hasNewContent = hasNewContent,
+ isFavorite = isFavorite,
+)
diff --git a/features/roomlist/impl/src/main/kotlin/io/element/android/features/roomlist/impl/RoomListView.kt b/features/roomlist/impl/src/main/kotlin/io/element/android/features/roomlist/impl/RoomListView.kt
index 0a9f4f523b..3d084e15c4 100644
--- a/features/roomlist/impl/src/main/kotlin/io/element/android/features/roomlist/impl/RoomListView.kt
+++ b/features/roomlist/impl/src/main/kotlin/io/element/android/features/roomlist/impl/RoomListView.kt
@@ -17,7 +17,10 @@
package io.element.android.features.roomlist.impl
import androidx.compose.foundation.background
+import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
+import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.consumeWindowInsets
import androidx.compose.foundation.layout.fillMaxSize
@@ -35,6 +38,7 @@ import androidx.compose.runtime.Composable
import androidx.compose.runtime.derivedStateOf
import androidx.compose.runtime.getValue
import androidx.compose.runtime.remember
+import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.input.nestedscroll.NestedScrollConnection
import androidx.compose.ui.input.nestedscroll.nestedScroll
@@ -42,6 +46,7 @@ import androidx.compose.ui.res.stringResource
import androidx.compose.ui.tooling.preview.PreviewParameter
import androidx.compose.ui.unit.Velocity
import androidx.compose.ui.unit.dp
+import io.element.android.compound.theme.ElementTheme
import io.element.android.features.leaveroom.api.LeaveRoomView
import io.element.android.features.networkmonitor.api.ui.ConnectivityIndicatorContainer
import io.element.android.features.roomlist.impl.components.ConfirmRecoveryKeyBanner
@@ -49,19 +54,24 @@ import io.element.android.features.roomlist.impl.components.RequestVerificationH
import io.element.android.features.roomlist.impl.components.RoomListMenuAction
import io.element.android.features.roomlist.impl.components.RoomListTopBar
import io.element.android.features.roomlist.impl.components.RoomSummaryRow
+import io.element.android.features.roomlist.impl.migration.MigrationScreenView
import io.element.android.features.roomlist.impl.model.RoomListRoomSummary
import io.element.android.features.roomlist.impl.search.RoomListSearchResultView
+import io.element.android.libraries.architecture.AsyncData
import io.element.android.libraries.designsystem.preview.ElementPreview
import io.element.android.libraries.designsystem.preview.PreviewsDayNight
+import io.element.android.libraries.designsystem.theme.components.Button
import io.element.android.libraries.designsystem.theme.components.FloatingActionButton
import io.element.android.libraries.designsystem.theme.components.HorizontalDivider
import io.element.android.libraries.designsystem.theme.components.Icon
+import io.element.android.libraries.designsystem.theme.components.IconSource
import io.element.android.libraries.designsystem.theme.components.Scaffold
+import io.element.android.libraries.designsystem.theme.components.Text
import io.element.android.libraries.designsystem.utils.CommonDrawables
-import io.element.android.libraries.designsystem.utils.LogCompositions
import io.element.android.libraries.designsystem.utils.snackbar.SnackbarHost
import io.element.android.libraries.designsystem.utils.snackbar.rememberSnackbarHostState
import io.element.android.libraries.matrix.api.core.RoomId
+import io.element.android.libraries.ui.strings.CommonStrings
@Composable
fun RoomListView(
@@ -122,6 +132,35 @@ fun RoomListView(
}
}
+@Composable
+private fun EmptyRoomListView(
+ onCreateRoomClicked: () -> Unit,
+) {
+ Column(
+ modifier = Modifier.fillMaxSize(),
+ horizontalAlignment = Alignment.CenterHorizontally,
+ verticalArrangement = Arrangement.Center
+ ) {
+ Text(
+ text = stringResource(R.string.screen_roomlist_empty_title),
+ style = ElementTheme.typography.fontBodyLgRegular,
+ color = ElementTheme.colors.textSecondary,
+ )
+ Spacer(modifier = Modifier.height(4.dp))
+ Text(
+ text = stringResource(R.string.screen_roomlist_empty_message),
+ style = ElementTheme.typography.fontBodyLgRegular,
+ color = ElementTheme.colors.textSecondary,
+ )
+ Spacer(modifier = Modifier.height(16.dp))
+ Button(
+ text = stringResource(CommonStrings.action_start_chat),
+ leadingIcon = IconSource.Resource(CommonDrawables.ic_new_message),
+ onClick = onCreateRoomClicked,
+ )
+ }
+}
+
@OptIn(ExperimentalMaterial3Api::class)
@Composable
private fun RoomListContent(
@@ -151,11 +190,6 @@ private fun RoomListContent(
}
}
val scrollBehavior = TopAppBarDefaults.exitUntilCollapsedScrollBehavior(appBarState)
- LogCompositions(
- tag = "RoomListScreen",
- msg = "Content"
- )
-
val nestedScrollConnection = remember {
object : NestedScrollConnection {
override suspend fun onPostFling(consumed: Velocity, available: Velocity): Velocity {
@@ -179,72 +213,81 @@ private fun RoomListContent(
onMenuActionClicked = onMenuActionClicked,
onOpenSettings = onOpenSettings,
scrollBehavior = scrollBehavior,
+ displayMenuItems = !state.displayMigrationStatus,
)
},
content = { padding ->
- LazyColumn(
- modifier = Modifier
- .padding(padding)
- .consumeWindowInsets(padding)
- .nestedScroll(nestedScrollConnection),
- state = lazyListState,
- ) {
- when {
- state.displayVerificationPrompt -> {
- item {
- RequestVerificationHeader(
- onVerifyClicked = onVerifyClicked,
- onDismissClicked = { state.eventSink(RoomListEvents.DismissRequestVerificationPrompt) }
- )
+ if (state.roomList is AsyncData.Success && state.roomList.data.isEmpty()) {
+ EmptyRoomListView(onCreateRoomClicked)
+ } else {
+ LazyColumn(
+ modifier = Modifier
+ .padding(padding)
+ .consumeWindowInsets(padding)
+ .nestedScroll(nestedScrollConnection),
+ state = lazyListState,
+ // FAB height is 56dp, bottom padding is 16dp, we add 8dp as extra margin -> 56+16+8 = 80
+ contentPadding = PaddingValues(bottom = 80.dp)
+ ) {
+ when {
+ state.displayVerificationPrompt -> {
+ item {
+ RequestVerificationHeader(
+ onVerifyClicked = onVerifyClicked,
+ onDismissClicked = { state.eventSink(RoomListEvents.DismissRequestVerificationPrompt) }
+ )
+ }
+ }
+ state.displayRecoveryKeyPrompt -> {
+ item {
+ ConfirmRecoveryKeyBanner(
+ onContinueClicked = onOpenSettings,
+ onDismissClicked = { state.eventSink(RoomListEvents.DismissRecoveryKeyPrompt) }
+ )
+ }
}
}
- state.displayRecoveryKeyPrompt -> {
+
+ if (state.invitesState != InvitesState.NoInvites) {
item {
- ConfirmRecoveryKeyBanner(
- onContinueClicked = onOpenSettings,
- onDismissClicked = { state.eventSink(RoomListEvents.DismissRecoveryKeyPrompt) }
- )
+ InvitesEntryPointView(onInvitesClicked, state.invitesState)
}
}
- }
- if (state.invitesState != InvitesState.NoInvites) {
- item {
- InvitesEntryPointView(onInvitesClicked, state.invitesState)
+ val roomList = state.roomList.dataOrNull().orEmpty()
+ // Note: do not use a key for the LazyColumn, or the scroll will not behave as expected if a room
+ // is moved to the top of the list.
+ itemsIndexed(
+ items = roomList,
+ contentType = { _, room -> room.contentType() },
+ ) { index, room ->
+ RoomSummaryRow(
+ room = room,
+ onClick = ::onRoomClicked,
+ onLongClick = onRoomLongClicked,
+ )
+ if (index != roomList.lastIndex) {
+ HorizontalDivider()
+ }
}
}
-
- itemsIndexed(
- items = state.roomList,
- contentType = { _, room -> room.contentType() },
- ) { index, room ->
- RoomSummaryRow(
- room = room,
- onClick = ::onRoomClicked,
- onLongClick = onRoomLongClicked,
- )
- if (index != state.roomList.lastIndex) {
- HorizontalDivider()
- }
- }
- // Add a last Spacer item to ensure that the FAB does not hide the last room item
- // FAB height is 56dp, bottom padding is 16dp, we add 8dp as extra margin -> 56+16+8 = 80
- item {
- Spacer(modifier = Modifier.height(80.dp))
- }
}
+
+ MigrationScreenView(isMigrating = state.displayMigrationStatus)
},
floatingActionButton = {
- FloatingActionButton(
- // FIXME align on Design system theme
- containerColor = MaterialTheme.colorScheme.primary,
- onClick = onCreateRoomClicked
- ) {
- Icon(
- // Note cannot use Icons.Outlined.EditSquare, it does not exist :/
- resourceId = CommonDrawables.ic_new_message,
- contentDescription = stringResource(id = R.string.screen_roomlist_a11y_create_message)
- )
+ if (!state.displayMigrationStatus) {
+ FloatingActionButton(
+ // FIXME align on Design system theme
+ containerColor = MaterialTheme.colorScheme.primary,
+ onClick = onCreateRoomClicked
+ ) {
+ Icon(
+ // Note cannot use Icons.Outlined.EditSquare, it does not exist :/
+ resourceId = CommonDrawables.ic_new_message,
+ contentDescription = stringResource(id = R.string.screen_roomlist_a11y_create_message)
+ )
+ }
}
},
snackbarHost = { SnackbarHost(snackbarHostState) },
diff --git a/features/roomlist/impl/src/main/kotlin/io/element/android/features/roomlist/impl/components/RoomListTopBar.kt b/features/roomlist/impl/src/main/kotlin/io/element/android/features/roomlist/impl/components/RoomListTopBar.kt
index e6aae4da6e..731e195744 100644
--- a/features/roomlist/impl/src/main/kotlin/io/element/android/features/roomlist/impl/components/RoomListTopBar.kt
+++ b/features/roomlist/impl/src/main/kotlin/io/element/android/features/roomlist/impl/components/RoomListTopBar.kt
@@ -21,8 +21,10 @@ import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.WindowInsets
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
+import androidx.compose.foundation.layout.size
import androidx.compose.foundation.layout.statusBars
import androidx.compose.foundation.layout.statusBarsPadding
+import androidx.compose.foundation.shape.CircleShape
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.TopAppBarDefaults
@@ -68,8 +70,8 @@ import io.element.android.libraries.designsystem.theme.components.HorizontalDivi
import io.element.android.libraries.designsystem.theme.components.Icon
import io.element.android.libraries.designsystem.theme.components.IconButton
import io.element.android.libraries.designsystem.theme.components.MediumTopAppBar
+import io.element.android.libraries.designsystem.theme.components.Surface
import io.element.android.libraries.designsystem.theme.components.Text
-import io.element.android.libraries.designsystem.utils.LogCompositions
import io.element.android.libraries.matrix.api.core.UserId
import io.element.android.libraries.matrix.api.user.MatrixUser
import io.element.android.libraries.matrix.ui.model.getAvatarData
@@ -90,13 +92,9 @@ fun RoomListTopBar(
onMenuActionClicked: (RoomListMenuAction) -> Unit,
onOpenSettings: () -> Unit,
scrollBehavior: TopAppBarScrollBehavior,
+ displayMenuItems: Boolean,
modifier: Modifier = Modifier,
) {
- LogCompositions(
- tag = "RoomListScreen",
- msg = "TopBar"
- )
-
fun closeFilter() {
onFilterChanged("")
}
@@ -114,6 +112,7 @@ fun RoomListTopBar(
onSearchClicked = onToggleSearch,
onMenuActionClicked = onMenuActionClicked,
scrollBehavior = scrollBehavior,
+ displayMenuItems = displayMenuItems,
modifier = modifier,
)
}
@@ -128,6 +127,7 @@ private fun DefaultRoomListTopBar(
onOpenSettings: () -> Unit,
onSearchClicked: () -> Unit,
onMenuActionClicked: (RoomListMenuAction) -> Unit,
+ displayMenuItems: Boolean,
modifier: Modifier = Modifier,
) {
// We need this to manually clip the top app bar in preview mode
@@ -201,79 +201,89 @@ private fun DefaultRoomListTopBar(
Text(text = stringResource(id = R.string.screen_roomlist_main_space_title))
},
navigationIcon = {
- avatarData?.let {
- IconButton(
- modifier = Modifier.testTag(TestTags.homeScreenSettings),
- onClick = onOpenSettings
- ) {
+ IconButton(
+ modifier = Modifier.testTag(TestTags.homeScreenSettings),
+ onClick = onOpenSettings
+ ) {
+ if (avatarData != null) {
Avatar(
- avatarData = it,
+ avatarData = avatarData!!,
contentDescription = stringResource(CommonStrings.common_settings),
)
- if (showAvatarIndicator) {
- RedIndicatorAtom(
- modifier = Modifier
- .padding(4.5.dp)
- .align(Alignment.TopEnd)
- )
- }
+ } else {
+ // Placeholder avatar until the avatarData is available
+ Surface(
+ modifier = Modifier.size(AvatarSize.CurrentUserTopBar.dp),
+ shape = CircleShape,
+ color = ElementTheme.colors.iconSecondary,
+ content = {}
+ )
+ }
+ if (showAvatarIndicator) {
+ RedIndicatorAtom(
+ modifier = Modifier
+ .padding(4.5.dp)
+ .align(Alignment.TopEnd)
+ )
}
}
},
actions = {
- IconButton(
- onClick = onSearchClicked,
- ) {
- Icon(
- imageVector = CompoundIcons.Search,
- contentDescription = stringResource(CommonStrings.action_search),
- )
- }
- if (RoomListConfig.HAS_DROP_DOWN_MENU) {
- var showMenu by remember { mutableStateOf(false) }
+ if (displayMenuItems) {
IconButton(
- onClick = { showMenu = !showMenu }
+ onClick = onSearchClicked,
) {
Icon(
- imageVector = CompoundIcons.OverflowVertical,
- contentDescription = null,
+ imageVector = CompoundIcons.Search,
+ contentDescription = stringResource(CommonStrings.action_search),
)
}
- DropdownMenu(
- expanded = showMenu,
- onDismissRequest = { showMenu = false }
- ) {
- if (RoomListConfig.SHOW_INVITE_MENU_ITEM) {
- DropdownMenuItem(
- onClick = {
- showMenu = false
- onMenuActionClicked(RoomListMenuAction.InviteFriends)
- },
- text = { Text(stringResource(id = CommonStrings.action_invite)) },
- leadingIcon = {
- Icon(
- imageVector = CompoundIcons.ShareAndroid,
- tint = ElementTheme.materialColors.secondary,
- contentDescription = null,
- )
- }
+ if (RoomListConfig.HAS_DROP_DOWN_MENU) {
+ var showMenu by remember { mutableStateOf(false) }
+ IconButton(
+ onClick = { showMenu = !showMenu }
+ ) {
+ Icon(
+ imageVector = CompoundIcons.OverflowVertical,
+ contentDescription = null,
)
}
- if (RoomListConfig.SHOW_REPORT_PROBLEM_MENU_ITEM) {
- DropdownMenuItem(
- onClick = {
- showMenu = false
- onMenuActionClicked(RoomListMenuAction.ReportBug)
- },
- text = { Text(stringResource(id = CommonStrings.common_report_a_problem)) },
- leadingIcon = {
- Icon(
- imageVector = CompoundIcons.ChatProblem,
- tint = ElementTheme.materialColors.secondary,
- contentDescription = null,
- )
- }
- )
+ DropdownMenu(
+ expanded = showMenu,
+ onDismissRequest = { showMenu = false }
+ ) {
+ if (RoomListConfig.SHOW_INVITE_MENU_ITEM) {
+ DropdownMenuItem(
+ onClick = {
+ showMenu = false
+ onMenuActionClicked(RoomListMenuAction.InviteFriends)
+ },
+ text = { Text(stringResource(id = CommonStrings.action_invite)) },
+ leadingIcon = {
+ Icon(
+ imageVector = CompoundIcons.ShareAndroid,
+ tint = ElementTheme.materialColors.secondary,
+ contentDescription = null,
+ )
+ }
+ )
+ }
+ if (RoomListConfig.SHOW_REPORT_PROBLEM_MENU_ITEM) {
+ DropdownMenuItem(
+ onClick = {
+ showMenu = false
+ onMenuActionClicked(RoomListMenuAction.ReportBug)
+ },
+ text = { Text(stringResource(id = CommonStrings.common_report_a_problem)) },
+ leadingIcon = {
+ Icon(
+ imageVector = CompoundIcons.ChatProblem,
+ tint = ElementTheme.materialColors.secondary,
+ contentDescription = null,
+ )
+ }
+ )
+ }
}
}
}
@@ -305,6 +315,7 @@ internal fun DefaultRoomListTopBarPreview() = ElementPreview {
scrollBehavior = TopAppBarDefaults.exitUntilCollapsedScrollBehavior(rememberTopAppBarState()),
onOpenSettings = {},
onSearchClicked = {},
+ displayMenuItems = true,
onMenuActionClicked = {},
)
}
@@ -320,6 +331,7 @@ internal fun DefaultRoomListTopBarWithIndicatorPreview() = ElementPreview {
scrollBehavior = TopAppBarDefaults.exitUntilCollapsedScrollBehavior(rememberTopAppBarState()),
onOpenSettings = {},
onSearchClicked = {},
+ displayMenuItems = true,
onMenuActionClicked = {},
)
}
diff --git a/features/roomlist/impl/src/main/kotlin/io/element/android/features/roomlist/impl/datasource/RoomListDataSource.kt b/features/roomlist/impl/src/main/kotlin/io/element/android/features/roomlist/impl/datasource/RoomListDataSource.kt
index a255767d7e..c55a47596b 100644
--- a/features/roomlist/impl/src/main/kotlin/io/element/android/features/roomlist/impl/datasource/RoomListDataSource.kt
+++ b/features/roomlist/impl/src/main/kotlin/io/element/android/features/roomlist/impl/datasource/RoomListDataSource.kt
@@ -21,6 +21,7 @@ import io.element.android.libraries.androidutils.diff.DiffCacheUpdater
import io.element.android.libraries.androidutils.diff.MutableListDiffCache
import io.element.android.libraries.core.coroutine.CoroutineDispatchers
import io.element.android.libraries.matrix.api.notificationsettings.NotificationSettingsService
+import io.element.android.libraries.matrix.api.roomlist.RoomList
import io.element.android.libraries.matrix.api.roomlist.RoomListService
import io.element.android.libraries.matrix.api.roomlist.RoomSummary
import kotlinx.collections.immutable.ImmutableList
@@ -28,7 +29,9 @@ import kotlinx.collections.immutable.persistentListOf
import kotlinx.collections.immutable.toImmutableList
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.FlowPreview
+import kotlinx.coroutines.flow.MutableSharedFlow
import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.coroutines.flow.SharedFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.debounce
@@ -52,7 +55,7 @@ class RoomListDataSource @Inject constructor(
}
private val _filter = MutableStateFlow("")
- private val _allRooms = MutableStateFlow>(persistentListOf())
+ private val _allRooms = MutableSharedFlow>(replay = 1)
private val _filteredRooms = MutableStateFlow>(persistentListOf())
private val lock = Mutex()
@@ -90,7 +93,7 @@ class RoomListDataSource @Inject constructor(
}
val filter: StateFlow = _filter
- val allRooms: StateFlow> = _allRooms
+ val allRooms: SharedFlow> = _allRooms
val filteredRooms: StateFlow> = _filteredRooms
@OptIn(FlowPreview::class)
@@ -111,10 +114,9 @@ class RoomListDataSource @Inject constructor(
}
private suspend fun buildAndEmitAllRooms(roomSummaries: List) {
- if (diffCache.isEmpty()) {
- _allRooms.emit(
- roomListRoomSummaryFactory.createFakeList()
- )
+ if (diffCache.isEmpty() && roomListService.allRooms.loadingState.value is RoomList.LoadingState.NotLoaded) {
+ // If the room list is not loaded, we emit a fake placeholders list
+ _allRooms.emit(RoomListRoomSummaryFactory.createFakeList())
} else {
val roomListRoomSummaries = ArrayList()
for (index in diffCache.indices()) {
@@ -133,7 +135,7 @@ class RoomListDataSource @Inject constructor(
private fun buildAndCacheItem(roomSummaries: List, index: Int): RoomListRoomSummary? {
val roomListRoomSummary = when (val roomSummary = roomSummaries.getOrNull(index)) {
- is RoomSummary.Empty -> roomListRoomSummaryFactory.createPlaceholder(roomSummary.identifier)
+ is RoomSummary.Empty -> RoomListRoomSummaryFactory.createPlaceholder(roomSummary.identifier)
is RoomSummary.Filled -> roomListRoomSummaryFactory.create(roomSummary)
null -> null
}
diff --git a/features/roomlist/impl/src/main/kotlin/io/element/android/features/roomlist/impl/datasource/RoomListRoomSummaryFactory.kt b/features/roomlist/impl/src/main/kotlin/io/element/android/features/roomlist/impl/datasource/RoomListRoomSummaryFactory.kt
index 9f1416c701..d3c7c43148 100644
--- a/features/roomlist/impl/src/main/kotlin/io/element/android/features/roomlist/impl/datasource/RoomListRoomSummaryFactory.kt
+++ b/features/roomlist/impl/src/main/kotlin/io/element/android/features/roomlist/impl/datasource/RoomListRoomSummaryFactory.kt
@@ -32,28 +32,31 @@ class RoomListRoomSummaryFactory @Inject constructor(
private val lastMessageTimestampFormatter: LastMessageTimestampFormatter,
private val roomLastMessageFormatter: RoomLastMessageFormatter,
) {
- fun createPlaceholder(id: String): RoomListRoomSummary {
- return RoomListRoomSummary(
- id = id,
- roomId = RoomId("!aRoom:domain"),
- isPlaceholder = true,
- name = "Short name",
- timestamp = "hh:mm",
- lastMessage = "Last message for placeholder",
- avatarData = AvatarData(id, "S", size = AvatarSize.RoomListItem),
- numberOfUnreadMessages = 0,
- numberOfUnreadMentions = 0,
- numberOfUnreadNotifications = 0,
- userDefinedNotificationMode = null,
- hasRoomCall = false,
- isDm = false,
- )
- }
+ companion object {
+ fun createPlaceholder(id: String): RoomListRoomSummary {
+ return RoomListRoomSummary(
+ id = id,
+ roomId = RoomId(id),
+ isPlaceholder = true,
+ name = "Short name",
+ timestamp = "hh:mm",
+ lastMessage = "Last message for placeholder",
+ avatarData = AvatarData(id, "S", size = AvatarSize.RoomListItem),
+ numberOfUnreadMessages = 0,
+ numberOfUnreadMentions = 0,
+ numberOfUnreadNotifications = 0,
+ isMarkedUnread = false,
+ userDefinedNotificationMode = null,
+ hasRoomCall = false,
+ isDm = false,
+ )
+ }
- fun createFakeList(): ImmutableList {
- return List(16) {
- createPlaceholder("!fakeRoom$it:domain")
- }.toImmutableList()
+ fun createFakeList(): ImmutableList {
+ return List(16) {
+ createPlaceholder("!fakeRoom$it:domain")
+ }.toImmutableList()
+ }
}
fun create(roomSummary: RoomSummary.Filled): RoomListRoomSummary {
@@ -71,6 +74,7 @@ class RoomListRoomSummaryFactory @Inject constructor(
numberOfUnreadMessages = roomSummary.details.numUnreadMessages,
numberOfUnreadMentions = roomSummary.details.numUnreadMentions,
numberOfUnreadNotifications = roomSummary.details.numUnreadNotifications,
+ isMarkedUnread = roomSummary.details.isMarkedUnread,
timestamp = lastMessageTimestampFormatter.format(roomSummary.details.lastMessageTimestamp),
lastMessage = roomSummary.details.lastMessage?.let { message ->
roomLastMessageFormatter.format(message.event, roomSummary.details.isDirect)
diff --git a/features/ftue/impl/src/main/kotlin/io/element/android/features/ftue/impl/migration/MigrationScreenPresenter.kt b/features/roomlist/impl/src/main/kotlin/io/element/android/features/roomlist/impl/migration/MigrationScreenPresenter.kt
similarity index 73%
rename from features/ftue/impl/src/main/kotlin/io/element/android/features/ftue/impl/migration/MigrationScreenPresenter.kt
rename to features/roomlist/impl/src/main/kotlin/io/element/android/features/roomlist/impl/migration/MigrationScreenPresenter.kt
index 6507130383..4886eca7bb 100644
--- a/features/ftue/impl/src/main/kotlin/io/element/android/features/ftue/impl/migration/MigrationScreenPresenter.kt
+++ b/features/roomlist/impl/src/main/kotlin/io/element/android/features/roomlist/impl/migration/MigrationScreenPresenter.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,12 +14,16 @@
* limitations under the License.
*/
-package io.element.android.features.ftue.impl.migration
+package io.element.android.features.roomlist.impl.migration
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
+import androidx.compose.runtime.mutableStateOf
+import androidx.compose.runtime.remember
+import androidx.compose.runtime.setValue
+import io.element.android.features.roomlist.api.migration.MigrationScreenStore
import io.element.android.libraries.architecture.Presenter
import io.element.android.libraries.matrix.api.MatrixClient
import io.element.android.libraries.matrix.api.roomlist.RoomListService
@@ -32,13 +36,15 @@ class MigrationScreenPresenter @Inject constructor(
@Composable
override fun present(): MigrationScreenState {
val roomListState by matrixClient.roomListService.state.collectAsState()
+ var needsMigration by remember { mutableStateOf(migrationScreenStore.isMigrationScreenNeeded(matrixClient.sessionId)) }
if (roomListState == RoomListService.State.Running) {
LaunchedEffect(Unit) {
+ needsMigration = false
migrationScreenStore.setMigrationScreenShown(matrixClient.sessionId)
}
}
return MigrationScreenState(
- isMigrating = roomListState != RoomListService.State.Running
+ isMigrating = needsMigration && roomListState != RoomListService.State.Running
)
}
}
diff --git a/features/ftue/impl/src/main/kotlin/io/element/android/features/ftue/impl/migration/MigrationScreenState.kt b/features/roomlist/impl/src/main/kotlin/io/element/android/features/roomlist/impl/migration/MigrationScreenState.kt
similarity index 91%
rename from features/ftue/impl/src/main/kotlin/io/element/android/features/ftue/impl/migration/MigrationScreenState.kt
rename to features/roomlist/impl/src/main/kotlin/io/element/android/features/roomlist/impl/migration/MigrationScreenState.kt
index fa718990e4..884c706da5 100644
--- a/features/ftue/impl/src/main/kotlin/io/element/android/features/ftue/impl/migration/MigrationScreenState.kt
+++ b/features/roomlist/impl/src/main/kotlin/io/element/android/features/roomlist/impl/migration/MigrationScreenState.kt
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package io.element.android.features.ftue.impl.migration
+package io.element.android.features.roomlist.impl.migration
data class MigrationScreenState(
val isMigrating: Boolean
diff --git a/features/ftue/impl/src/main/kotlin/io/element/android/features/ftue/impl/migration/MigrationScreenView.kt b/features/roomlist/impl/src/main/kotlin/io/element/android/features/roomlist/impl/migration/MigrationScreenView.kt
similarity index 54%
rename from features/ftue/impl/src/main/kotlin/io/element/android/features/ftue/impl/migration/MigrationScreenView.kt
rename to features/roomlist/impl/src/main/kotlin/io/element/android/features/roomlist/impl/migration/MigrationScreenView.kt
index 54a1b541be..b7627f1ce0 100644
--- a/features/ftue/impl/src/main/kotlin/io/element/android/features/ftue/impl/migration/MigrationScreenView.kt
+++ b/features/roomlist/impl/src/main/kotlin/io/element/android/features/roomlist/impl/migration/MigrationScreenView.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,45 +14,43 @@
* limitations under the License.
*/
-package io.element.android.features.ftue.impl.migration
+package io.element.android.features.roomlist.impl.migration
+import androidx.compose.animation.core.animateFloatAsState
+import androidx.compose.animation.core.tween
import androidx.compose.runtime.Composable
-import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue
-import androidx.compose.runtime.rememberUpdatedState
import androidx.compose.ui.Modifier
+import androidx.compose.ui.draw.alpha
import androidx.compose.ui.res.stringResource
-import io.element.android.features.ftue.impl.R
+import io.element.android.features.roomlist.impl.R
import io.element.android.libraries.designsystem.atomic.pages.SunsetPage
import io.element.android.libraries.designsystem.preview.ElementPreview
import io.element.android.libraries.designsystem.preview.PreviewsDayNight
@Composable
fun MigrationScreenView(
- migrationState: MigrationScreenState,
- onMigrationFinished: () -> Unit,
+ isMigrating: Boolean,
modifier: Modifier = Modifier,
) {
- if (migrationState.isMigrating.not()) {
- val latestOnMigrationFinished by rememberUpdatedState(onMigrationFinished)
- LaunchedEffect(Unit) {
- latestOnMigrationFinished()
- }
- }
- SunsetPage(
- modifier = modifier,
- isLoading = true,
- title = stringResource(id = R.string.screen_migration_title),
- subtitle = stringResource(id = R.string.screen_migration_message),
- overallContent = {}
+ val displayMigrationStatusFadeProgress by animateFloatAsState(
+ targetValue = if (isMigrating) 1f else 0f,
+ animationSpec = tween(durationMillis = 200),
+ label = "Migration view fade"
)
+ if (displayMigrationStatusFadeProgress > 0f) {
+ SunsetPage(
+ modifier = modifier.alpha(displayMigrationStatusFadeProgress),
+ isLoading = true,
+ title = stringResource(id = R.string.screen_migration_title),
+ subtitle = stringResource(id = R.string.screen_migration_message),
+ overallContent = {}
+ )
+ }
}
-@PreviewsDayNight
@Composable
+@PreviewsDayNight
internal fun MigrationViewPreview() = ElementPreview {
- MigrationScreenView(
- migrationState = MigrationScreenState(isMigrating = true),
- onMigrationFinished = {}
- )
+ MigrationScreenView(isMigrating = true)
}
diff --git a/features/ftue/impl/src/main/kotlin/io/element/android/features/ftue/impl/migration/SharedPrefsMigrationScreenStore.kt b/features/roomlist/impl/src/main/kotlin/io/element/android/features/roomlist/impl/migration/SharedPrefsMigrationScreenStore.kt
similarity index 92%
rename from features/ftue/impl/src/main/kotlin/io/element/android/features/ftue/impl/migration/SharedPrefsMigrationScreenStore.kt
rename to features/roomlist/impl/src/main/kotlin/io/element/android/features/roomlist/impl/migration/SharedPrefsMigrationScreenStore.kt
index 8ece45c08c..62121fd282 100644
--- a/features/ftue/impl/src/main/kotlin/io/element/android/features/ftue/impl/migration/SharedPrefsMigrationScreenStore.kt
+++ b/features/roomlist/impl/src/main/kotlin/io/element/android/features/roomlist/impl/migration/SharedPrefsMigrationScreenStore.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,11 +14,12 @@
* limitations under the License.
*/
-package io.element.android.features.ftue.impl.migration
+package io.element.android.features.roomlist.impl.migration
import android.content.SharedPreferences
import androidx.core.content.edit
import com.squareup.anvil.annotations.ContributesBinding
+import io.element.android.features.roomlist.api.migration.MigrationScreenStore
import io.element.android.libraries.androidutils.hash.hash
import io.element.android.libraries.di.AppScope
import io.element.android.libraries.di.DefaultPreferences
diff --git a/features/roomlist/impl/src/main/kotlin/io/element/android/features/roomlist/impl/model/RoomListRoomSummary.kt b/features/roomlist/impl/src/main/kotlin/io/element/android/features/roomlist/impl/model/RoomListRoomSummary.kt
index 26cd9e2d32..2a5289c9db 100644
--- a/features/roomlist/impl/src/main/kotlin/io/element/android/features/roomlist/impl/model/RoomListRoomSummary.kt
+++ b/features/roomlist/impl/src/main/kotlin/io/element/android/features/roomlist/impl/model/RoomListRoomSummary.kt
@@ -29,6 +29,7 @@ data class RoomListRoomSummary(
val numberOfUnreadMessages: Int,
val numberOfUnreadMentions: Int,
val numberOfUnreadNotifications: Int,
+ val isMarkedUnread: Boolean,
val timestamp: String?,
val lastMessage: CharSequence?,
val avatarData: AvatarData,
@@ -38,9 +39,11 @@ data class RoomListRoomSummary(
val isDm: Boolean,
) {
val isHighlighted = userDefinedNotificationMode != RoomNotificationMode.MUTE &&
- (numberOfUnreadNotifications > 0 || numberOfUnreadMentions > 0)
+ (numberOfUnreadNotifications > 0 || numberOfUnreadMentions > 0) ||
+ isMarkedUnread
val hasNewContent = numberOfUnreadMessages > 0 ||
numberOfUnreadMentions > 0 ||
- numberOfUnreadNotifications > 0
+ numberOfUnreadNotifications > 0 ||
+ isMarkedUnread
}
diff --git a/features/roomlist/impl/src/main/kotlin/io/element/android/features/roomlist/impl/model/RoomListRoomSummaryProvider.kt b/features/roomlist/impl/src/main/kotlin/io/element/android/features/roomlist/impl/model/RoomListRoomSummaryProvider.kt
index e53e1f9072..9b80edecb0 100644
--- a/features/roomlist/impl/src/main/kotlin/io/element/android/features/roomlist/impl/model/RoomListRoomSummaryProvider.kt
+++ b/features/roomlist/impl/src/main/kotlin/io/element/android/features/roomlist/impl/model/RoomListRoomSummaryProvider.kt
@@ -89,6 +89,7 @@ internal fun aRoomListRoomSummary(
numberOfUnreadMessages: Int = 0,
numberOfUnreadMentions: Int = 0,
numberOfUnreadNotifications: Int = 0,
+ isMarkedUnread: Boolean = false,
lastMessage: String? = "Last message",
timestamp: String? = lastMessage?.let { "88:88" },
isPlaceholder: Boolean = false,
@@ -103,6 +104,7 @@ internal fun aRoomListRoomSummary(
numberOfUnreadMessages = numberOfUnreadMessages,
numberOfUnreadMentions = numberOfUnreadMentions,
numberOfUnreadNotifications = numberOfUnreadNotifications,
+ isMarkedUnread = isMarkedUnread,
timestamp = timestamp,
lastMessage = lastMessage,
avatarData = avatarData,
diff --git a/features/roomlist/impl/src/main/kotlin/io/element/android/features/roomlist/impl/search/RoomListSearchResultView.kt b/features/roomlist/impl/src/main/kotlin/io/element/android/features/roomlist/impl/search/RoomListSearchResultView.kt
index e05f0a3ac5..9dd70fb0ef 100644
--- a/features/roomlist/impl/src/main/kotlin/io/element/android/features/roomlist/impl/search/RoomListSearchResultView.kt
+++ b/features/roomlist/impl/src/main/kotlin/io/element/android/features/roomlist/impl/search/RoomListSearchResultView.kt
@@ -103,7 +103,6 @@ private fun RoomListSearchResultContent(
state: RoomListState,
onRoomClicked: (RoomId) -> Unit,
onRoomLongClicked: (RoomListRoomSummary) -> Unit,
- modifier: Modifier = Modifier,
) {
val borderColor = MaterialTheme.colorScheme.tertiary
val strokeWidth = 1.dp
@@ -115,7 +114,6 @@ private fun RoomListSearchResultContent(
onRoomClicked(room.roomId)
}
Scaffold(
- modifier = modifier,
topBar = {
TopAppBar(
modifier = Modifier.drawBehind {
diff --git a/features/roomlist/impl/src/main/res/values-be/translations.xml b/features/roomlist/impl/src/main/res/values-be/translations.xml
new file mode 100644
index 0000000000..aeb01f846d
--- /dev/null
+++ b/features/roomlist/impl/src/main/res/values-be/translations.xml
@@ -0,0 +1,14 @@
+
+
+ "Ваша рэзервовая копія чата зараз не сінхранізавана. Вам трэба пацвердзіць ключ аднаўлення, каб захаваць доступ да рэзервовай копіі чата."
+ "Пацвердзіце ключ аднаўлення"
+ "Гэта аднаразовы працэс, дзякуем за чаканне."
+ "Налада ўліковага запісу."
+ "Стварыце новую размову або пакой"
+ "Пачніце з паведамлення каму-небудзь."
+ "Пакуль няма чатаў."
+ "Усе чаты"
+ "Здаецца, вы карыстаецеся новай прыладай. Праверце з дапамогай іншай прылады, каб атрымаць доступ да зашыфраваных паведамленняў."
+ "Пацвердзіце, што гэта вы"
+ "Людзі"
+
diff --git a/features/roomlist/impl/src/main/res/values-cs/translations.xml b/features/roomlist/impl/src/main/res/values-cs/translations.xml
index 506c0c60b4..74b1b7223b 100644
--- a/features/roomlist/impl/src/main/res/values-cs/translations.xml
+++ b/features/roomlist/impl/src/main/res/values-cs/translations.xml
@@ -2,15 +2,19 @@
"Vaše záloha chatu není aktuálně synchronizována. Abyste si zachovali přístup k záloze chatu, musíte potvrdit klíč pro obnovení."
"Potvrďte klíč pro obnovení"
+ "Jedná se o jednorázový proces, prosíme o strpení."
+ "Nastavení vašeho účtu"
"Vytvořte novou konverzaci nebo místnost"
"Začněte tím, že někomu pošnete zprávu."
"Zatím žádné konverzace."
"Oblíbené"
"Nízká priorita"
- "Lidé"
"Místnosti"
"Nepřečtené"
"Všechny chaty"
+ "Označit jako přečtené"
+ "Označit jako nepřečtené"
"Zdá se, že používáte nové zařízení. Ověřte přihlášení, abyste měli přístup k zašifrovaným zprávám."
"Ověřte, že jste to vy"
+ "Lidé"
diff --git a/features/roomlist/impl/src/main/res/values-de/translations.xml b/features/roomlist/impl/src/main/res/values-de/translations.xml
index d471bd3c7b..c64dbf332e 100644
--- a/features/roomlist/impl/src/main/res/values-de/translations.xml
+++ b/features/roomlist/impl/src/main/res/values-de/translations.xml
@@ -2,10 +2,19 @@
"Dein Chat-Backup ist derzeit nicht synchronisiert. Du musst deinen Wiederherstellungsschlüssel bestätigen, um Zugriff auf dein Chat-Backup zu erhalten."
"Wiederherstellungsschlüssel bestätigen."
+ "Dies ist ein einmaliger Vorgang, danke fürs Warten."
+ "Dein Konto wird eingerichtet."
"Eine neue Unterhaltung oder einen neuen Raum erstellen"
"Beginne, indem du jemandem eine Nachricht sendest."
"Noch keine Chats."
+ "Favoriten"
+ "Niedrige Priorität"
+ "Räume"
+ "Ungelesen"
"Alle Chats"
+ "Als gelesen markieren"
+ "Als ungelesen markieren"
"Es sieht aus, als würdest du ein neues Gerät verwenden. Verifiziere es mit einem anderen Gerät, damit du auf deine verschlüsselten Nachrichten zugreifen kannst."
"Bestätige deine Identität"
+ "Personen"
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 c3f8b23398..530da8271f 100644
--- a/features/roomlist/impl/src/main/res/values-es/translations.xml
+++ b/features/roomlist/impl/src/main/res/values-es/translations.xml
@@ -2,10 +2,13 @@
"La copia de seguridad del chat no está sincronizada en este momento. Debes confirmar tu clave de recuperación para mantener el acceso a la copia de seguridad del chat."
"Confirma tu clave de recuperación"
+ "Este proceso solo se hace una vez, gracias por esperar."
+ "Configura tu cuenta"
"Crear una nueva conversación o sala"
"Empieza enviando un mensaje a alguien."
"Aún no hay chats."
"Todos los chats"
"Parece que estás usando un nuevo dispositivo. Verifica que eres tú para acceder a tus mensajes cifrados."
"Verifica que eres tú"
+ "Personas"
diff --git a/features/roomlist/impl/src/main/res/values-fr/translations.xml b/features/roomlist/impl/src/main/res/values-fr/translations.xml
index 70795bcd5f..77f7b1e3e6 100644
--- a/features/roomlist/impl/src/main/res/values-fr/translations.xml
+++ b/features/roomlist/impl/src/main/res/values-fr/translations.xml
@@ -2,15 +2,19 @@
"La sauvegarde des conversations est désynchronisée. Vous devez confirmer la clé de récupération pour accéder à votre historique."
"Confirmer votre clé de récupération"
+ "Il s’agit d’une opération ponctuelle, merci d’attendre quelques instants."
+ "Configuration de votre compte."
"Créer une nouvelle discussion ou un nouveau salon"
"Commencez par envoyer un message à quelqu’un."
"Aucune discussion pour le moment."
"Favoris"
"Priorité basse"
- "Discussions"
"Salons"
"Non-lus"
"Conversations"
+ "Marquer comme lu"
+ "Marquer comme non lu"
"Il semblerait que vous utilisiez un nouvel appareil. Vérifiez la session avec un autre de vos appareils pour accéder à vos messages chiffrés."
"Vérifier que c’est bien vous"
+ "Personnes"
diff --git a/features/roomlist/impl/src/main/res/values-hu/translations.xml b/features/roomlist/impl/src/main/res/values-hu/translations.xml
index cd5dced50a..5410e5364f 100644
--- a/features/roomlist/impl/src/main/res/values-hu/translations.xml
+++ b/features/roomlist/impl/src/main/res/values-hu/translations.xml
@@ -1,11 +1,20 @@
- "A csevegés biztonsági mentés nincs szinkronban. Meg kell erősítenie a helyreállítási kulcsát, hogy továbbra is hozzáférjen a csevegés biztonsági mentéséhez."
+ "A csevegés biztonsági mentése nincs szinkronban. Meg kell erősítened a helyreállítási kulcsát, hogy továbbra is hozzáférj a csevegés biztonsági mentéséhez."
"Helyreállítási kulcs megerősítése"
+ "Ez egy egyszeri folyamat, köszönjük a türelmét."
+ "A fiók beállítása."
"Új beszélgetés vagy szoba létrehozása"
"Kezdje azzal, hogy üzenetet küld valakinek."
"Még nincsenek csevegések."
+ "Kedvencek"
+ "Alacsony prioritás"
+ "Szobák"
+ "Olvasatlan"
"Összes csevegés"
+ "Megjelölés olvasottként"
+ "Megjelölés olvasatlanként"
"Úgy tűnik, hogy új eszközt használ. Ellenőrizze egy másik eszközzel, hogy a továbbiakban elérje a titkosított üzeneteket."
"Ellenőrizze, hogy Ön az"
+ "Emberek"
diff --git a/features/roomlist/impl/src/main/res/values-in/translations.xml b/features/roomlist/impl/src/main/res/values-in/translations.xml
index 58994e4772..c3560b5b58 100644
--- a/features/roomlist/impl/src/main/res/values-in/translations.xml
+++ b/features/roomlist/impl/src/main/res/values-in/translations.xml
@@ -2,10 +2,13 @@
"Cadangan percakapan Anda saat ini tidak tersinkron. Anda perlu mengonfirmasi kunci pemulihan Anda untuk tetap memiliki akses ke cadangan percakapan Anda."
"Konfirmasi kunci pemulihan Anda"
+ "Ini adalah proses satu kali, terima kasih telah menunggu."
+ "Menyiapkan akun Anda."
"Buat percakapan atau ruangan baru"
"Mulailah dengan mengirim pesan kepada seseorang."
"Belum ada obrolan."
"Semua Obrolan"
"Sepertinya Anda menggunakan perangkat baru. Verifikasi dengan perangkat lain untuk mengakses pesan terenkripsi Anda selanjutnya."
"Verifikasi bahwa ini Anda"
+ "Orang"
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 2d186453a9..6f7648254f 100644
--- a/features/roomlist/impl/src/main/res/values-it/translations.xml
+++ b/features/roomlist/impl/src/main/res/values-it/translations.xml
@@ -2,10 +2,19 @@
"Il backup della chat non è attualmente sincronizzato. Devi confermare la chiave di recupero per mantenere l\'accesso al backup della chat."
"Conferma la chiave di recupero"
+ "Si tratta di una procedura che si effettua una sola volta, grazie per l\'attesa."
+ "Configurazione del tuo account."
"Crea una nuova conversazione o stanza"
"Inizia inviando un messaggio a qualcuno."
"Ancora nessuna chat."
+ "Preferiti"
+ "Bassa priorità"
+ "Stanze"
+ "Non letti"
"Tutte le conversazioni"
+ "Segna come letto"
+ "Segna come non letto"
"Sembra che tu stia usando un nuovo dispositivo. Verificati con un altro dispositivo per accedere ai tuoi messaggi cifrati."
"Verifica che sei tu"
+ "Persone"
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 e1f43a02ca..53ff7c87f7 100644
--- a/features/roomlist/impl/src/main/res/values-ro/translations.xml
+++ b/features/roomlist/impl/src/main/res/values-ro/translations.xml
@@ -1,9 +1,12 @@
+ "Acesta este un proces care se desfășoară o singură dată, vă mulțumim pentru așteptare."
+ "Contul dumneavoastră se configurează"
"Creați o conversație sau o cameră nouă"
"Începeți prin a trimite mesaje cuiva."
"Nu există încă discuții."
"Toate conversatiile"
"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ă"
+ "Persoane"
diff --git a/features/roomlist/impl/src/main/res/values-ru/translations.xml b/features/roomlist/impl/src/main/res/values-ru/translations.xml
index 261feda31d..f15eed6fb2 100644
--- a/features/roomlist/impl/src/main/res/values-ru/translations.xml
+++ b/features/roomlist/impl/src/main/res/values-ru/translations.xml
@@ -2,10 +2,19 @@
"В настоящее время резервная копия вашего чата не синхронизирована. Требуется подтвердить вашим ключом восстановления, чтобы сохранить доступ к резервной копии чата."
"Подтвердите ключ восстановления"
+ "Это одноразовый процесс, спасибо, что подождали."
+ "Настройка учетной записи."
"Создайте новую беседу или комнату"
"Начните переписку с отправки сообщения."
"Пока нет доступных чатов."
+ "Избранное"
+ "Низкий приоритет"
+ "Комнаты"
+ "Непрочитанные"
"Все чаты"
+ "Пометить как прочитанное"
+ "Пометить как непрочитанное"
"Похоже, вы используете новое устройство. Чтобы получить доступ к зашифрованным сообщениям пройдите верификацию с другим устройством."
"Подтвердите, что это вы"
+ "Люди"
diff --git a/features/roomlist/impl/src/main/res/values-sk/translations.xml b/features/roomlist/impl/src/main/res/values-sk/translations.xml
index 705d31cee3..412828ce85 100644
--- a/features/roomlist/impl/src/main/res/values-sk/translations.xml
+++ b/features/roomlist/impl/src/main/res/values-sk/translations.xml
@@ -2,15 +2,19 @@
"Vaša záloha konverzácie nie je momentálne synchronizovaná. Na zachovanie prístupu k zálohe konverzácie musíte potvrdiť svoj kľúč na obnovu."
"Potvrďte svoj kľúč na obnovenie"
+ "Ide o jednorazový proces, ďakujeme za trpezlivosť."
+ "Nastavenie vášho účtu."
"Vytvorte novú konverzáciu alebo miestnosť"
"Začnite tým, že niekomu pošlete správu."
"Zatiaľ žiadne konverzácie."
"Obľúbené"
"Nízka priorita"
- "Ľudia"
"Miestnosti"
"Neprečítané"
"Všetky konverzácie"
+ "Označiť ako prečítané"
+ "Označiť ako neprečítané"
"Vyzerá to tak, že používate nové zariadenie. Overte svoj prístup k zašifrovaným správam pomocou vášho druhého zariadenia."
"Overte, že ste to vy"
+ "Ľudia"
diff --git a/features/roomlist/impl/src/main/res/values-zh-rTW/translations.xml b/features/roomlist/impl/src/main/res/values-zh-rTW/translations.xml
index 4ad446a0bf..db51ea8a48 100644
--- a/features/roomlist/impl/src/main/res/values-zh-rTW/translations.xml
+++ b/features/roomlist/impl/src/main/res/values-zh-rTW/translations.xml
@@ -1,7 +1,10 @@
+ "這是一次性的程序,感謝您耐心等候。"
+ "正在設定您的帳號。"
"建立新的對話或聊天室"
"所有聊天室"
"您似乎正在使用新的裝置。請使用另一個裝置進行驗證,以存取您的加密訊息。"
"驗證這是您本人"
+ "夥伴"
diff --git a/features/roomlist/impl/src/main/res/values/localazy.xml b/features/roomlist/impl/src/main/res/values/localazy.xml
index 6f7332a091..d9980835f4 100644
--- a/features/roomlist/impl/src/main/res/values/localazy.xml
+++ b/features/roomlist/impl/src/main/res/values/localazy.xml
@@ -2,15 +2,19 @@
"Your chat backup is currently out of sync. You need to confirm your recovery key to maintain access to your chat backup."
"Confirm your recovery key"
+ "This is a one time process, thanks for waiting."
+ "Setting up your account."
"Create a new conversation or room"
"Get started by messaging someone."
"No chats yet."
"Favourites"
"Low Priority"
- "People"
"Rooms"
"Unreads"
"All Chats"
+ "Mark as read"
+ "Mark as unread"
"Looks like you’re using a new device. Verify with another device to access your encrypted messages."
"Verify it’s you"
+ "People"
diff --git a/features/roomlist/impl/src/test/kotlin/io/element/android/features/roomlist/impl/RoomListContextMenuTest.kt b/features/roomlist/impl/src/test/kotlin/io/element/android/features/roomlist/impl/RoomListContextMenuTest.kt
new file mode 100644
index 0000000000..6030ea1c6f
--- /dev/null
+++ b/features/roomlist/impl/src/test/kotlin/io/element/android/features/roomlist/impl/RoomListContextMenuTest.kt
@@ -0,0 +1,131 @@
+/*
+ * Copyright (c) 2024 New Vector Ltd
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package io.element.android.features.roomlist.impl
+
+import androidx.activity.ComponentActivity
+import androidx.compose.ui.test.junit4.createAndroidComposeRule
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import io.element.android.libraries.ui.strings.CommonStrings
+import io.element.android.tests.testutils.EnsureCalledOnceWithParam
+import io.element.android.tests.testutils.EnsureNeverCalledWithParam
+import io.element.android.tests.testutils.EventsRecorder
+import io.element.android.tests.testutils.clickOn
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@RunWith(AndroidJUnit4::class)
+class RoomListContextMenuTest {
+ @get:Rule val rule = createAndroidComposeRule()
+
+ @Test
+ fun `clicking on Mark as read generates expected Events`() {
+ val eventsRecorder = EventsRecorder()
+ val contextMenu = aContextMenuShown(hasNewContent = true)
+ rule.setContent {
+ RoomListContextMenu(
+ contextMenu = contextMenu,
+ eventSink = eventsRecorder,
+ onRoomSettingsClicked = EnsureNeverCalledWithParam(),
+ )
+ }
+ rule.clickOn(R.string.screen_roomlist_mark_as_read)
+ eventsRecorder.assertList(
+ listOf(
+ RoomListEvents.HideContextMenu,
+ RoomListEvents.MarkAsRead(contextMenu.roomId),
+ )
+ )
+ }
+
+ @Test
+ fun `clicking on Mark as unread generates expected Events`() {
+ val eventsRecorder = EventsRecorder()
+ val contextMenu = aContextMenuShown(hasNewContent = false)
+ rule.setContent {
+ RoomListContextMenu(
+ contextMenu = contextMenu,
+ eventSink = eventsRecorder,
+ onRoomSettingsClicked = EnsureNeverCalledWithParam(),
+ )
+ }
+ rule.clickOn(R.string.screen_roomlist_mark_as_unread)
+ eventsRecorder.assertList(
+ listOf(
+ RoomListEvents.HideContextMenu,
+ RoomListEvents.MarkAsUnread(contextMenu.roomId),
+ )
+ )
+ }
+
+ @Test
+ fun `clicking on Leave dm generates expected Events`() {
+ val eventsRecorder = EventsRecorder()
+ val contextMenu = aContextMenuShown(isDm = true)
+ rule.setContent {
+ RoomListContextMenu(
+ contextMenu = contextMenu,
+ eventSink = eventsRecorder,
+ onRoomSettingsClicked = EnsureNeverCalledWithParam(),
+ )
+ }
+ rule.clickOn(CommonStrings.action_leave_conversation)
+ eventsRecorder.assertList(
+ listOf(
+ RoomListEvents.HideContextMenu,
+ RoomListEvents.LeaveRoom(contextMenu.roomId),
+ )
+ )
+ }
+
+ @Test
+ fun `clicking on Leave room generates expected Events`() {
+ val eventsRecorder = EventsRecorder()
+ val contextMenu = aContextMenuShown(isDm = false)
+ rule.setContent {
+ RoomListContextMenu(
+ contextMenu = contextMenu,
+ eventSink = eventsRecorder,
+ onRoomSettingsClicked = EnsureNeverCalledWithParam(),
+ )
+ }
+ rule.clickOn(CommonStrings.action_leave_room)
+ eventsRecorder.assertList(
+ listOf(
+ RoomListEvents.HideContextMenu,
+ RoomListEvents.LeaveRoom(contextMenu.roomId),
+ )
+ )
+ }
+
+ @Test
+ fun `clicking on Settings invokes the expected callback and generates expected Event`() {
+ val eventsRecorder = EventsRecorder()
+ val contextMenu = aContextMenuShown()
+ val callback = EnsureCalledOnceWithParam(contextMenu.roomId, Unit)
+ rule.setContent {
+ RoomListContextMenu(
+ contextMenu = contextMenu,
+ eventSink = eventsRecorder,
+ onRoomSettingsClicked = callback,
+ )
+ }
+ rule.clickOn(CommonStrings.common_settings)
+ eventsRecorder.assertSingle(RoomListEvents.HideContextMenu)
+ callback.assertSuccess()
+ }
+}
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 b3da58220f..26a349818e 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
@@ -25,35 +25,40 @@ import io.element.android.features.leaveroom.api.LeaveRoomPresenter
import io.element.android.features.leaveroom.fake.FakeLeaveRoomPresenter
import io.element.android.features.networkmonitor.api.NetworkMonitor
import io.element.android.features.networkmonitor.test.FakeNetworkMonitor
+import io.element.android.features.preferences.api.store.SessionPreferencesStore
import io.element.android.features.roomactions.api.SetRoomIsFavoriteAction
import io.element.android.features.roomactions.test.FakeSetRoomIsFavoriteAction
import io.element.android.features.roomlist.impl.datasource.FakeInviteDataSource
import io.element.android.features.roomlist.impl.datasource.InviteStateDataSource
import io.element.android.features.roomlist.impl.datasource.RoomListDataSource
import io.element.android.features.roomlist.impl.datasource.RoomListRoomSummaryFactory
-import io.element.android.features.roomlist.impl.model.RoomListRoomSummary
+import io.element.android.features.roomlist.impl.migration.InMemoryMigrationScreenStore
+import io.element.android.features.roomlist.impl.migration.MigrationScreenPresenter
+import io.element.android.features.roomlist.impl.model.createRoomListRoomSummary
import io.element.android.libraries.architecture.AsyncData
import io.element.android.libraries.dateformatter.api.LastMessageTimestampFormatter
+import io.element.android.libraries.dateformatter.test.A_FORMATTED_DATE
import io.element.android.libraries.dateformatter.test.FakeLastMessageTimestampFormatter
-import io.element.android.libraries.designsystem.components.avatar.AvatarData
-import io.element.android.libraries.designsystem.components.avatar.AvatarSize
import io.element.android.libraries.designsystem.utils.snackbar.SnackbarDispatcher
import io.element.android.libraries.eventformatter.api.RoomLastMessageFormatter
import io.element.android.libraries.eventformatter.test.FakeRoomLastMessageFormatter
import io.element.android.libraries.featureflag.api.FeatureFlags
import io.element.android.libraries.featureflag.test.FakeFeatureFlagService
+import io.element.android.libraries.featureflag.test.InMemorySessionPreferencesStore
import io.element.android.libraries.indicator.impl.DefaultIndicatorService
import io.element.android.libraries.matrix.api.MatrixClient
import io.element.android.libraries.matrix.api.encryption.BackupState
import io.element.android.libraries.matrix.api.encryption.EncryptionService
import io.element.android.libraries.matrix.api.room.RoomNotificationMode
-import io.element.android.libraries.matrix.api.room.tags.RoomNotableTags
+import io.element.android.libraries.matrix.api.roomlist.RoomListService
+import io.element.android.libraries.matrix.api.timeline.ReceiptType
import io.element.android.libraries.matrix.api.verification.SessionVerificationService
import io.element.android.libraries.matrix.api.verification.SessionVerifiedStatus
import io.element.android.libraries.matrix.test.AN_AVATAR_URL
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_SESSION_ID
import io.element.android.libraries.matrix.test.A_USER_ID
import io.element.android.libraries.matrix.test.A_USER_NAME
import io.element.android.libraries.matrix.test.FakeMatrixClient
@@ -171,15 +176,28 @@ class RoomListPresenterTests {
moleculeFlow(RecompositionMode.Immediate) {
presenter.present()
}.test {
- val initialState = consumeItemsUntilPredicate { state -> state.roomList.size == 16 }.last()
+ val initialState = consumeItemsUntilPredicate { state -> state.roomList.dataOrNull()?.size == 16 }.last()
// Room list is loaded with 16 placeholders
- assertThat(initialState.roomList.size).isEqualTo(16)
- assertThat(initialState.roomList.all { it.isPlaceholder }).isTrue()
- roomListService.postAllRooms(listOf(aRoomSummaryFilled()))
- val withRoomState = consumeItemsUntilPredicate { state -> state.roomList.size == 1 }.last()
- assertThat(withRoomState.roomList.size).isEqualTo(1)
- assertThat(withRoomState.roomList.first())
- .isEqualTo(aRoomListRoomSummary)
+ val initialItems = initialState.roomList.dataOrNull().orEmpty()
+ assertThat(initialItems.size).isEqualTo(16)
+ assertThat(initialItems.all { it.isPlaceholder }).isTrue()
+ roomListService.postAllRooms(
+ listOf(
+ aRoomSummaryFilled(
+ numUnreadMentions = 1,
+ numUnreadMessages = 2,
+ )
+ )
+ )
+ val withRoomState = consumeItemsUntilPredicate { state -> state.roomList.dataOrNull()?.size == 1 }.last()
+ val withRoomStateItems = withRoomState.roomList.dataOrNull().orEmpty()
+ assertThat(withRoomStateItems.size).isEqualTo(1)
+ assertThat(withRoomStateItems.first()).isEqualTo(
+ createRoomListRoomSummary(
+ numberOfUnreadMentions = 1,
+ numberOfUnreadMessages = 2,
+ )
+ )
scope.cancel()
}
}
@@ -195,19 +213,30 @@ class RoomListPresenterTests {
moleculeFlow(RecompositionMode.Immediate) {
presenter.present()
}.test {
- roomListService.postAllRooms(listOf(aRoomSummaryFilled()))
+ roomListService.postAllRooms(
+ listOf(
+ aRoomSummaryFilled(
+ numUnreadMentions = 1,
+ numUnreadMessages = 2,
+ )
+ )
+ )
skipItems(3)
val loadedState = awaitItem()
// Test filtering with result
- assertThat(loadedState.roomList.size).isEqualTo(1)
+ assertThat(loadedState.roomList.dataOrNull().orEmpty().size).isEqualTo(1)
loadedState.eventSink.invoke(RoomListEvents.UpdateFilter(A_ROOM_NAME.substring(0, 3)))
skipItems(1)
val withFilteredRoomState = awaitItem()
assertThat(withFilteredRoomState.filteredRoomList.size).isEqualTo(1)
assertThat(withFilteredRoomState.filter).isEqualTo(A_ROOM_NAME.substring(0, 3))
assertThat(withFilteredRoomState.filteredRoomList.size).isEqualTo(1)
- assertThat(withFilteredRoomState.filteredRoomList.first())
- .isEqualTo(aRoomListRoomSummary)
+ assertThat(withFilteredRoomState.filteredRoomList.first()).isEqualTo(
+ createRoomListRoomSummary(
+ numberOfUnreadMentions = 1,
+ numberOfUnreadMessages = 2,
+ )
+ )
// Test filtering without result
withFilteredRoomState.eventSink.invoke(RoomListEvents.UpdateFilter("tada"))
skipItems(1)
@@ -324,18 +353,34 @@ class RoomListPresenterTests {
}.test {
skipItems(1)
val initialState = awaitItem()
- val summary = aRoomListRoomSummary
+ val summary = createRoomListRoomSummary()
initialState.eventSink(RoomListEvents.ShowContextMenu(summary))
awaitItem().also { state ->
assertThat(state.contextMenu)
- .isEqualTo(RoomListState.ContextMenu.Shown(summary.roomId, summary.name, false, AsyncData.Success(false)))
+ .isEqualTo(
+ RoomListState.ContextMenu.Shown(
+ roomId = summary.roomId,
+ roomName = summary.name,
+ isDm = false,
+ isFavorite = AsyncData.Success(false),
+ markAsUnreadFeatureFlagEnabled = true,
+ hasNewContent = false,
+ ))
}
- room.updateNotableTags(RoomNotableTags(isFavorite = true))
+ room.setIsFavorite(isFavorite = true)
awaitItem().also { state ->
assertThat(state.contextMenu)
- .isEqualTo(RoomListState.ContextMenu.Shown(summary.roomId, summary.name, false, AsyncData.Success(true)))
+ .isEqualTo(
+ RoomListState.ContextMenu.Shown(
+ roomId = summary.roomId,
+ roomName = summary.name,
+ isDm = false,
+ isFavorite = AsyncData.Success(true),
+ markAsUnreadFeatureFlagEnabled = true,
+ hasNewContent = false,
+ ))
}
scope.cancel()
}
@@ -355,12 +400,20 @@ class RoomListPresenterTests {
skipItems(1)
val initialState = awaitItem()
- val summary = aRoomListRoomSummary
+ val summary = createRoomListRoomSummary()
initialState.eventSink(RoomListEvents.ShowContextMenu(summary))
val shownState = awaitItem()
assertThat(shownState.contextMenu)
- .isEqualTo(RoomListState.ContextMenu.Shown(summary.roomId, summary.name, false, AsyncData.Success(false)))
+ .isEqualTo(RoomListState.ContextMenu.Shown(
+ roomId = summary.roomId,
+ roomName = summary.name,
+ isDm = false,
+ isFavorite = AsyncData.Success(false),
+ markAsUnreadFeatureFlagEnabled = true,
+ hasNewContent = false,
+ ))
+
shownState.eventSink(RoomListEvents.HideContextMenu)
val hiddenState = awaitItem()
@@ -403,10 +456,10 @@ class RoomListPresenterTests {
notificationSettingsService.setRoomNotificationMode(A_ROOM_ID, userDefinedMode)
val updatedState = consumeItemsUntilPredicate { state ->
- state.roomList.any { it.id == A_ROOM_ID.value && it.userDefinedNotificationMode == userDefinedMode }
+ state.roomList.dataOrNull().orEmpty().any { it.id == A_ROOM_ID.value && it.userDefinedNotificationMode == userDefinedMode }
}.last()
- val room = updatedState.roomList.find { it.id == A_ROOM_ID.value }
+ val room = updatedState.roomList.dataOrNull()?.find { it.id == A_ROOM_ID.value }
assertThat(room?.userDefinedNotificationMode).isEqualTo(userDefinedMode)
cancelAndIgnoreRemainingEvents()
scope.cancel()
@@ -429,6 +482,71 @@ class RoomListPresenterTests {
}
}
+ fun `present - change in migration presenter state modifies isMigrating`() = runTest {
+ val client = FakeMatrixClient(sessionId = A_SESSION_ID)
+ val migrationStore = InMemoryMigrationScreenStore()
+ val migrationScreenPresenter = MigrationScreenPresenter(client, migrationStore)
+ val scope = CoroutineScope(coroutineContext + SupervisorJob())
+ val presenter = createRoomListPresenter(
+ client = client,
+ coroutineScope = scope,
+ migrationScreenPresenter = migrationScreenPresenter,
+ )
+ moleculeFlow(RecompositionMode.Immediate) {
+ presenter.present()
+ }.test {
+ val initialState = awaitItem()
+ // The migration screen is shown if the migration screen has not been shown before
+ assertThat(initialState.displayMigrationStatus).isTrue()
+ skipItems(2)
+
+ // Set migration as done and set the room list service as running to trigger a refresh of the presenter value
+ (client.roomListService as FakeRoomListService).postState(RoomListService.State.Running)
+ migrationStore.setMigrationScreenShown(A_SESSION_ID)
+
+ // The migration screen is not shown anymore
+ assertThat(awaitItem().displayMigrationStatus).isFalse()
+ cancelAndIgnoreRemainingEvents()
+ scope.cancel()
+ }
+ }
+
+ @Test
+ fun `present - check that the room is marked as read with correct RR and as unread`() = runTest {
+ val room = FakeMatrixRoom()
+ val sessionPreferencesStore = InMemorySessionPreferencesStore()
+ val matrixClient = FakeMatrixClient().apply {
+ givenGetRoomResult(A_ROOM_ID, room)
+ }
+ val scope = CoroutineScope(coroutineContext + SupervisorJob())
+ val presenter = createRoomListPresenter(
+ client = matrixClient,
+ coroutineScope = scope,
+ sessionPreferencesStore = sessionPreferencesStore,
+ )
+ moleculeFlow(RecompositionMode.Immediate) {
+ presenter.present()
+ }.test {
+ val initialState = awaitItem()
+ assertThat(room.markAsReadCalls).isEmpty()
+ assertThat(room.markAsUnreadReadCallCount).isEqualTo(0)
+ initialState.eventSink.invoke(RoomListEvents.MarkAsRead(A_ROOM_ID))
+ assertThat(room.markAsReadCalls).isEqualTo(listOf(ReceiptType.READ))
+ assertThat(room.markAsUnreadReadCallCount).isEqualTo(0)
+ initialState.eventSink.invoke(RoomListEvents.MarkAsUnread(A_ROOM_ID))
+ assertThat(room.markAsReadCalls).isEqualTo(listOf(ReceiptType.READ))
+ assertThat(room.markAsUnreadReadCallCount).isEqualTo(1)
+ // Test again with private read receipts
+ sessionPreferencesStore.setSendPublicReadReceipts(false)
+ initialState.eventSink.invoke(RoomListEvents.MarkAsRead(A_ROOM_ID))
+ assertThat(room.markAsReadCalls).isEqualTo(listOf(ReceiptType.READ, ReceiptType.READ_PRIVATE))
+ assertThat(room.markAsUnreadReadCallCount).isEqualTo(1)
+
+ cancelAndIgnoreRemainingEvents()
+ scope.cancel()
+ }
+ }
+
private fun TestScope.createRoomListPresenter(
client: MatrixClient = FakeMatrixClient(),
sessionVerificationService: SessionVerificationService = FakeSessionVerificationService(),
@@ -441,8 +559,13 @@ class RoomListPresenterTests {
},
roomLastMessageFormatter: RoomLastMessageFormatter = FakeRoomLastMessageFormatter(),
encryptionService: EncryptionService = FakeEncryptionService(),
+ sessionPreferencesStore: SessionPreferencesStore = InMemorySessionPreferencesStore(),
coroutineScope: CoroutineScope,
setRoomIsFavoriteAction: SetRoomIsFavoriteAction = FakeSetRoomIsFavoriteAction(),
+ migrationScreenPresenter: MigrationScreenPresenter = MigrationScreenPresenter(
+ matrixClient = client,
+ migrationScreenStore = InMemoryMigrationScreenStore(),
+ )
) = RoomListPresenter(
client = client,
sessionVerificationService = sessionVerificationService,
@@ -468,23 +591,7 @@ class RoomListPresenterTests {
featureFlagService = FakeFeatureFlagService(mapOf(FeatureFlags.SecureStorage.key to true)),
),
setRoomIsFavorite = setRoomIsFavoriteAction,
+ migrationScreenPresenter = migrationScreenPresenter,
+ sessionPreferencesStore = sessionPreferencesStore,
)
}
-
-private const val A_FORMATTED_DATE = "formatted_date"
-
-private val aRoomListRoomSummary = RoomListRoomSummary(
- id = A_ROOM_ID.value,
- roomId = A_ROOM_ID,
- name = A_ROOM_NAME,
- numberOfUnreadMentions = 1,
- numberOfUnreadMessages = 2,
- numberOfUnreadNotifications = 0,
- timestamp = A_FORMATTED_DATE,
- lastMessage = "",
- avatarData = AvatarData(id = A_ROOM_ID.value, name = A_ROOM_NAME, size = AvatarSize.RoomListItem),
- isPlaceholder = false,
- userDefinedNotificationMode = null,
- hasRoomCall = false,
- isDm = false,
-)
diff --git a/features/ftue/impl/src/test/kotlin/io/element/android/features/ftue/impl/migration/InMemoryMigrationScreenStore.kt b/features/roomlist/impl/src/test/kotlin/io/element/android/features/roomlist/impl/migration/InMemoryMigrationScreenStore.kt
similarity index 86%
rename from features/ftue/impl/src/test/kotlin/io/element/android/features/ftue/impl/migration/InMemoryMigrationScreenStore.kt
rename to features/roomlist/impl/src/test/kotlin/io/element/android/features/roomlist/impl/migration/InMemoryMigrationScreenStore.kt
index a77a4d001a..79d0b7c628 100644
--- a/features/ftue/impl/src/test/kotlin/io/element/android/features/ftue/impl/migration/InMemoryMigrationScreenStore.kt
+++ b/features/roomlist/impl/src/test/kotlin/io/element/android/features/roomlist/impl/migration/InMemoryMigrationScreenStore.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,8 +14,9 @@
* limitations under the License.
*/
-package io.element.android.features.ftue.impl.migration
+package io.element.android.features.roomlist.impl.migration
+import io.element.android.features.roomlist.api.migration.MigrationScreenStore
import io.element.android.libraries.matrix.api.core.SessionId
class InMemoryMigrationScreenStore : MigrationScreenStore {
diff --git a/features/ftue/impl/src/test/kotlin/io/element/android/features/ftue/impl/migration/MigrationScreenPresenterTest.kt b/features/roomlist/impl/src/test/kotlin/io/element/android/features/roomlist/impl/migration/MigrationScreenPresenterTest.kt
similarity index 92%
rename from features/ftue/impl/src/test/kotlin/io/element/android/features/ftue/impl/migration/MigrationScreenPresenterTest.kt
rename to features/roomlist/impl/src/test/kotlin/io/element/android/features/roomlist/impl/migration/MigrationScreenPresenterTest.kt
index 44dcba6e00..2ddcaed566 100644
--- a/features/ftue/impl/src/test/kotlin/io/element/android/features/ftue/impl/migration/MigrationScreenPresenterTest.kt
+++ b/features/roomlist/impl/src/test/kotlin/io/element/android/features/roomlist/impl/migration/MigrationScreenPresenterTest.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,12 +14,13 @@
* limitations under the License.
*/
-package io.element.android.features.ftue.impl.migration
+package io.element.android.features.roomlist.impl.migration
import app.cash.molecule.RecompositionMode
import app.cash.molecule.moleculeFlow
import app.cash.turbine.test
import com.google.common.truth.Truth.assertThat
+import io.element.android.features.roomlist.api.migration.MigrationScreenStore
import io.element.android.libraries.matrix.api.MatrixClient
import io.element.android.libraries.matrix.api.roomlist.RoomListService
import io.element.android.libraries.matrix.test.A_SESSION_ID
@@ -61,6 +62,7 @@ class MigrationScreenPresenterTest {
val nextState = awaitItem()
assertThat(nextState.isMigrating).isFalse()
assertThat(migrationScreenStore.isMigrationScreenNeeded(A_SESSION_ID)).isFalse()
+ cancelAndIgnoreRemainingEvents()
}
}
diff --git a/features/roomlist/impl/src/test/kotlin/io/element/android/features/roomlist/impl/model/RoomListRoomSummaryTest.kt b/features/roomlist/impl/src/test/kotlin/io/element/android/features/roomlist/impl/model/RoomListRoomSummaryTest.kt
new file mode 100644
index 0000000000..f36299b1b7
--- /dev/null
+++ b/features/roomlist/impl/src/test/kotlin/io/element/android/features/roomlist/impl/model/RoomListRoomSummaryTest.kt
@@ -0,0 +1,98 @@
+/*
+ * Copyright (c) 2024 New Vector Ltd
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package io.element.android.features.roomlist.impl.model
+
+import com.google.common.truth.Truth.assertThat
+import io.element.android.libraries.dateformatter.test.A_FORMATTED_DATE
+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.room.RoomNotificationMode
+import io.element.android.libraries.matrix.test.A_ROOM_ID
+import io.element.android.libraries.matrix.test.A_ROOM_NAME
+import org.junit.Test
+
+class RoomListRoomSummaryTest {
+ @Test
+ fun `test default value`() {
+ val sut = createRoomListRoomSummary(
+ isMarkedUnread = false,
+ )
+ assertThat(sut.isHighlighted).isFalse()
+ assertThat(sut.hasNewContent).isFalse()
+ }
+
+ @Test
+ fun `test muted room`() {
+ val sut = createRoomListRoomSummary(
+ userDefinedNotificationMode = RoomNotificationMode.MUTE,
+ )
+ assertThat(sut.isHighlighted).isFalse()
+ assertThat(sut.hasNewContent).isFalse()
+ }
+
+ @Test
+ fun `test muted room isMarkedUnread set to true`() {
+ val sut = createRoomListRoomSummary(
+ isMarkedUnread = true,
+ userDefinedNotificationMode = RoomNotificationMode.MUTE,
+ )
+ assertThat(sut.isHighlighted).isTrue()
+ assertThat(sut.hasNewContent).isTrue()
+ }
+
+ @Test
+ fun `test muted room with unread message`() {
+ val sut = createRoomListRoomSummary(
+ numberOfUnreadNotifications = 1,
+ userDefinedNotificationMode = RoomNotificationMode.MUTE,
+ )
+ assertThat(sut.isHighlighted).isFalse()
+ assertThat(sut.hasNewContent).isTrue()
+ }
+
+ @Test
+ fun `test isMarkedUnread set to true`() {
+ val sut = createRoomListRoomSummary(
+ isMarkedUnread = true,
+ )
+ assertThat(sut.isHighlighted).isTrue()
+ assertThat(sut.hasNewContent).isTrue()
+ }
+}
+
+internal fun createRoomListRoomSummary(
+ numberOfUnreadMentions: Int = 0,
+ numberOfUnreadMessages: Int = 0,
+ numberOfUnreadNotifications: Int = 0,
+ isMarkedUnread: Boolean = false,
+ userDefinedNotificationMode: RoomNotificationMode? = null,
+) = RoomListRoomSummary(
+ id = A_ROOM_ID.value,
+ roomId = A_ROOM_ID,
+ name = A_ROOM_NAME,
+ numberOfUnreadMentions = numberOfUnreadMentions,
+ numberOfUnreadMessages = numberOfUnreadMessages,
+ numberOfUnreadNotifications = numberOfUnreadNotifications,
+ isMarkedUnread = isMarkedUnread,
+ timestamp = A_FORMATTED_DATE,
+ lastMessage = "",
+ avatarData = AvatarData(id = A_ROOM_ID.value, name = A_ROOM_NAME, size = AvatarSize.RoomListItem),
+ isPlaceholder = false,
+ userDefinedNotificationMode = userDefinedNotificationMode,
+ hasRoomCall = false,
+ isDm = false,
+)
diff --git a/features/securebackup/impl/src/main/res/values-be/translations.xml b/features/securebackup/impl/src/main/res/values-be/translations.xml
new file mode 100644
index 0000000000..d16399978d
--- /dev/null
+++ b/features/securebackup/impl/src/main/res/values-be/translations.xml
@@ -0,0 +1,44 @@
+
+
+ "Выключыць рэзервовае капіраванне"
+ "Уключыце рэзервовае капіраванне"
+ "Рэзервовае капіраванне гарантуе, што вы не страціце сваю гісторыю паведамленняў. %1$s."
+ "Рэзервовая копія"
+ "Змяніць ключ аднаўлення"
+ "Пацвердзіце ключ аднаўлення"
+ "Ваша рэзервовая копія чата зараз не сінхранізавана."
+ "Наладзьце аднаўленне"
+ "Атрымайце доступ да зашыфраваных паведамленняў, калі вы страціце ўсе свае прылады або выйдзеце з сістэмы %1$s усюды."
+ "Адключыць"
+ "Вы страціце зашыфраваныя паведамленні, калі выйдзеце з усіх прылад."
+ "Вы ўпэўнены, што жадаеце адключыць рэзервовае капіраванне?"
+ "Адключэнне рэзервовага капіравання прывядзе да выдалення бягучай рэзервовай копіі ключа шыфравання і адключэння іншых функцый бяспекі. У гэтым выпадку вы:"
+ "Няма зашыфраванай гісторыі паведамленняў на новых прыладах"
+ "Калі вы выходзіце з сістэмы, то губляеце доступ да зашыфраваных паведамленняў %1$s усюды"
+ "Вы ўпэўнены, што жадаеце адключыць рэзервовае капіраванне?"
+ "Атрымайце новы ключ аднаўлення, калі вы страцілі існуючы. Пасля змены ключа аднаўлення ваш стары больш не будзе працаваць."
+ "Стварыць новы ключ аднаўлення"
+ "Пераканайцеся, што вы можаце захаваць ключ аднаўлення ў бяспечным месцы"
+ "Ключ аднаўлення зменены"
+ "Змяніць ключ аднаўлення?"
+ "Увядзіце ключ аднаўлення, каб пацвердзіць доступ да рэзервовай копіі чата."
+ "Паўтарыце спробу, каб пацвердзіць доступ да рэзервовай копіі чата."
+ "Няправільны ключ аднаўлення"
+ "Увядзіце код з 48 сімвалаў."
+ "Увесці…"
+ "Ключ аднаўлення пацверджаны"
+ "Пацвердзіце ключ аднаўлення"
+ "Ключ аднаўлення скапіраваны"
+ "Стварэнне…"
+ "Захаваць ключ аднаўлення"
+ "Запішыце ключ аднаўлення ў бяспечным месцы або захавайце яго ў менеджары пароляў."
+ "Націсніце, каб скапіяваць ключ аднаўлення"
+ "Захавайце ключ аднаўлення"
+ "Пасля гэтага кроку вы не зможаце атрымаць доступ да новага ключа аднаўлення."
+ "Вы захавалі свой ключ аднаўлення?"
+ "Рэзервовая копія чата абаронена ключом аднаўлення. Калі пасля настройкі вам спатрэбіцца новы ключ аднаўлення, вы можаце стварыць яго нанова, выбраўшы \"Змяніць ключ аднаўлення\"."
+ "Стварыце ключ аднаўлення"
+ "Пераканайцеся, што вы можаце захаваць ключ аднаўлення ў бяспечным месцы"
+ "Наладка аднаўлення прайшла паспяхова"
+ "Наладзьце аднаўленне"
+
diff --git a/features/signedout/impl/src/main/kotlin/io/element/android/features/signedout/impl/SignedOutView.kt b/features/signedout/impl/src/main/kotlin/io/element/android/features/signedout/impl/SignedOutView.kt
index 9f62546c1a..a703baa180 100644
--- a/features/signedout/impl/src/main/kotlin/io/element/android/features/signedout/impl/SignedOutView.kt
+++ b/features/signedout/impl/src/main/kotlin/io/element/android/features/signedout/impl/SignedOutView.kt
@@ -78,11 +78,9 @@ private fun SignedOutHeader(state: SignedOutState) {
}
@Composable
-private fun SignedOutContent(
- modifier: Modifier = Modifier,
-) {
+private fun SignedOutContent() {
Box(
- modifier = modifier.fillMaxSize(),
+ modifier = Modifier.fillMaxSize(),
contentAlignment = BiasAlignment(
horizontalBias = 0f,
verticalBias = -0.4f
@@ -112,12 +110,9 @@ private fun SignedOutContent(
@Composable
private fun SignedOutFooter(
- modifier: Modifier = Modifier,
onSignInAgain: () -> Unit,
) {
- ButtonColumnMolecule(
- modifier = modifier,
- ) {
+ ButtonColumnMolecule {
Button(
text = stringResource(id = CommonStrings.action_sign_in_again),
onClick = onSignInAgain,
diff --git a/features/signedout/impl/src/main/res/values-be/translations.xml b/features/signedout/impl/src/main/res/values-be/translations.xml
new file mode 100644
index 0000000000..42cb5e41ff
--- /dev/null
+++ b/features/signedout/impl/src/main/res/values-be/translations.xml
@@ -0,0 +1,8 @@
+
+
+ "Вы змянілі свой пароль на іншым сеансе"
+ "Вы выдалілі сеанс з іншага сеансу"
+ "Адміністратар вашага сервера ануляваў ваш доступ"
+ "Магчыма, вы выйшлі з сістэмы па адной з прычын, пералічаных ніжэй. Калі ласка, увайдзіце яшчэ раз, каб працягнуць выкарыстанне %s."
+ "Вы выйшлі з сістэмы"
+
diff --git a/features/verifysession/impl/src/main/kotlin/io/element/android/features/verifysession/impl/VerifySelfSessionView.kt b/features/verifysession/impl/src/main/kotlin/io/element/android/features/verifysession/impl/VerifySelfSessionView.kt
index 02f5514e9f..e71df4c6d1 100644
--- a/features/verifysession/impl/src/main/kotlin/io/element/android/features/verifysession/impl/VerifySelfSessionView.kt
+++ b/features/verifysession/impl/src/main/kotlin/io/element/android/features/verifysession/impl/VerifySelfSessionView.kt
@@ -94,7 +94,7 @@ fun VerifySelfSessionView(
}
@Composable
-private fun HeaderContent(verificationFlowStep: FlowStep, modifier: Modifier = Modifier) {
+private fun HeaderContent(verificationFlowStep: FlowStep) {
val iconResourceId = when (verificationFlowStep) {
FlowStep.Initial -> R.drawable.ic_verification_devices
FlowStep.Canceled -> R.drawable.ic_verification_warning
@@ -125,7 +125,7 @@ private fun HeaderContent(verificationFlowStep: FlowStep, modifier: Modifier = M
}
IconTitleSubtitleMolecule(
- modifier = modifier.padding(top = 60.dp),
+ modifier = Modifier.padding(top = 60.dp),
iconResourceId = iconResourceId,
title = stringResource(id = titleTextId),
subTitle = stringResource(id = subtitleTextId)
@@ -133,8 +133,8 @@ private fun HeaderContent(verificationFlowStep: FlowStep, modifier: Modifier = M
}
@Composable
-private fun Content(flowState: FlowStep, modifier: Modifier = Modifier) {
- Column(modifier.fillMaxHeight(), verticalArrangement = Arrangement.Center) {
+private fun Content(flowState: FlowStep) {
+ Column(Modifier.fillMaxHeight(), verticalArrangement = Arrangement.Center) {
when (flowState) {
FlowStep.Initial, FlowStep.Ready, FlowStep.Canceled, FlowStep.Completed -> Unit
FlowStep.AwaitingOtherDeviceResponse -> ContentWaiting()
@@ -144,19 +144,19 @@ private fun Content(flowState: FlowStep, modifier: Modifier = Modifier) {
}
@Composable
-private fun ContentWaiting(modifier: Modifier = Modifier) {
- Row(modifier = modifier.fillMaxWidth(), horizontalArrangement = Arrangement.Center) {
+private fun ContentWaiting() {
+ Row(modifier = Modifier.fillMaxWidth(), horizontalArrangement = Arrangement.Center) {
CircularProgressIndicator()
}
}
@Composable
-private fun ContentVerifying(verificationFlowStep: FlowStep.Verifying, modifier: Modifier = Modifier) {
+private fun ContentVerifying(verificationFlowStep: FlowStep.Verifying) {
when (verificationFlowStep.data) {
is SessionVerificationData.Decimals -> {
val text = verificationFlowStep.data.decimals.joinToString(separator = " - ") { it.toString() }
Text(
- modifier = modifier.fillMaxWidth(),
+ modifier = Modifier.fillMaxWidth(),
text = text,
style = ElementTheme.typography.fontHeadingLgBold,
color = MaterialTheme.colorScheme.primary,
@@ -167,7 +167,7 @@ private fun ContentVerifying(verificationFlowStep: FlowStep.Verifying, modifier:
// We want each row to have up to 4 emojis
val rows = verificationFlowStep.data.emojis.chunked(4)
Column(
- modifier = modifier.fillMaxWidth(),
+ modifier = Modifier.fillMaxWidth(),
verticalArrangement = Arrangement.spacedBy(40.dp),
) {
rows.forEach { emojis ->
diff --git a/features/verifysession/impl/src/main/res/values-be/translations.xml b/features/verifysession/impl/src/main/res/values-be/translations.xml
new file mode 100644
index 0000000000..5605dbc962
--- /dev/null
+++ b/features/verifysession/impl/src/main/res/values-be/translations.xml
@@ -0,0 +1,20 @@
+
+
+ "Здаецца, нешта не так. Альбо час чакання запыту скончыўся, альбо запыт быў адхілены."
+ "Пераканайцеся, што прыведзеныя ніжэй эмодзі супадаюць з эмодзі, паказанымі ў вашым іншым сеансе."
+ "Параўнайце эмодзі"
+ "Пераканайцеся, што прыведзеныя ніжэй лічбы супадаюць з лічбамі, паказанымі ў іншым сеансе."
+ "Параўнайце лічбы"
+ "Ваш новы сеанс пацверджаны. Ён мае доступ да вашых зашыфраваных паведамленняў, і іншыя карыстальнікі будуць лічыць яго давераным."
+ "Дакажыце, што гэта вы, каб атрымаць доступ да вашай зашыфраванай гісторыі паведамленняў."
+ "Адкрыйце існуючы сеанс"
+ "Паўтарыце праверку"
+ "Я гатовы"
+ "Чаканне супадзення"
+ "Параўнайце ўнікальны набор эмодзі."
+ "Параўнайце ўнікальныя эмодзі, пераканаўшыся, што яны размешчаны ў тым жа парадку."
+ "Яны не супадаюць"
+ "Яны супадаюць"
+ "Для працягу працы прыміце запыт на запуск працэсу праверкі ў іншым сеансе."
+ "Чаканне прыняцця запыту"
+
diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml
index 591113eb1b..232a845e70 100644
--- a/gradle/libs.versions.toml
+++ b/gradle/libs.versions.toml
@@ -6,7 +6,7 @@
android_gradle_plugin = "8.2.2"
kotlin = "1.9.22"
ksp = "1.9.22-1.0.17"
-firebaseAppDistribution = "4.0.1"
+firebaseAppDistribution = "4.1.0"
# AndroidX
core = "1.12.0"
@@ -18,8 +18,8 @@ activity = "1.8.2"
media3 = "1.2.1"
# Compose
-compose_bom = "2024.01.00"
-composecompiler = "1.5.8"
+compose_bom = "2024.02.00"
+composecompiler = "1.5.9"
# Coroutines
coroutines = "1.7.3"
@@ -38,7 +38,7 @@ serialization_json = "1.6.2"
showkase = "1.0.2"
appyx = "1.4.0"
sqldelight = "2.0.1"
-wysiwyg = "2.25.0"
+wysiwyg = "2.29.0"
# DI
dagger = "2.50"
@@ -60,9 +60,9 @@ android_gradle_plugin = { module = "com.android.tools.build:gradle", version.ref
android_desugar = "com.android.tools:desugar_jdk_libs:2.0.4"
kotlin_gradle_plugin = { module = "org.jetbrains.kotlin:kotlin-gradle-plugin", version.ref = "kotlin" }
kover_gradle_plugin = { module = "org.jetbrains.kotlinx:kover-gradle-plugin", version.ref = "kover" }
-gms_google_services = "com.google.gms:google-services:4.4.0"
+gms_google_services = "com.google.gms:google-services:4.4.1"
# https://firebase.google.com/docs/android/setup#available-libraries
-google_firebase_bom = "com.google.firebase:firebase-bom:32.7.1"
+google_firebase_bom = "com.google.firebase:firebase-bom:32.7.2"
firebase_appdistribution_gradle = { module = "com.google.firebase:firebase-appdistribution-gradle", version.ref = "firebaseAppDistribution" }
autonomousapps_dependencyanalysis_plugin = { module = "com.autonomousapps:dependency-analysis-gradle-plugin", version.ref = "dependencyAnalysis" }
@@ -93,8 +93,7 @@ androidx_preference = "androidx.preference:preference:1.2.1"
androidx_webkit = "androidx.webkit:webkit:1.10.0"
androidx_compose_bom = { module = "androidx.compose:compose-bom", version.ref = "compose_bom" }
-# When Material3 updates its transitive Compose dependencies, take a look at the constraints in `DependencyHandleScope.kt`. We may be able to remove the workaround there.
-androidx_compose_material3 = "androidx.compose.material3:material3:1.2.0-rc01"
+androidx_compose_material3 = "androidx.compose.material3:material3:1.2.0"
androidx_compose_ui = { module = "androidx.compose.ui:ui" }
androidx_compose_ui_tooling = { module = "androidx.compose.ui:ui-tooling" }
androidx_compose_ui_tooling_preview = { module = "androidx.compose.ui:ui-tooling-preview" }
@@ -133,7 +132,7 @@ test_junitext = "androidx.test.ext:junit:1.1.5"
test_mockk = "io.mockk:mockk:1.13.9"
test_konsist = "com.lemonappdev:konsist:0.13.0"
test_turbine = "app.cash.turbine:turbine:1.0.0"
-test_truth = "com.google.truth:truth:1.3.0"
+test_truth = "com.google.truth:truth:1.4.0"
test_parameter_injector = "com.google.testparameterinjector:test-parameter-injector:1.15"
test_robolectric = "org.robolectric:robolectric:4.11.1"
test_appyx_junit = { module = "com.bumble.appyx:testing-junit4", version.ref = "appyx" }
@@ -143,7 +142,7 @@ coil = { module = "io.coil-kt:coil", version.ref = "coil" }
coil_compose = { module = "io.coil-kt:coil-compose", version.ref = "coil" }
coil_gif = { module = "io.coil-kt:coil-gif", version.ref = "coil" }
coil_test = { module = "io.coil-kt:coil-test", version.ref = "coil" }
-compound = { module = "io.element.android:compound-android", version = "0.0.3" }
+compound = { module = "io.element.android:compound-android", version = "0.0.4" }
datetime = { module = "org.jetbrains.kotlinx:kotlinx-datetime", version.ref = "datetime" }
serialization_json = { module = "org.jetbrains.kotlinx:kotlinx-serialization-json", version.ref = "serialization_json" }
kotlinx_collections_immutable = "org.jetbrains.kotlinx:kotlinx-collections-immutable:0.3.7"
@@ -153,7 +152,7 @@ jsoup = "org.jsoup:jsoup:1.17.2"
appyx_core = { module = "com.bumble.appyx:core", version.ref = "appyx" }
molecule-runtime = "app.cash.molecule:molecule-runtime:1.3.2"
timber = "com.jakewharton.timber:timber:5.0.1"
-matrix_sdk = "org.matrix.rustcomponents:sdk-android:0.1.96"
+matrix_sdk = "org.matrix.rustcomponents:sdk-android:0.1.99"
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" }
@@ -173,7 +172,7 @@ opusencoder = "io.element.android:opusencoder:1.1.0"
kotlinpoet = "com.squareup:kotlinpoet:1.16.0"
# Analytics
-posthog = "com.posthog:posthog-android:3.1.5"
+posthog = "com.posthog:posthog-android:3.1.6"
sentry = "io.sentry:sentry-android:7.3.0"
matrix_analytics_events = "com.github.matrix-org:matrix-analytics-events:aa14cbcdf81af2746d20a71779ec751f971e1d7f"
@@ -212,7 +211,7 @@ kotlin_serialization = { id = "org.jetbrains.kotlin.plugin.serialization", versi
kapt = { id = "org.jetbrains.kotlin.kapt", version.ref = "kotlin" }
ksp = { id = "com.google.devtools.ksp", version.ref = "ksp" }
anvil = { id = "com.squareup.anvil", version.ref = "anvil" }
-detekt = "io.gitlab.arturbosch.detekt:1.23.4"
+detekt = "io.gitlab.arturbosch.detekt:1.23.5"
ktlint = "org.jlleitschuh.gradle.ktlint:12.1.0"
dependencygraph = "com.savvasdalkitsis.module-dependency-graph:0.12"
dependencycheck = "org.owasp.dependencycheck:9.0.9"
@@ -222,7 +221,4 @@ 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" }
-
-# Version '4.3.1.3277' introduced some regressions in CI time (more than 2x slower), so make sure
-# this is no longer the case before upgrading.
-sonarqube = "org.sonarqube:4.2.1.3168"
+sonarqube = "org.sonarqube:4.4.1.3373"
diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar
index 7f93135c49..d64cd49177 100644
Binary files a/gradle/wrapper/gradle-wrapper.jar and b/gradle/wrapper/gradle-wrapper.jar differ
diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties
index a7a990ab2a..865f1ba80d 100644
--- a/gradle/wrapper/gradle-wrapper.properties
+++ b/gradle/wrapper/gradle-wrapper.properties
@@ -1,7 +1,7 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
-distributionSha256Sum=c16d517b50dd28b3f5838f0e844b7520b8f1eb610f2f29de7e4e04a1b7c9c79b
-distributionUrl=https\://services.gradle.org/distributions/gradle-8.5-all.zip
+distributionSha256Sum=85719317abd2112f021d4f41f09ec370534ba288432065f4b477b6a3b652910d
+distributionUrl=https\://services.gradle.org/distributions/gradle-8.6-all.zip
networkTimeout=10000
validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME
diff --git a/libraries/androidutils/src/main/res/values-be/translations.xml b/libraries/androidutils/src/main/res/values-be/translations.xml
new file mode 100644
index 0000000000..699c2537d1
--- /dev/null
+++ b/libraries/androidutils/src/main/res/values-be/translations.xml
@@ -0,0 +1,4 @@
+
+
+ "Не знойдзена сумяшчальная праграма для выканання гэтага дзеяння."
+
diff --git a/libraries/dateformatter/test/src/main/kotlin/io/element/android/libraries/dateformatter/test/FakeLastMessageTimestampFormatter.kt b/libraries/dateformatter/test/src/main/kotlin/io/element/android/libraries/dateformatter/test/FakeLastMessageTimestampFormatter.kt
index 47226c34d9..ca248f6bf8 100644
--- a/libraries/dateformatter/test/src/main/kotlin/io/element/android/libraries/dateformatter/test/FakeLastMessageTimestampFormatter.kt
+++ b/libraries/dateformatter/test/src/main/kotlin/io/element/android/libraries/dateformatter/test/FakeLastMessageTimestampFormatter.kt
@@ -18,6 +18,8 @@ package io.element.android.libraries.dateformatter.test
import io.element.android.libraries.dateformatter.api.LastMessageTimestampFormatter
+const val A_FORMATTED_DATE = "formatted_date"
+
class FakeLastMessageTimestampFormatter : LastMessageTimestampFormatter {
private var format = ""
fun givenFormat(format: String) {
diff --git a/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/atomic/pages/HeaderFooterPage.kt b/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/atomic/pages/HeaderFooterPage.kt
index c08eb5149a..6b99537dc9 100644
--- a/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/atomic/pages/HeaderFooterPage.kt
+++ b/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/atomic/pages/HeaderFooterPage.kt
@@ -68,7 +68,9 @@ fun HeaderFooterPage(
content()
}
// Footer
- footer()
+ Box(modifier = Modifier.padding(horizontal = 16.dp)) {
+ footer()
+ }
}
}
}
diff --git a/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/atomic/pages/OnBoardingPage.kt b/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/atomic/pages/OnBoardingPage.kt
index 1b8aed72c2..9f028f5c5a 100644
--- a/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/atomic/pages/OnBoardingPage.kt
+++ b/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/atomic/pages/OnBoardingPage.kt
@@ -67,13 +67,12 @@ fun OnBoardingPage(
modifier = Modifier
.fillMaxSize()
.systemBarsPadding()
- .padding(vertical = 16.dp),
+ .padding(all = 20.dp),
) {
// Content
Column(
modifier = Modifier
.weight(1f)
- .padding(horizontal = 24.dp)
.fillMaxWidth(),
horizontalAlignment = contentAlignment,
) {
diff --git a/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/atomic/pages/SunsetPage.kt b/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/atomic/pages/SunsetPage.kt
index 476545befc..c4a56404cb 100644
--- a/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/atomic/pages/SunsetPage.kt
+++ b/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/atomic/pages/SunsetPage.kt
@@ -37,8 +37,10 @@ import androidx.compose.ui.layout.ContentScale
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.unit.dp
+import io.element.android.compound.annotations.CoreColorToken
import io.element.android.compound.theme.ElementTheme
-import io.element.android.compound.theme.ForcedDarkElementTheme
+import io.element.android.compound.tokens.generated.internal.DarkColorTokens
+import io.element.android.compound.tokens.generated.internal.LightColorTokens
import io.element.android.libraries.designsystem.R
import io.element.android.libraries.designsystem.preview.ElementPreview
import io.element.android.libraries.designsystem.preview.PreviewsDayNight
@@ -54,7 +56,11 @@ fun SunsetPage(
modifier: Modifier = Modifier,
overallContent: @Composable () -> Unit,
) {
- ForcedDarkElementTheme(lightStatusBar = true) {
+ ElementTheme(
+ // Always use the opposite value of the current theme
+ darkTheme = ElementTheme.isLightTheme,
+ applySystemBarsUpdate = false,
+ ) {
Box(
modifier = modifier.fillMaxSize()
) {
@@ -107,21 +113,32 @@ fun SunsetPage(
}
}
+@OptIn(CoreColorToken::class)
@Composable
-private fun SunsetBackground(
- modifier: Modifier = Modifier,
-) {
- Column(modifier = modifier.fillMaxSize()) {
+private fun SunsetBackground() {
+ Column(modifier = Modifier.fillMaxSize()) {
+ // The top background colors are the opposite of the current theme ones
+ val topBackgroundColor = if (ElementTheme.isLightTheme) {
+ DarkColorTokens.colorThemeBg
+ } else {
+ LightColorTokens.colorThemeBg
+ }
+ // The bottom background colors follow the current theme
+ val bottomBackgroundColor = if (ElementTheme.isLightTheme) {
+ LightColorTokens.colorThemeBg
+ } else {
+ // The dark background color doesn't 100% match the image, so we use a custom color
+ Color(0xFF121418)
+ }
Box(
modifier = Modifier
.fillMaxWidth()
.weight(0.3f)
- .background(Color.White)
+ .background(topBackgroundColor)
)
Image(
- modifier = Modifier
- .fillMaxWidth(),
- painter = painterResource(id = R.drawable.light_dark),
+ modifier = Modifier.fillMaxWidth(),
+ painter = painterResource(id = R.drawable.bg_migration),
contentScale = ContentScale.Crop,
contentDescription = null,
)
@@ -129,7 +146,7 @@ private fun SunsetBackground(
modifier = Modifier
.fillMaxWidth()
.weight(0.7f)
- .background(Color(0xFF121418))
+ .background(bottomBackgroundColor)
)
}
}
diff --git a/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/components/Bloom.kt b/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/components/Bloom.kt
index 5742438641..bb3373b397 100644
--- a/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/components/Bloom.kt
+++ b/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/components/Bloom.kt
@@ -23,7 +23,6 @@ import android.os.Build
import android.text.TextPaint
import androidx.annotation.FloatRange
import androidx.compose.foundation.Image
-import androidx.compose.foundation.isSystemInDarkTheme
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.consumeWindowInsets
@@ -136,13 +135,13 @@ object BloomDefaults {
@Composable
fun defaultLayers() = persistentListOf(
// Bottom layer
- if (isSystemInDarkTheme()) {
- BloomLayer(0.5f, BlendMode.Exclusion)
- } else {
+ if (ElementTheme.isLightTheme) {
BloomLayer(0.2f, BlendMode.Hardlight)
+ } else {
+ BloomLayer(0.5f, BlendMode.Exclusion)
},
// Top layer
- BloomLayer(if (isSystemInDarkTheme()) 0.2f else 0.8f, BlendMode.Color),
+ BloomLayer(if (ElementTheme.isLightTheme) 0.8f else 0.2f, BlendMode.Color),
)
}
diff --git a/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/components/BlurHashAsyncImage.kt b/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/components/BlurHashAsyncImage.kt
index dcfce743c1..23e1882382 100644
--- a/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/components/BlurHashAsyncImage.kt
+++ b/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/components/BlurHashAsyncImage.kt
@@ -73,7 +73,6 @@ fun BlurHashAsyncImage(
@Composable
private fun BlurHashImage(
blurHash: String?,
- modifier: Modifier = Modifier,
contentDescription: String? = null,
contentScale: ContentScale = ContentScale.Fit,
) {
@@ -91,7 +90,7 @@ private fun BlurHashImage(
}
bitmapState.value?.let { bitmap ->
Image(
- modifier = modifier.fillMaxSize(),
+ modifier = Modifier.fillMaxSize(),
bitmap = bitmap.asImageBitmap(),
contentScale = contentScale,
contentDescription = contentDescription
diff --git a/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/components/dialogs/ConfirmationDialog.kt b/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/components/dialogs/ConfirmationDialog.kt
index aed618cd3b..9fccecaa6e 100644
--- a/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/components/dialogs/ConfirmationDialog.kt
+++ b/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/components/dialogs/ConfirmationDialog.kt
@@ -65,7 +65,6 @@ private fun ConfirmationDialogContent(
cancelText: String,
onSubmitClicked: () -> Unit,
onCancelClicked: () -> Unit,
- modifier: Modifier = Modifier,
title: String? = null,
thirdButtonText: String? = null,
onThirdButtonClicked: () -> Unit = {},
@@ -73,7 +72,6 @@ private fun ConfirmationDialogContent(
icon: @Composable (() -> Unit)? = null,
) {
SimpleAlertDialogContent(
- modifier = modifier,
title = title,
content = content,
submitText = submitText,
diff --git a/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/components/dialogs/ErrorDialog.kt b/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/components/dialogs/ErrorDialog.kt
index 52779052a6..a4a4a6e8b9 100644
--- a/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/components/dialogs/ErrorDialog.kt
+++ b/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/components/dialogs/ErrorDialog.kt
@@ -51,12 +51,10 @@ fun ErrorDialog(
private fun ErrorDialogContent(
content: String,
onSubmitClicked: () -> Unit,
- modifier: Modifier = Modifier,
title: String = ErrorDialogDefaults.title,
submitText: String = ErrorDialogDefaults.submitText,
) {
SimpleAlertDialogContent(
- modifier = modifier,
title = title,
content = content,
submitText = submitText,
diff --git a/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/components/dialogs/ListDialog.kt b/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/components/dialogs/ListDialog.kt
index 83079584c3..71cf3e78ee 100644
--- a/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/components/dialogs/ListDialog.kt
+++ b/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/components/dialogs/ListDialog.kt
@@ -80,7 +80,6 @@ private fun ListDialogContent(
onSubmitClicked: () -> Unit,
cancelText: String,
submitText: String,
- modifier: Modifier = Modifier,
title: String? = null,
enabled: Boolean = true,
subtitle: @Composable (() -> Unit)? = null,
@@ -88,7 +87,6 @@ private fun ListDialogContent(
SimpleAlertDialogContent(
title = title,
subtitle = subtitle,
- modifier = modifier,
cancelText = cancelText,
submitText = submitText,
onCancelClicked = onDismissRequest,
diff --git a/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/components/dialogs/MultipleSelectionDialog.kt b/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/components/dialogs/MultipleSelectionDialog.kt
index e790cb1921..7bea51952a 100644
--- a/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/components/dialogs/MultipleSelectionDialog.kt
+++ b/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/components/dialogs/MultipleSelectionDialog.kt
@@ -84,7 +84,6 @@ private fun MultipleSelectionDialogContent(
onConfirmClicked: (List) -> Unit,
dismissButtonTitle: String,
onDismissRequest: () -> Unit,
- modifier: Modifier = Modifier,
title: String? = null,
initialSelected: ImmutableList = persistentListOf(),
subtitle: @Composable (() -> Unit)? = null,
@@ -96,7 +95,6 @@ private fun MultipleSelectionDialogContent(
SimpleAlertDialogContent(
title = title,
subtitle = subtitle,
- modifier = modifier,
submitText = confirmButtonTitle,
onSubmitClicked = {
onConfirmClicked(selectedOptionIndexes.toList())
diff --git a/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/components/dialogs/RetryDialog.kt b/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/components/dialogs/RetryDialog.kt
index 78897efb50..161b552ce4 100644
--- a/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/components/dialogs/RetryDialog.kt
+++ b/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/components/dialogs/RetryDialog.kt
@@ -56,13 +56,11 @@ private fun RetryDialogContent(
content: String,
onRetry: () -> Unit,
onDismiss: () -> Unit,
- modifier: Modifier = Modifier,
title: String = RetryDialogDefaults.title,
retryText: String = RetryDialogDefaults.retryText,
dismissText: String = RetryDialogDefaults.dismissText,
) {
SimpleAlertDialogContent(
- modifier = modifier,
title = title,
content = content,
submitText = retryText,
diff --git a/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/components/dialogs/SingleSelectionDialog.kt b/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/components/dialogs/SingleSelectionDialog.kt
index 2462fd779f..99ed32b674 100644
--- a/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/components/dialogs/SingleSelectionDialog.kt
+++ b/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/components/dialogs/SingleSelectionDialog.kt
@@ -79,7 +79,6 @@ private fun SingleSelectionDialogContent(
onOptionSelected: (Int) -> Unit,
dismissButtonTitle: String,
onDismissRequest: () -> Unit,
- modifier: Modifier = Modifier,
title: String? = null,
initialSelection: Int? = null,
subtitle: @Composable (() -> Unit)? = null,
@@ -87,7 +86,6 @@ private fun SingleSelectionDialogContent(
SimpleAlertDialogContent(
title = title,
subtitle = subtitle,
- modifier = modifier,
submitText = dismissButtonTitle,
onSubmitClicked = onDismissRequest,
applyPaddingToContents = false,
diff --git a/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/components/preferences/PreferenceCategory.kt b/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/components/preferences/PreferenceCategory.kt
index 42dc343782..45764c588b 100644
--- a/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/components/preferences/PreferenceCategory.kt
+++ b/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/components/preferences/PreferenceCategory.kt
@@ -52,9 +52,9 @@ fun PreferenceCategory(
}
@Composable
-private fun PreferenceCategoryTitle(title: String, modifier: Modifier = Modifier) {
+private fun PreferenceCategoryTitle(title: String) {
Text(
- modifier = modifier.padding(
+ modifier = Modifier.padding(
top = 20.dp,
bottom = 8.dp,
start = preferencePaddingHorizontal,
diff --git a/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/components/preferences/PreferencePage.kt b/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/components/preferences/PreferencePage.kt
index 063c17aac1..1d6a5669b9 100644
--- a/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/components/preferences/PreferencePage.kt
+++ b/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/components/preferences/PreferencePage.kt
@@ -80,10 +80,8 @@ fun PreferencePage(
private fun PreferenceTopAppBar(
title: String,
onBackPressed: () -> Unit,
- modifier: Modifier = Modifier,
) {
TopAppBar(
- modifier = modifier,
navigationIcon = {
BackButton(onClick = onBackPressed)
},
diff --git a/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/components/preferences/PreferenceTextField.kt b/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/components/preferences/PreferenceTextField.kt
index 0c3735547b..f616c20a72 100644
--- a/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/components/preferences/PreferenceTextField.kt
+++ b/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/components/preferences/PreferenceTextField.kt
@@ -91,7 +91,6 @@ private fun TextFieldDialog(
onDismissRequest: () -> Unit,
value: String?,
placeholder: String?,
- modifier: Modifier = Modifier,
validation: (String?) -> Boolean = { true },
onValidationErrorMessage: String? = null,
autoSelectOnDisplay: Boolean = true,
@@ -110,7 +109,6 @@ private fun TextFieldDialog(
onSubmit = { onSubmit(textFieldContents.text) },
onDismissRequest = onDismissRequest,
enabled = canSubmit,
- modifier = modifier,
) {
item {
TextFieldListItem(
diff --git a/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/icons/IconsPreview.kt b/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/icons/IconsPreview.kt
index 8bd7d2b16e..e9952ee1e0 100644
--- a/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/icons/IconsPreview.kt
+++ b/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/icons/IconsPreview.kt
@@ -98,11 +98,9 @@ private fun IconsPreview(
title: String,
iconsList: ImmutableList,
iconNameTransform: (String) -> String,
- modifier: Modifier = Modifier,
) = ElementPreview {
val context = LocalContext.current
Column(
- modifier = modifier,
verticalArrangement = Arrangement.spacedBy(2.dp),
) {
Text(
diff --git a/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/modifiers/ClearFocusOnTap.kt b/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/modifiers/ClearFocusOnTap.kt
new file mode 100644
index 0000000000..15f925b993
--- /dev/null
+++ b/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/modifiers/ClearFocusOnTap.kt
@@ -0,0 +1,30 @@
+/*
+ * Copyright (c) 2024 New Vector Ltd
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package io.element.android.libraries.designsystem.modifiers
+
+import androidx.compose.foundation.gestures.detectTapGestures
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.focus.FocusManager
+import androidx.compose.ui.input.pointer.pointerInput
+
+fun Modifier.clearFocusOnTap(focusManager: FocusManager): Modifier = then(
+ pointerInput(Unit) {
+ detectTapGestures(onTap = {
+ focusManager.clearFocus()
+ })
+ }
+)
diff --git a/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/theme/components/AlertDialogContent.kt b/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/theme/components/AlertDialogContent.kt
index 8ea42eef88..a52c023fa6 100644
--- a/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/theme/components/AlertDialogContent.kt
+++ b/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/theme/components/AlertDialogContent.kt
@@ -55,7 +55,6 @@ internal fun SimpleAlertDialogContent(
content: String,
submitText: String,
onSubmitClicked: () -> Unit,
- modifier: Modifier = Modifier,
title: String? = null,
subtitle: @Composable (() -> Unit)? = null,
destructiveSubmit: Boolean = false,
@@ -67,7 +66,6 @@ internal fun SimpleAlertDialogContent(
icon: @Composable (() -> Unit)? = null,
) {
SimpleAlertDialogContent(
- modifier = modifier,
icon = icon,
title = title,
subtitle = subtitle,
@@ -92,7 +90,6 @@ internal fun SimpleAlertDialogContent(
internal fun SimpleAlertDialogContent(
submitText: String,
onSubmitClicked: () -> Unit,
- modifier: Modifier = Modifier,
title: String? = null,
subtitle: @Composable (() -> Unit)? = null,
destructiveSubmit: Boolean = false,
@@ -148,7 +145,6 @@ internal fun SimpleAlertDialogContent(
}
}
},
- modifier = modifier,
title = title?.let { titleText ->
@Composable {
Text(
@@ -192,11 +188,9 @@ internal fun AlertDialogContent(
iconContentColor: Color,
titleContentColor: Color,
textContentColor: Color,
- modifier: Modifier = Modifier,
applyPaddingToContents: Boolean = true,
) {
Surface(
- modifier = modifier,
shape = shape,
color = containerColor,
tonalElevation = tonalElevation,
diff --git a/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/utils/LogCompositions.kt b/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/utils/LogCompositions.kt
deleted file mode 100644
index 2618a5de82..0000000000
--- a/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/utils/LogCompositions.kt
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * Copyright (c) 2023 New Vector Ltd
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package io.element.android.libraries.designsystem.utils
-
-import androidx.compose.runtime.Composable
-import androidx.compose.runtime.SideEffect
-import androidx.compose.runtime.remember
-import io.element.android.libraries.designsystem.BuildConfig
-import timber.log.Timber
-
-// Note the inline function below which ensures that this function is essentially
-// copied at the call site to ensure that its logging only recompositions from the
-// original call site.
-@Composable
-fun LogCompositions(tag: String, msg: String) {
- if (BuildConfig.DEBUG) {
- val ref = remember { Ref() }
- SideEffect { ref.value++ }
- Timber.tag(tag).d("Compositions: $msg ${ref.value}")
- }
-}
-
-private class Ref {
- var value: Int = 0
-}
diff --git a/libraries/designsystem/src/main/res/drawable-night/bg_migration.png b/libraries/designsystem/src/main/res/drawable-night/bg_migration.png
new file mode 100644
index 0000000000..41cba4f4ba
Binary files /dev/null and b/libraries/designsystem/src/main/res/drawable-night/bg_migration.png differ
diff --git a/libraries/designsystem/src/main/res/drawable/light_dark.png b/libraries/designsystem/src/main/res/drawable/bg_migration.png
similarity index 100%
rename from libraries/designsystem/src/main/res/drawable/light_dark.png
rename to libraries/designsystem/src/main/res/drawable/bg_migration.png
diff --git a/libraries/eventformatter/impl/src/main/res/values-be/translations.xml b/libraries/eventformatter/impl/src/main/res/values-be/translations.xml
new file mode 100644
index 0000000000..d46abb9041
--- /dev/null
+++ b/libraries/eventformatter/impl/src/main/res/values-be/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-de/translations.xml b/libraries/eventformatter/impl/src/main/res/values-de/translations.xml
index 51f73581c1..3444cdaef0 100644
--- a/libraries/eventformatter/impl/src/main/res/values-de/translations.xml
+++ b/libraries/eventformatter/impl/src/main/res/values-de/translations.xml
@@ -39,6 +39,8 @@
"Du hast den Raumnamen geändert in: %1$s"
"%1$s hat den Raumnamen entfernt"
"Du hast den Raumnamen entfernt"
+ "%1$shat keine Änderungen vorgenommen"
+ "Du hast keine Änderungen vorgenommen"
"%1$s hat die Einladung abgelehnt"
"Du hast die Einladung abgelehnt"
"%1$s hat %2$s entfernt"
diff --git a/libraries/eventformatter/impl/src/main/res/values-hu/translations.xml b/libraries/eventformatter/impl/src/main/res/values-hu/translations.xml
index dd38dcbbe4..167b695698 100644
--- a/libraries/eventformatter/impl/src/main/res/values-hu/translations.xml
+++ b/libraries/eventformatter/impl/src/main/res/values-hu/translations.xml
@@ -39,6 +39,8 @@
"Megváltoztatta a szoba nevét: %1$s"
"%1$s eltávolította a szoba nevét"
"Eltávolította a szoba nevét"
+ "%1$s nem változtatott semmin"
+ "Nem változtatott semmin"
"%1$s elutasította a meghívást"
"Elutasította a meghívást"
"%1$s eltávolította: %2$s"
diff --git a/libraries/featureflag/api/src/main/kotlin/io/element/android/libraries/featureflag/api/FeatureFlags.kt b/libraries/featureflag/api/src/main/kotlin/io/element/android/libraries/featureflag/api/FeatureFlags.kt
index 61c155caac..3c56c81fae 100644
--- a/libraries/featureflag/api/src/main/kotlin/io/element/android/libraries/featureflag/api/FeatureFlags.kt
+++ b/libraries/featureflag/api/src/main/kotlin/io/element/android/libraries/featureflag/api/FeatureFlags.kt
@@ -75,4 +75,11 @@ enum class FeatureFlags(
defaultValue = true,
isFinished = false,
),
+ MarkAsUnread(
+ key = "feature.markAsUnread",
+ title = "Mark as unread",
+ description = "Allow user to mark a room as unread",
+ defaultValue = true,
+ isFinished = false,
+ ),
}
diff --git a/libraries/featureflag/impl/src/main/kotlin/io/element/android/libraries/featureflag/impl/StaticFeatureFlagProvider.kt b/libraries/featureflag/impl/src/main/kotlin/io/element/android/libraries/featureflag/impl/StaticFeatureFlagProvider.kt
index 75b16d4e84..8462a33ba5 100644
--- a/libraries/featureflag/impl/src/main/kotlin/io/element/android/libraries/featureflag/impl/StaticFeatureFlagProvider.kt
+++ b/libraries/featureflag/impl/src/main/kotlin/io/element/android/libraries/featureflag/impl/StaticFeatureFlagProvider.kt
@@ -40,6 +40,7 @@ class StaticFeatureFlagProvider @Inject constructor() :
FeatureFlags.PinUnlock -> true
FeatureFlags.Mentions -> true
FeatureFlags.SecureStorage -> true
+ FeatureFlags.MarkAsUnread -> false
}
} else {
false
diff --git a/libraries/featureflag/ui/src/main/kotlin/io/element/android/libraries/featureflag/ui/FeatureListView.kt b/libraries/featureflag/ui/src/main/kotlin/io/element/android/libraries/featureflag/ui/FeatureListView.kt
index a0e298db26..20648e6142 100644
--- a/libraries/featureflag/ui/src/main/kotlin/io/element/android/libraries/featureflag/ui/FeatureListView.kt
+++ b/libraries/featureflag/ui/src/main/kotlin/io/element/android/libraries/featureflag/ui/FeatureListView.kt
@@ -49,13 +49,11 @@ fun FeatureListView(
private fun FeaturePreferenceView(
feature: FeatureUiModel,
onCheckedChange: (Boolean) -> Unit,
- modifier: Modifier = Modifier
) {
PreferenceCheckbox(
title = feature.title,
supportingText = feature.description,
isChecked = feature.isEnabled,
- modifier = modifier,
onCheckedChange = onCheckedChange
)
}
diff --git a/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/room/MatrixRoom.kt b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/room/MatrixRoom.kt
index 762121a8fe..25806b6a06 100644
--- a/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/room/MatrixRoom.kt
+++ b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/room/MatrixRoom.kt
@@ -31,6 +31,7 @@ import io.element.android.libraries.matrix.api.poll.PollKind
import io.element.android.libraries.matrix.api.room.location.AssetType
import io.element.android.libraries.matrix.api.room.tags.RoomNotableTags
import io.element.android.libraries.matrix.api.timeline.MatrixTimeline
+import io.element.android.libraries.matrix.api.timeline.ReceiptType
import io.element.android.libraries.matrix.api.widget.MatrixWidgetDriver
import io.element.android.libraries.matrix.api.widget.MatrixWidgetSettings
import kotlinx.coroutines.flow.Flow
@@ -57,6 +58,7 @@ interface MatrixRoom : Closeable {
val isDm: Boolean get() = isDirect && isOneToOne
val roomInfoFlow: Flow
+ val roomTypingMembersFlow: Flow>
/**
* The current notable tags as a Flow.
@@ -158,6 +160,17 @@ interface MatrixRoom : Closeable {
suspend fun setIsFavorite(isFavorite: Boolean): Result
+ /**
+ * Reverts a previously set unread flag, and eventually send a Read Receipt.
+ * @param receiptType The type of receipt to send. If null, no Read Receipt will be sent.
+ */
+ suspend fun markAsRead(receiptType: ReceiptType?): Result
+
+ /**
+ * Sets a flag on the room to indicate that the user has explicitly marked it as unread.
+ */
+ suspend fun markAsUnread(): Result
+
/**
* Share a location message in the room.
*
diff --git a/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/room/MessageEventType.kt b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/room/MessageEventType.kt
index 109e50e602..ea9e37cfd6 100644
--- a/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/room/MessageEventType.kt
+++ b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/room/MessageEventType.kt
@@ -28,9 +28,15 @@ enum class MessageEventType {
KEY_VERIFICATION_KEY,
KEY_VERIFICATION_MAC,
KEY_VERIFICATION_DONE,
- REACTION_SENT,
+ REACTION,
ROOM_ENCRYPTED,
ROOM_MESSAGE,
ROOM_REDACTION,
- STICKER
+ STICKER,
+ POLL_END,
+ POLL_RESPONSE,
+ POLL_START,
+ UNSTABLE_POLL_END,
+ UNSTABLE_POLL_RESPONSE,
+ UNSTABLE_POLL_START,
}
diff --git a/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/room/RoomMember.kt b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/room/RoomMember.kt
index 86cff93688..908390484b 100644
--- a/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/room/RoomMember.kt
+++ b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/room/RoomMember.kt
@@ -27,7 +27,19 @@ data class RoomMember(
val powerLevel: Long,
val normalizedPowerLevel: Long,
val isIgnored: Boolean,
-)
+) {
+ /**
+ * Disambiguated display name for the RoomMember.
+ * If the display name is null, the user ID is returned.
+ * If the display name is ambiguous, the user ID is appended in parentheses.
+ * Otherwise, the display name is returned.
+ */
+ val disambiguatedDisplayName: String = when {
+ displayName == null -> userId.value
+ isNameAmbiguous -> "$displayName ($userId)"
+ else -> displayName
+ }
+}
enum class RoomMembershipState {
BAN,
diff --git a/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/roomlist/DynamicRoomList.kt b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/roomlist/DynamicRoomList.kt
index 02833762e2..8cb43af24c 100644
--- a/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/roomlist/DynamicRoomList.kt
+++ b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/roomlist/DynamicRoomList.kt
@@ -28,29 +28,7 @@ import kotlinx.coroutines.flow.onEach
* It lets load rooms on demand and filter them.
*/
interface DynamicRoomList : RoomList {
- sealed interface Filter {
- /**
- * No filter applied.
- */
- data object All : Filter
-
- /**
- * Filter only the left rooms.
- */
- data object AllNonLeft : Filter
-
- /**
- * Filter all rooms.
- */
- data object None : Filter
-
- /**
- * Filter rooms by normalized room name.
- */
- data class NormalizedMatchRoomName(val pattern: String) : Filter
- }
-
- val currentFilter: StateFlow
+ val currentFilter: StateFlow
val loadedPages: StateFlow
val pageSize: Int
@@ -68,7 +46,7 @@ interface DynamicRoomList : RoomList {
* Update the filter to apply to the list.
* @param filter the filter to apply.
*/
- suspend fun updateFilter(filter: Filter)
+ suspend fun updateFilter(filter: RoomListFilter)
}
/**
diff --git a/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/roomlist/RoomListFilter.kt b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/roomlist/RoomListFilter.kt
new file mode 100644
index 0000000000..99ba4531e2
--- /dev/null
+++ b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/roomlist/RoomListFilter.kt
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 2024 New Vector Ltd
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package io.element.android.libraries.matrix.api.roomlist
+
+sealed interface RoomListFilter {
+ companion object {
+ fun all(vararg filters: RoomListFilter): RoomListFilter {
+ return All(filters.toList())
+ }
+
+ fun any(vararg filters: RoomListFilter): RoomListFilter {
+ return Any(filters.toList())
+ }
+ }
+
+ data class All(
+ val filters: List
+ ) : RoomListFilter
+
+ data class Any(
+ val filters: List
+ ) : RoomListFilter
+
+ data object NonLeft : RoomListFilter
+
+ data object Unread : RoomListFilter
+
+ sealed interface Category : RoomListFilter {
+ data object Group : Category
+ data object People : Category
+ }
+
+ data object None : RoomListFilter
+
+ data class NormalizedMatchRoomName(
+ val pattern: String
+ ) : RoomListFilter
+
+ data class FuzzyMatchRoomName(
+ val pattern: String
+ ) : RoomListFilter
+}
diff --git a/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/roomlist/RoomSummary.kt b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/roomlist/RoomSummary.kt
index cc584f08bb..b8e6dbd84f 100644
--- a/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/roomlist/RoomSummary.kt
+++ b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/roomlist/RoomSummary.kt
@@ -43,6 +43,7 @@ data class RoomSummaryDetails(
val numUnreadMessages: Int,
val numUnreadMentions: Int,
val numUnreadNotifications: Int,
+ val isMarkedUnread: Boolean,
val inviter: RoomMember?,
val userDefinedNotificationMode: RoomNotificationMode?,
val hasRoomCall: Boolean,
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 87e4f4ab73..fc4840d610 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
@@ -85,11 +85,7 @@ data class ProfileChangeContent(
data class StateContent(
val stateKey: String,
val content: OtherState
-) : EventContent {
- fun isVisibleInTimeline(): Boolean {
- return content.isVisibleInTimeline()
- }
-}
+) : EventContent
data class FailedToParseMessageLikeContent(
val eventType: String,
diff --git a/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/timeline/item/event/OtherState.kt b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/timeline/item/event/OtherState.kt
index e5119c388e..6960b3565d 100644
--- a/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/timeline/item/event/OtherState.kt
+++ b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/timeline/item/event/OtherState.kt
@@ -41,30 +41,4 @@ sealed interface OtherState {
data object SpaceChild : OtherState
data object SpaceParent : OtherState
data class Custom(val eventType: String) : OtherState
-
- fun isVisibleInTimeline() = when (this) {
- // Visible
- is RoomAvatar,
- is RoomName,
- is RoomTopic,
- is RoomThirdPartyInvite,
- is RoomCreate,
- is RoomEncryption,
- is Custom -> true
- // Hidden
- is RoomAliases,
- is RoomCanonicalAlias,
- is RoomGuestAccess,
- is RoomHistoryVisibility,
- is RoomJoinRules,
- is RoomPinnedEvents,
- is RoomPowerLevels,
- is RoomServerAcl,
- is RoomTombstone,
- is SpaceChild,
- is SpaceParent,
- is PolicyRuleRoom,
- is PolicyRuleServer,
- is PolicyRuleUser -> false
- }
}
diff --git a/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/tracing/TracingFilterConfiguration.kt b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/tracing/TracingFilterConfiguration.kt
index 114c7df0cb..aa4297969a 100644
--- a/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/tracing/TracingFilterConfiguration.kt
+++ b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/tracing/TracingFilterConfiguration.kt
@@ -25,6 +25,7 @@ data class TracingFilterConfiguration(
private val targetsToLogLevel: Map = mapOf(
Target.HYPER to LogLevel.WARN,
Target.MATRIX_SDK_CRYPTO to LogLevel.DEBUG,
+ Target.MATRIX_SDK_CRYPTO_ACCOUNT to LogLevel.TRACE,
Target.MATRIX_SDK_HTTP_CLIENT to LogLevel.DEBUG,
Target.MATRIX_SDK_SLIDING_SYNC to LogLevel.TRACE,
Target.MATRIX_SDK_BASE_SLIDING_SYNC to LogLevel.TRACE,
@@ -58,6 +59,7 @@ enum class Target(open val filter: String) {
MATRIX_SDK_FFI("matrix_sdk_ffi"),
MATRIX_SDK_UNIFFI_API("matrix_sdk_ffi::uniffi_api"),
MATRIX_SDK_CRYPTO("matrix_sdk_crypto"),
+ MATRIX_SDK_CRYPTO_ACCOUNT("matrix_sdk_crypto::olm::account"),
MATRIX_SDK("matrix_sdk"),
MATRIX_SDK_HTTP_CLIENT("matrix_sdk::http_client"),
MATRIX_SDK_CLIENT("matrix_sdk::client"),
diff --git a/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/widget/CallWidgetSettingsProvider.kt b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/widget/CallWidgetSettingsProvider.kt
index f0a22d0128..9e5d8a41ad 100644
--- a/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/widget/CallWidgetSettingsProvider.kt
+++ b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/widget/CallWidgetSettingsProvider.kt
@@ -21,6 +21,7 @@ import java.util.UUID
interface CallWidgetSettingsProvider {
fun provide(
baseUrl: String,
- widgetId: String = UUID.randomUUID().toString()
+ widgetId: String = UUID.randomUUID().toString(),
+ encrypted: Boolean,
): MatrixWidgetSettings
}
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 26bc775e55..f7213becc4 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
@@ -55,10 +55,12 @@ import io.element.android.libraries.matrix.impl.room.RoomSyncSubscriber
import io.element.android.libraries.matrix.impl.room.RustMatrixRoom
import io.element.android.libraries.matrix.impl.roomlist.RoomListFactory
import io.element.android.libraries.matrix.impl.roomlist.RustRoomListService
+import io.element.android.libraries.matrix.impl.roomlist.fullRoomWithTimeline
import io.element.android.libraries.matrix.impl.roomlist.roomOrNull
import io.element.android.libraries.matrix.impl.sync.RustSyncService
import io.element.android.libraries.matrix.impl.usersearch.UserProfileMapper
import io.element.android.libraries.matrix.impl.usersearch.UserSearchResultMapper
+import io.element.android.libraries.matrix.impl.util.SessionDirectoryNameProvider
import io.element.android.libraries.matrix.impl.util.cancelAndDestroy
import io.element.android.libraries.matrix.impl.verification.RustSessionVerificationService
import io.element.android.libraries.sessionstorage.api.SessionStore
@@ -76,12 +78,12 @@ import kotlinx.coroutines.withTimeout
import org.matrix.rustcomponents.sdk.BackupState
import org.matrix.rustcomponents.sdk.Client
import org.matrix.rustcomponents.sdk.ClientDelegate
-import org.matrix.rustcomponents.sdk.FilterStateEventType
import org.matrix.rustcomponents.sdk.FilterTimelineEventType
import org.matrix.rustcomponents.sdk.NotificationProcessSetup
import org.matrix.rustcomponents.sdk.PowerLevels
import org.matrix.rustcomponents.sdk.Room
import org.matrix.rustcomponents.sdk.RoomListItem
+import org.matrix.rustcomponents.sdk.StateEventType
import org.matrix.rustcomponents.sdk.TaskHandle
import org.matrix.rustcomponents.sdk.TimelineEventTypeFilter
import org.matrix.rustcomponents.sdk.use
@@ -133,6 +135,7 @@ class RustMatrixClient(
sessionCoroutineScope = sessionCoroutineScope,
dispatchers = dispatchers,
).apply { start() }
+ private val sessionDirectoryNameProvider = SessionDirectoryNameProvider()
private val isLoggingOut = AtomicBoolean(false)
@@ -203,20 +206,20 @@ class RustMatrixClient(
private val eventFilters = TimelineEventTypeFilter.exclude(
listOf(
- FilterStateEventType.ROOM_ALIASES,
- FilterStateEventType.ROOM_CANONICAL_ALIAS,
- FilterStateEventType.ROOM_GUEST_ACCESS,
- FilterStateEventType.ROOM_HISTORY_VISIBILITY,
- FilterStateEventType.ROOM_JOIN_RULES,
- FilterStateEventType.ROOM_PINNED_EVENTS,
- FilterStateEventType.ROOM_POWER_LEVELS,
- FilterStateEventType.ROOM_SERVER_ACL,
- FilterStateEventType.ROOM_TOMBSTONE,
- FilterStateEventType.SPACE_CHILD,
- FilterStateEventType.SPACE_PARENT,
- FilterStateEventType.POLICY_RULE_ROOM,
- FilterStateEventType.POLICY_RULE_SERVER,
- FilterStateEventType.POLICY_RULE_USER,
+ StateEventType.ROOM_ALIASES,
+ StateEventType.ROOM_CANONICAL_ALIAS,
+ StateEventType.ROOM_GUEST_ACCESS,
+ StateEventType.ROOM_HISTORY_VISIBILITY,
+ StateEventType.ROOM_JOIN_RULES,
+ StateEventType.ROOM_PINNED_EVENTS,
+ StateEventType.ROOM_POWER_LEVELS,
+ StateEventType.ROOM_SERVER_ACL,
+ StateEventType.ROOM_TOMBSTONE,
+ StateEventType.SPACE_CHILD,
+ StateEventType.SPACE_PARENT,
+ StateEventType.POLICY_RULE_ROOM,
+ StateEventType.POLICY_RULE_SERVER,
+ StateEventType.POLICY_RULE_USER,
).map(FilterTimelineEventType::State)
)
@@ -270,12 +273,7 @@ class RustMatrixClient(
private suspend fun pairOfRoom(roomId: RoomId): Pair? {
val cachedRoomListItem = innerRoomListService.roomOrNull(roomId.value)
- val fullRoom = cachedRoomListItem?.let { roomListItem ->
- if (!roomListItem.isTimelineInitialized()) {
- roomListItem.initTimeline(eventFilters)
- }
- roomListItem.fullRoom()
- }
+ val fullRoom = cachedRoomListItem?.fullRoomWithTimeline(filter = eventFilters)
return if (cachedRoomListItem == null || fullRoom == null) {
Timber.d("No room cached for $roomId")
null
@@ -401,13 +399,12 @@ class RustMatrixClient(
}
override suspend fun getCacheSize(): Long {
- // Do not use client.userId since it can throw if client has been closed (during clear cache)
- return baseDirectory.getCacheSize(userID = sessionId.value)
+ return baseDirectory.getCacheSize()
}
override suspend fun clearCache() {
close()
- baseDirectory.deleteSessionDirectory(userID = sessionId.value, deleteCryptoDb = false)
+ baseDirectory.deleteSessionDirectory(deleteCryptoDb = false)
}
override suspend fun logout(ignoreSdkError: Boolean): String? = doLogout(
@@ -436,7 +433,7 @@ class RustMatrixClient(
}
}
close()
- baseDirectory.deleteSessionDirectory(userID = sessionId.value, deleteCryptoDb = true)
+ baseDirectory.deleteSessionDirectory(deleteCryptoDb = true)
if (removeSession) {
sessionStore.removeSession(sessionId.value)
}
@@ -482,12 +479,10 @@ class RustMatrixClient(
override fun roomMembershipObserver(): RoomMembershipObserver = roomMembershipObserver
private suspend fun File.getCacheSize(
- userID: String,
includeCryptoDb: Boolean = false,
): Long = withContext(sessionDispatcher) {
- // Rust sanitises the user ID replacing invalid characters with an _
- val sanitisedUserID = userID.replace(":", "_")
- val sessionDirectory = File(this@getCacheSize, sanitisedUserID)
+ val sessionDirectoryName = sessionDirectoryNameProvider.provides(sessionId)
+ val sessionDirectory = File(this@getCacheSize, sessionDirectoryName)
if (includeCryptoDb) {
sessionDirectory.getSizeOfFiles()
} else {
@@ -504,12 +499,10 @@ class RustMatrixClient(
}
private suspend fun File.deleteSessionDirectory(
- userID: String,
deleteCryptoDb: Boolean = false,
): Boolean = withContext(sessionDispatcher) {
- // Rust sanitises the user ID replacing invalid characters with an _
- val sanitisedUserID = userID.replace(":", "_")
- val sessionDirectory = File(this@deleteSessionDirectory, sanitisedUserID)
+ val sessionDirectoryName = sessionDirectoryNameProvider.provides(sessionId)
+ val sessionDirectory = File(this@deleteSessionDirectory, sessionDirectoryName)
if (deleteCryptoDb) {
// Delete the folder and all its content
sessionDirectory.deleteRecursively()
diff --git a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/room/MessageEventType.kt b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/room/MessageEventType.kt
index a117c1d313..bce74bc2db 100644
--- a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/room/MessageEventType.kt
+++ b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/room/MessageEventType.kt
@@ -31,11 +31,17 @@ fun MessageEventType.map(): MessageLikeEventType = when (this) {
MessageEventType.KEY_VERIFICATION_KEY -> MessageLikeEventType.KEY_VERIFICATION_KEY
MessageEventType.KEY_VERIFICATION_MAC -> MessageLikeEventType.KEY_VERIFICATION_MAC
MessageEventType.KEY_VERIFICATION_DONE -> MessageLikeEventType.KEY_VERIFICATION_DONE
- MessageEventType.REACTION_SENT -> MessageLikeEventType.REACTION_SENT
+ MessageEventType.REACTION -> MessageLikeEventType.REACTION
MessageEventType.ROOM_ENCRYPTED -> MessageLikeEventType.ROOM_ENCRYPTED
MessageEventType.ROOM_MESSAGE -> MessageLikeEventType.ROOM_MESSAGE
MessageEventType.ROOM_REDACTION -> MessageLikeEventType.ROOM_REDACTION
MessageEventType.STICKER -> MessageLikeEventType.STICKER
+ MessageEventType.POLL_END -> MessageLikeEventType.POLL_END
+ MessageEventType.POLL_RESPONSE -> MessageLikeEventType.POLL_RESPONSE
+ MessageEventType.POLL_START -> MessageLikeEventType.POLL_START
+ MessageEventType.UNSTABLE_POLL_END -> MessageLikeEventType.UNSTABLE_POLL_END
+ MessageEventType.UNSTABLE_POLL_RESPONSE -> MessageLikeEventType.UNSTABLE_POLL_RESPONSE
+ MessageEventType.UNSTABLE_POLL_START -> MessageLikeEventType.UNSTABLE_POLL_START
}
fun MessageLikeEventType.map(): MessageEventType = when (this) {
@@ -50,9 +56,15 @@ fun MessageLikeEventType.map(): MessageEventType = when (this) {
MessageLikeEventType.KEY_VERIFICATION_KEY -> MessageEventType.KEY_VERIFICATION_KEY
MessageLikeEventType.KEY_VERIFICATION_MAC -> MessageEventType.KEY_VERIFICATION_MAC
MessageLikeEventType.KEY_VERIFICATION_DONE -> MessageEventType.KEY_VERIFICATION_DONE
- MessageLikeEventType.REACTION_SENT -> MessageEventType.REACTION_SENT
+ MessageLikeEventType.REACTION -> MessageEventType.REACTION
MessageLikeEventType.ROOM_ENCRYPTED -> MessageEventType.ROOM_ENCRYPTED
MessageLikeEventType.ROOM_MESSAGE -> MessageEventType.ROOM_MESSAGE
MessageLikeEventType.ROOM_REDACTION -> MessageEventType.ROOM_REDACTION
MessageLikeEventType.STICKER -> MessageEventType.STICKER
+ MessageLikeEventType.POLL_END -> MessageEventType.POLL_END
+ MessageLikeEventType.POLL_RESPONSE -> MessageEventType.POLL_RESPONSE
+ MessageLikeEventType.POLL_START -> MessageEventType.POLL_START
+ MessageLikeEventType.UNSTABLE_POLL_END -> MessageEventType.UNSTABLE_POLL_END
+ MessageLikeEventType.UNSTABLE_POLL_RESPONSE -> MessageEventType.UNSTABLE_POLL_RESPONSE
+ MessageLikeEventType.UNSTABLE_POLL_START -> MessageEventType.UNSTABLE_POLL_START
}
diff --git a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/room/RoomContentForwarder.kt b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/room/RoomContentForwarder.kt
index 1d610422f9..1688763d4c 100644
--- a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/room/RoomContentForwarder.kt
+++ b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/room/RoomContentForwarder.kt
@@ -20,6 +20,7 @@ import io.element.android.libraries.core.coroutine.parallelMap
import io.element.android.libraries.matrix.api.core.EventId
import io.element.android.libraries.matrix.api.core.RoomId
import io.element.android.libraries.matrix.api.room.ForwardEventException
+import io.element.android.libraries.matrix.impl.roomlist.fullRoomWithTimeline
import io.element.android.libraries.matrix.impl.roomlist.roomOrNull
import io.element.android.libraries.matrix.impl.timeline.runWithTimelineListenerRegistered
import kotlinx.coroutines.CancellationException
@@ -50,7 +51,9 @@ class RoomContentForwarder(
) {
val content = fromTimeline.getTimelineEventContentByEventId(eventId.value)
val targetSlidingSyncRooms = toRoomIds.mapNotNull { roomId -> roomListService.roomOrNull(roomId.value) }
- val targetRooms = targetSlidingSyncRooms.mapNotNull { slidingSyncRoom -> slidingSyncRoom.use { it.fullRoom() } }
+ val targetRooms = targetSlidingSyncRooms.map { slidingSyncRoom ->
+ slidingSyncRoom.use { it.fullRoomWithTimeline(null) }
+ }
val failedForwardingTo = mutableSetOf()
targetRooms.parallelMap { room ->
room.use { targetRoom ->
diff --git a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/room/RustMatrixRoom.kt b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/room/RustMatrixRoom.kt
index bf67064f2a..e7d1761c05 100644
--- a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/room/RustMatrixRoom.kt
+++ b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/room/RustMatrixRoom.kt
@@ -41,6 +41,7 @@ import io.element.android.libraries.matrix.api.room.location.AssetType
import io.element.android.libraries.matrix.api.room.roomNotificationSettings
import io.element.android.libraries.matrix.api.room.tags.RoomNotableTags
import io.element.android.libraries.matrix.api.timeline.MatrixTimeline
+import io.element.android.libraries.matrix.api.timeline.ReceiptType
import io.element.android.libraries.matrix.api.widget.MatrixWidgetDriver
import io.element.android.libraries.matrix.api.widget.MatrixWidgetSettings
import io.element.android.libraries.matrix.impl.core.toProgressWatcher
@@ -53,6 +54,7 @@ import io.element.android.libraries.matrix.impl.room.location.toInner
import io.element.android.libraries.matrix.impl.room.member.RoomMemberListFetcher
import io.element.android.libraries.matrix.impl.room.tags.map
import io.element.android.libraries.matrix.impl.timeline.RustMatrixTimeline
+import io.element.android.libraries.matrix.impl.timeline.toRustReceiptType
import io.element.android.libraries.matrix.impl.util.mxCallbackFlow
import io.element.android.libraries.matrix.impl.widget.RustWidgetDriver
import io.element.android.libraries.matrix.impl.widget.generateWidgetWebViewUrl
@@ -74,6 +76,7 @@ import org.matrix.rustcomponents.sdk.RoomListItem
import org.matrix.rustcomponents.sdk.RoomMessageEventContentWithoutRelation
import org.matrix.rustcomponents.sdk.RoomNotableTagsListener
import org.matrix.rustcomponents.sdk.SendAttachmentJoinHandle
+import org.matrix.rustcomponents.sdk.TypingNotificationsListener
import org.matrix.rustcomponents.sdk.WidgetCapabilities
import org.matrix.rustcomponents.sdk.WidgetCapabilitiesProvider
import org.matrix.rustcomponents.sdk.messageEventContentFromHtml
@@ -115,6 +118,7 @@ class RustMatrixRoom(
})
}
+
override val notableTagsFlow: Flow = mxCallbackFlow {
innerRoom.subscribeToNotableTags(object : RoomNotableTagsListener {
override fun call(notableTags: RustRoomNotableTags) {
@@ -123,6 +127,22 @@ class RustMatrixRoom(
})
}
+ override val roomTypingMembersFlow: Flow> = mxCallbackFlow {
+ launch {
+ val initial = emptyList()
+ channel.trySend(initial)
+ }
+ innerRoom.subscribeToTypingNotifications(object : TypingNotificationsListener {
+ override fun call(typingUserIds: List) {
+ channel.trySend(
+ typingUserIds
+ .filter { it != sessionData.userId }
+ .map(::UserId)
+ )
+ }
+ })
+ }
+
// Create a dispatcher for all room methods...
private val roomDispatcher = coroutineDispatchers.io.limitedParallelism(32)
@@ -441,6 +461,22 @@ class RustMatrixRoom(
}
}
+ override suspend fun markAsRead(receiptType: ReceiptType?): Result = withContext(roomDispatcher) {
+ runCatching {
+ if (receiptType != null) {
+ innerRoom.markAsReadAndSendReadReceipt(receiptType.toRustReceiptType())
+ } else {
+ innerRoom.markAsRead()
+ }
+ }
+ }
+
+ override suspend fun markAsUnread(): Result = withContext(roomDispatcher) {
+ runCatching {
+ innerRoom.markAsUnread()
+ }
+ }
+
override suspend fun sendLocation(
body: String,
geoUri: String,
diff --git a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/roomlist/RoomListFactory.kt b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/roomlist/RoomListFactory.kt
index c8d4dfd507..f0d9c7e2a4 100644
--- a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/roomlist/RoomListFactory.kt
+++ b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/roomlist/RoomListFactory.kt
@@ -18,6 +18,7 @@ package io.element.android.libraries.matrix.impl.roomlist
import io.element.android.libraries.matrix.api.roomlist.DynamicRoomList
import io.element.android.libraries.matrix.api.roomlist.RoomList
+import io.element.android.libraries.matrix.api.roomlist.RoomListFilter
import io.element.android.libraries.matrix.api.roomlist.RoomSummary
import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.CoroutineScope
@@ -28,7 +29,6 @@ import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.launch
-import org.matrix.rustcomponents.sdk.RoomListEntriesDynamicFilterKind
import org.matrix.rustcomponents.sdk.RoomListLoadingState
import org.matrix.rustcomponents.sdk.RoomList as InnerRoomList
import org.matrix.rustcomponents.sdk.RoomListService as InnerRoomListService
@@ -44,7 +44,7 @@ internal class RoomListFactory(
*/
fun createRoomList(
pageSize: Int,
- initialFilter: DynamicRoomList.Filter = DynamicRoomList.Filter.All,
+ initialFilter: RoomListFilter = RoomListFilter.all(),
innerProvider: suspend () -> InnerRoomList
): DynamicRoomList {
val loadingStateFlow: MutableStateFlow = MutableStateFlow(RoomList.LoadingState.NotLoaded)
@@ -91,7 +91,7 @@ internal class RoomListFactory(
private class RustDynamicRoomList(
override val summaries: MutableStateFlow>,
override val loadingState: MutableStateFlow,
- override val currentFilter: MutableStateFlow,
+ override val currentFilter: MutableStateFlow,
override val loadedPages: MutableStateFlow,
private val dynamicEvents: MutableSharedFlow,
private val processor: RoomSummaryListProcessor,
@@ -101,7 +101,7 @@ private class RustDynamicRoomList(
processor.rebuildRoomSummaries()
}
- override suspend fun updateFilter(filter: DynamicRoomList.Filter) {
+ override suspend fun updateFilter(filter: RoomListFilter) {
currentFilter.emit(filter)
val filterEvent = RoomListDynamicEvents.SetFilter(filter.toRustFilter())
dynamicEvents.emit(filterEvent)
@@ -124,12 +124,3 @@ private fun RoomListLoadingState.toLoadingState(): RoomList.LoadingState {
RoomListLoadingState.NotLoaded -> RoomList.LoadingState.NotLoaded
}
}
-
-private fun DynamicRoomList.Filter.toRustFilter(): RoomListEntriesDynamicFilterKind {
- return when (this) {
- DynamicRoomList.Filter.All -> RoomListEntriesDynamicFilterKind.All
- is DynamicRoomList.Filter.NormalizedMatchRoomName -> RoomListEntriesDynamicFilterKind.NormalizedMatchRoomName(this.pattern)
- DynamicRoomList.Filter.None -> RoomListEntriesDynamicFilterKind.None
- DynamicRoomList.Filter.AllNonLeft -> RoomListEntriesDynamicFilterKind.AllNonLeft
- }
-}
diff --git a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/roomlist/RoomListFilter.kt b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/roomlist/RoomListFilter.kt
new file mode 100644
index 0000000000..c28da59ea4
--- /dev/null
+++ b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/roomlist/RoomListFilter.kt
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2024 New Vector Ltd
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package io.element.android.libraries.matrix.impl.roomlist
+
+import io.element.android.libraries.matrix.api.roomlist.RoomListFilter
+import org.matrix.rustcomponents.sdk.RoomListEntriesDynamicFilterKind
+import org.matrix.rustcomponents.sdk.RoomListFilterCategory
+
+fun RoomListFilter.toRustFilter(): RoomListEntriesDynamicFilterKind {
+ return when (this) {
+ is RoomListFilter.All -> RoomListEntriesDynamicFilterKind.All(filters.map { it.toRustFilter() })
+ is RoomListFilter.Any -> RoomListEntriesDynamicFilterKind.Any(filters.map { it.toRustFilter() })
+ RoomListFilter.Category.Group -> RoomListEntriesDynamicFilterKind.Category(RoomListFilterCategory.GROUP)
+ RoomListFilter.Category.People -> RoomListEntriesDynamicFilterKind.Category(RoomListFilterCategory.PEOPLE)
+ is RoomListFilter.FuzzyMatchRoomName -> RoomListEntriesDynamicFilterKind.FuzzyMatchRoomName(pattern)
+ RoomListFilter.NonLeft -> RoomListEntriesDynamicFilterKind.NonLeft
+ RoomListFilter.None -> RoomListEntriesDynamicFilterKind.None
+ is RoomListFilter.NormalizedMatchRoomName -> RoomListEntriesDynamicFilterKind.NormalizedMatchRoomName(pattern)
+ RoomListFilter.Unread -> RoomListEntriesDynamicFilterKind.Unread
+ }
+}
diff --git a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/roomlist/RoomListItemExtensions.kt b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/roomlist/RoomListItemExtensions.kt
new file mode 100644
index 0000000000..24f292b456
--- /dev/null
+++ b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/roomlist/RoomListItemExtensions.kt
@@ -0,0 +1,29 @@
+/*
+ * Copyright (c) 2024 New Vector Ltd
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package io.element.android.libraries.matrix.impl.roomlist
+
+import org.matrix.rustcomponents.sdk.Room
+import org.matrix.rustcomponents.sdk.RoomListItem
+import org.matrix.rustcomponents.sdk.TimelineEventTypeFilter
+
+/** Returns a `Room` with an initialized timeline using the given [filter]. */
+suspend fun RoomListItem.fullRoomWithTimeline(filter: TimelineEventTypeFilter? = null): Room {
+ if (!isTimelineInitialized()) {
+ initTimeline(filter)
+ }
+ return fullRoom()
+}
diff --git a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/roomlist/RoomSummaryDetailsFactory.kt b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/roomlist/RoomSummaryDetailsFactory.kt
index 1b3e900f17..cd3c86871b 100644
--- a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/roomlist/RoomSummaryDetailsFactory.kt
+++ b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/roomlist/RoomSummaryDetailsFactory.kt
@@ -38,6 +38,7 @@ class RoomSummaryDetailsFactory(private val roomMessageFactory: RoomMessageFacto
numUnreadMentions = roomInfo.numUnreadMentions.toInt(),
numUnreadMessages = roomInfo.numUnreadMessages.toInt(),
numUnreadNotifications = roomInfo.numUnreadNotifications.toInt(),
+ isMarkedUnread = roomInfo.isMarkedUnread,
lastMessage = latestRoomMessage,
inviter = roomInfo.inviter?.let(RoomMemberMapper::map),
userDefinedNotificationMode = roomInfo.userDefinedNotificationMode?.let(RoomNotificationSettingsMapper::mapMode),
diff --git a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/roomlist/RustRoomListService.kt b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/roomlist/RustRoomListService.kt
index 77d3a4e1fe..4fef34b571 100644
--- a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/roomlist/RustRoomListService.kt
+++ b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/roomlist/RustRoomListService.kt
@@ -18,6 +18,7 @@ package io.element.android.libraries.matrix.impl.roomlist
import io.element.android.libraries.matrix.api.roomlist.DynamicRoomList
import io.element.android.libraries.matrix.api.roomlist.RoomList
+import io.element.android.libraries.matrix.api.roomlist.RoomListFilter
import io.element.android.libraries.matrix.api.roomlist.RoomListService
import io.element.android.libraries.matrix.api.roomlist.loadAllIncrementally
import kotlinx.coroutines.CoroutineScope
@@ -45,7 +46,7 @@ internal class RustRoomListService(
) : RoomListService {
override val allRooms: DynamicRoomList = roomListFactory.createRoomList(
pageSize = DEFAULT_PAGE_SIZE,
- initialFilter = DynamicRoomList.Filter.AllNonLeft,
+ initialFilter = RoomListFilter.all(RoomListFilter.NonLeft),
) {
innerRoomListService.allRooms()
}
diff --git a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/timeline/RustMatrixTimeline.kt b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/timeline/RustMatrixTimeline.kt
index 7b1e7d0500..0f8da55a75 100644
--- a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/timeline/RustMatrixTimeline.kt
+++ b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/timeline/RustMatrixTimeline.kt
@@ -28,7 +28,6 @@ import io.element.android.libraries.matrix.impl.timeline.item.event.EventTimelin
import io.element.android.libraries.matrix.impl.timeline.item.event.TimelineEventContentMapper
import io.element.android.libraries.matrix.impl.timeline.item.virtual.VirtualTimelineItemMapper
import io.element.android.libraries.matrix.impl.timeline.postprocessor.DmBeginningTimelineProcessor
-import io.element.android.libraries.matrix.impl.timeline.postprocessor.FilterHiddenStateEventsProcessor
import io.element.android.libraries.matrix.impl.timeline.postprocessor.TimelineEncryptedHistoryPostProcessor
import kotlinx.coroutines.CompletableDeferred
import kotlinx.coroutines.CoroutineDispatcher
@@ -84,8 +83,6 @@ class RustMatrixTimeline(
dispatcher = dispatcher,
)
- private val filterHiddenStateEventsProcessor = FilterHiddenStateEventsProcessor()
-
private val dmBeginningTimelineProcessor = DmBeginningTimelineProcessor()
private val timelineItemFactory = MatrixTimelineItemMapper(
@@ -109,7 +106,6 @@ class RustMatrixTimeline(
@OptIn(ExperimentalCoroutinesApi::class)
override val timelineItems: Flow> = _timelineItems
.mapLatest { items -> encryptedHistoryPostProcessor.process(items) }
- .mapLatest { items -> filterHiddenStateEventsProcessor.process(items) }
.mapLatest { items ->
dmBeginningTimelineProcessor.process(
items = items,
diff --git a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/timeline/postprocessor/FilterHiddenStateEventsProcessor.kt b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/timeline/postprocessor/FilterHiddenStateEventsProcessor.kt
deleted file mode 100644
index c54221d84e..0000000000
--- a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/timeline/postprocessor/FilterHiddenStateEventsProcessor.kt
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * Copyright (c) 2024 New Vector Ltd
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package io.element.android.libraries.matrix.impl.timeline.postprocessor
-
-import io.element.android.libraries.matrix.api.timeline.MatrixTimelineItem
-import io.element.android.libraries.matrix.api.timeline.item.event.StateContent
-
-/**
- * This class is used to filter out 'hidden' state events from the timeline.
- */
-class FilterHiddenStateEventsProcessor {
- fun process(items: List): List {
- return items.filter { item ->
- when (item) {
- is MatrixTimelineItem.Event -> {
- when (val content = item.event.content) {
- // If it's a state event, make sure it's visible
- is StateContent -> content.isVisibleInTimeline()
- // We can display any other event
- else -> true
- }
- }
- is MatrixTimelineItem.Virtual -> true
- is MatrixTimelineItem.Other -> true
- }
- }
- }
-}
diff --git a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/util/SessionDirectoryNameProvider.kt b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/util/SessionDirectoryNameProvider.kt
new file mode 100644
index 0000000000..de9d6c1520
--- /dev/null
+++ b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/util/SessionDirectoryNameProvider.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.libraries.matrix.impl.util
+
+import io.element.android.libraries.matrix.api.core.SessionId
+
+class SessionDirectoryNameProvider {
+ // Rust sanitises the user ID replacing invalid characters with an _
+ fun provides(sessionId: SessionId): String {
+ return sessionId.value.replace(":", "_")
+ }
+}
diff --git a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/widget/DefaultCallWidgetSettingsProvider.kt b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/widget/DefaultCallWidgetSettingsProvider.kt
index a337adff17..44c73ae9d3 100644
--- a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/widget/DefaultCallWidgetSettingsProvider.kt
+++ b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/widget/DefaultCallWidgetSettingsProvider.kt
@@ -27,7 +27,7 @@ import javax.inject.Inject
@ContributesBinding(AppScope::class)
class DefaultCallWidgetSettingsProvider @Inject constructor() : CallWidgetSettingsProvider {
- override fun provide(baseUrl: String, widgetId: String): MatrixWidgetSettings {
+ override fun provide(baseUrl: String, widgetId: String, encrypted: Boolean): MatrixWidgetSettings {
val options = VirtualElementCallWidgetOptions(
elementCallUrl = baseUrl,
widgetId = widgetId,
@@ -40,7 +40,7 @@ class DefaultCallWidgetSettingsProvider @Inject constructor() : CallWidgetSettin
confineToRoom = true,
font = null,
analyticsId = null,
- encryption = EncryptionSystem.PerParticipantKeys,
+ encryption = if (encrypted) EncryptionSystem.PerParticipantKeys else EncryptionSystem.Unencrypted,
)
val rustWidgetSettings = newVirtualElementCallWidget(options)
return MatrixWidgetSettings.fromRustWidgetSettings(rustWidgetSettings)
diff --git a/libraries/matrix/impl/src/test/kotlin/io/element/android/libraries/matrix/impl/timeline/postprocessor/FilterHiddenStateEventsProcessorTest.kt b/libraries/matrix/impl/src/test/kotlin/io/element/android/libraries/matrix/impl/timeline/postprocessor/FilterHiddenStateEventsProcessorTest.kt
deleted file mode 100644
index 0532d1b762..0000000000
--- a/libraries/matrix/impl/src/test/kotlin/io/element/android/libraries/matrix/impl/timeline/postprocessor/FilterHiddenStateEventsProcessorTest.kt
+++ /dev/null
@@ -1,77 +0,0 @@
-/*
- * Copyright (c) 2024 New Vector Ltd
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package io.element.android.libraries.matrix.impl.timeline.postprocessor
-
-import com.google.common.truth.Truth.assertThat
-import io.element.android.libraries.matrix.api.timeline.MatrixTimelineItem
-import io.element.android.libraries.matrix.api.timeline.item.event.OtherState
-import io.element.android.libraries.matrix.api.timeline.item.event.StateContent
-import io.element.android.libraries.matrix.api.timeline.item.virtual.VirtualTimelineItem
-import io.element.android.libraries.matrix.test.timeline.anEventTimelineItem
-import org.junit.Test
-
-class FilterHiddenStateEventsProcessorTest {
- @Test
- fun test() {
- val items = listOf(
- // These are visible because they're not state events
- MatrixTimelineItem.Other,
- MatrixTimelineItem.Virtual("virtual", VirtualTimelineItem.ReadMarker),
- MatrixTimelineItem.Event("event", anEventTimelineItem()),
- // These are visible state events
- MatrixTimelineItem.Event("m.room.avatar", anEventTimelineItem(content = StateContent("", OtherState.RoomAvatar("")))),
- MatrixTimelineItem.Event("m.room.create", anEventTimelineItem(content = StateContent("", OtherState.RoomCreate))),
- MatrixTimelineItem.Event("m.room.encrypted", anEventTimelineItem(content = StateContent("", OtherState.RoomEncryption))),
- MatrixTimelineItem.Event("m.room.name", anEventTimelineItem(content = StateContent("", OtherState.RoomName("")))),
- MatrixTimelineItem.Event("m.room.third_party_invite", anEventTimelineItem(content = StateContent("", OtherState.RoomThirdPartyInvite("")))),
- MatrixTimelineItem.Event("m.room.topic", anEventTimelineItem(content = StateContent("", OtherState.RoomTopic("")))),
- MatrixTimelineItem.Event("m.room.custom", anEventTimelineItem(content = StateContent("", OtherState.Custom("")))),
- // These ones are hidden
- MatrixTimelineItem.Event("m.room.aliases", anEventTimelineItem(content = StateContent("", OtherState.RoomAliases))),
- MatrixTimelineItem.Event("m.room.canonical_alias", anEventTimelineItem(content = StateContent("", OtherState.RoomCanonicalAlias))),
- MatrixTimelineItem.Event("m.room.guest_access", anEventTimelineItem(content = StateContent("", OtherState.RoomGuestAccess))),
- MatrixTimelineItem.Event("m.room.history_visibility", anEventTimelineItem(content = StateContent("", OtherState.RoomHistoryVisibility))),
- MatrixTimelineItem.Event("m.room.join_rules", anEventTimelineItem(content = StateContent("", OtherState.RoomJoinRules))),
- MatrixTimelineItem.Event("m.room.pinned_events", anEventTimelineItem(content = StateContent("", OtherState.RoomPinnedEvents))),
- MatrixTimelineItem.Event("m.room.power_levels", anEventTimelineItem(content = StateContent("", OtherState.RoomPowerLevels))),
- MatrixTimelineItem.Event("m.room.server_acl", anEventTimelineItem(content = StateContent("", OtherState.RoomServerAcl))),
- MatrixTimelineItem.Event("m.room.tombstone", anEventTimelineItem(content = StateContent("", OtherState.RoomTombstone))),
- MatrixTimelineItem.Event("m.space.child", anEventTimelineItem(content = StateContent("", OtherState.SpaceChild))),
- MatrixTimelineItem.Event("m.space.parent", anEventTimelineItem(content = StateContent("", OtherState.SpaceParent))),
- MatrixTimelineItem.Event("m.room.policy.rule.room", anEventTimelineItem(content = StateContent("", OtherState.PolicyRuleRoom))),
- MatrixTimelineItem.Event("m.room.policy.rule.server", anEventTimelineItem(content = StateContent("", OtherState.PolicyRuleServer))),
- MatrixTimelineItem.Event("m.room.policy.rule.user", anEventTimelineItem(content = StateContent("", OtherState.PolicyRuleUser))),
- )
-
- val expected = listOf(
- MatrixTimelineItem.Other,
- MatrixTimelineItem.Virtual("virtual", VirtualTimelineItem.ReadMarker),
- MatrixTimelineItem.Event("event", anEventTimelineItem()),
- MatrixTimelineItem.Event("m.room.avatar", anEventTimelineItem(content = StateContent("", OtherState.RoomAvatar("")))),
- MatrixTimelineItem.Event("m.room.create", anEventTimelineItem(content = StateContent("", OtherState.RoomCreate))),
- MatrixTimelineItem.Event("m.room.encrypted", anEventTimelineItem(content = StateContent("", OtherState.RoomEncryption))),
- MatrixTimelineItem.Event("m.room.name", anEventTimelineItem(content = StateContent("", OtherState.RoomName("")))),
- MatrixTimelineItem.Event("m.room.third_party_invite", anEventTimelineItem(content = StateContent("", OtherState.RoomThirdPartyInvite("")))),
- MatrixTimelineItem.Event("m.room.topic", anEventTimelineItem(content = StateContent("", OtherState.RoomTopic("")))),
- MatrixTimelineItem.Event("m.room.custom", anEventTimelineItem(content = StateContent("", OtherState.Custom("")))),
- )
-
- val processor = FilterHiddenStateEventsProcessor()
-
- assertThat(processor.process(items)).isEqualTo(expected)
- }
-}
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 b0b77761d8..9c10783e0f 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
@@ -42,6 +42,7 @@ import io.element.android.libraries.matrix.api.room.StateEventType
import io.element.android.libraries.matrix.api.room.location.AssetType
import io.element.android.libraries.matrix.api.room.tags.RoomNotableTags
import io.element.android.libraries.matrix.api.timeline.MatrixTimeline
+import io.element.android.libraries.matrix.api.timeline.ReceiptType
import io.element.android.libraries.matrix.api.timeline.item.event.EventTimelineItem
import io.element.android.libraries.matrix.api.widget.MatrixWidgetDriver
import io.element.android.libraries.matrix.api.widget.MatrixWidgetSettings
@@ -174,6 +175,9 @@ class FakeMatrixRoom(
private val _notableTagsFlow: MutableStateFlow = MutableStateFlow(aRoomNotableTags())
override val notableTagsFlow: Flow = _notableTagsFlow
+ private val _roomTypingMembersFlow: MutableSharedFlow> = MutableSharedFlow(replay = 1)
+ override val roomTypingMembersFlow: Flow> = _roomTypingMembersFlow
+
override val membersStateFlow: MutableStateFlow = MutableStateFlow(MatrixRoomMembersState.Unknown)
override val roomNotificationSettingsStateFlow: MutableStateFlow =
@@ -393,6 +397,22 @@ class FakeMatrixRoom(
}
}
+
+ val markAsReadCalls = mutableListOf()
+
+ override suspend fun markAsRead(receiptType: ReceiptType?): Result {
+ markAsReadCalls.add(receiptType)
+ return Result.success(Unit)
+ }
+
+ var markAsUnreadReadCallCount = 0
+ private set
+
+ override suspend fun markAsUnread(): Result {
+ markAsUnreadReadCallCount++
+ return Result.success(Unit)
+ }
+
override suspend fun sendLocation(
body: String,
geoUri: String,
@@ -597,6 +617,10 @@ class FakeMatrixRoom(
fun givenRoomInfo(roomInfo: MatrixRoomInfo) {
_roomInfoFlow.tryEmit(roomInfo)
}
+
+ fun givenRoomTypingMembers(typingMembers: List) {
+ _roomTypingMembersFlow.tryEmit(typingMembers)
+ }
}
data class SendLocationInvocation(
diff --git a/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/room/RoomSummaryFixture.kt b/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/room/RoomSummaryFixture.kt
index 2bd04894c0..4871dcb402 100644
--- a/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/room/RoomSummaryFixture.kt
+++ b/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/room/RoomSummaryFixture.kt
@@ -37,8 +37,8 @@ fun aRoomSummaryFilled(
isDirect: Boolean = false,
avatarUrl: String? = null,
lastMessage: RoomMessage? = aRoomMessage(),
- numUnreadMentions: Int = 1,
- numUnreadMessages: Int = 2,
+ numUnreadMentions: Int = 0,
+ numUnreadMessages: Int = 0,
notificationMode: RoomNotificationMode? = null,
) = RoomSummary.Filled(
aRoomSummaryDetails(
@@ -62,6 +62,7 @@ fun aRoomSummaryDetails(
numUnreadMentions: Int = 0,
numUnreadMessages: Int = 0,
numUnreadNotifications: Int = 0,
+ isMarkedUnread: Boolean = false,
notificationMode: RoomNotificationMode? = null,
inviter: RoomMember? = null,
canonicalAlias: String? = null,
@@ -76,6 +77,7 @@ fun aRoomSummaryDetails(
numUnreadMentions = numUnreadMentions,
numUnreadMessages = numUnreadMessages,
numUnreadNotifications = numUnreadNotifications,
+ isMarkedUnread = isMarkedUnread,
userDefinedNotificationMode = notificationMode,
inviter = inviter,
canonicalAlias = canonicalAlias,
diff --git a/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/roomlist/FakeRoomListService.kt b/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/roomlist/FakeRoomListService.kt
index e998a35ecf..7540d6cee8 100644
--- a/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/roomlist/FakeRoomListService.kt
+++ b/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/roomlist/FakeRoomListService.kt
@@ -18,6 +18,7 @@ package io.element.android.libraries.matrix.test.roomlist
import io.element.android.libraries.matrix.api.roomlist.DynamicRoomList
import io.element.android.libraries.matrix.api.roomlist.RoomList
+import io.element.android.libraries.matrix.api.roomlist.RoomListFilter
import io.element.android.libraries.matrix.api.roomlist.RoomListService
import io.element.android.libraries.matrix.api.roomlist.RoomSummary
import kotlinx.coroutines.flow.MutableStateFlow
@@ -61,13 +62,13 @@ class FakeRoomListService : RoomListService {
override val allRooms: DynamicRoomList = SimplePagedRoomList(
allRoomSummariesFlow,
allRoomsLoadingStateFlow,
- MutableStateFlow(DynamicRoomList.Filter.None)
+ MutableStateFlow(RoomListFilter.all())
)
override val invites: RoomList = SimplePagedRoomList(
inviteRoomSummariesFlow,
inviteRoomsLoadingStateFlow,
- MutableStateFlow(DynamicRoomList.Filter.None)
+ MutableStateFlow(RoomListFilter.all())
)
override fun updateAllRoomsVisibleRange(range: IntRange) {
diff --git a/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/roomlist/SimplePagedRoomList.kt b/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/roomlist/SimplePagedRoomList.kt
index e5f70b1b30..4f1b07ce69 100644
--- a/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/roomlist/SimplePagedRoomList.kt
+++ b/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/roomlist/SimplePagedRoomList.kt
@@ -18,6 +18,7 @@ package io.element.android.libraries.matrix.test.roomlist
import io.element.android.libraries.matrix.api.roomlist.DynamicRoomList
import io.element.android.libraries.matrix.api.roomlist.RoomList
+import io.element.android.libraries.matrix.api.roomlist.RoomListFilter
import io.element.android.libraries.matrix.api.roomlist.RoomSummary
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
@@ -26,7 +27,7 @@ import kotlinx.coroutines.flow.getAndUpdate
data class SimplePagedRoomList(
override val summaries: StateFlow>,
override val loadingState: StateFlow,
- override val currentFilter: MutableStateFlow
+ override val currentFilter: MutableStateFlow
) : DynamicRoomList {
override val pageSize: Int = Int.MAX_VALUE
override val loadedPages = MutableStateFlow(1)
@@ -40,7 +41,7 @@ data class SimplePagedRoomList(
loadedPages.emit(1)
}
- override suspend fun updateFilter(filter: DynamicRoomList.Filter) {
+ override suspend fun updateFilter(filter: RoomListFilter) {
currentFilter.emit(filter)
}
diff --git a/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/widget/FakeCallWidgetSettingsProvider.kt b/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/widget/FakeCallWidgetSettingsProvider.kt
index d2be886ea6..ca198129f6 100644
--- a/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/widget/FakeCallWidgetSettingsProvider.kt
+++ b/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/widget/FakeCallWidgetSettingsProvider.kt
@@ -24,7 +24,7 @@ class FakeCallWidgetSettingsProvider(
) : CallWidgetSettingsProvider {
val providedBaseUrls = mutableListOf()
- override fun provide(baseUrl: String, widgetId: String): MatrixWidgetSettings {
+ override fun provide(baseUrl: String, widgetId: String, encrypted: Boolean): MatrixWidgetSettings {
providedBaseUrls += baseUrl
return provideFn(baseUrl, widgetId)
}
diff --git a/libraries/matrixui/src/main/kotlin/io/element/android/libraries/matrix/ui/components/SelectedRoom.kt b/libraries/matrixui/src/main/kotlin/io/element/android/libraries/matrix/ui/components/SelectedRoom.kt
index a4d9a479c2..bebe82dca2 100644
--- a/libraries/matrixui/src/main/kotlin/io/element/android/libraries/matrix/ui/components/SelectedRoom.kt
+++ b/libraries/matrixui/src/main/kotlin/io/element/android/libraries/matrix/ui/components/SelectedRoom.kt
@@ -116,6 +116,7 @@ fun aRoomSummaryDetails(
numUnreadMentions: Int = 0,
numUnreadMessages: Int = 0,
numUnreadNotifications: Int = 0,
+ isMarkedUnread: Boolean = false,
) = RoomSummaryDetails(
roomId = roomId,
name = name,
@@ -130,4 +131,5 @@ fun aRoomSummaryDetails(
numUnreadMentions = numUnreadMentions,
numUnreadMessages = numUnreadMessages,
numUnreadNotifications = numUnreadNotifications,
+ isMarkedUnread = isMarkedUnread,
)
diff --git a/libraries/mediaviewer/api/src/main/kotlin/io/element/android/libraries/mediaviewer/api/local/pdf/PdfViewer.kt b/libraries/mediaviewer/api/src/main/kotlin/io/element/android/libraries/mediaviewer/api/local/pdf/PdfViewer.kt
index 0f00e3faa6..a4b523d45d 100644
--- a/libraries/mediaviewer/api/src/main/kotlin/io/element/android/libraries/mediaviewer/api/local/pdf/PdfViewer.kt
+++ b/libraries/mediaviewer/api/src/main/kotlin/io/element/android/libraries/mediaviewer/api/local/pdf/PdfViewer.kt
@@ -86,7 +86,6 @@ private fun PdfPagesView(
@Composable
private fun PdfPageView(
pdfPage: PdfPage,
- modifier: Modifier = Modifier,
) {
val pdfPageState by pdfPage.stateFlow.collectAsState()
DisposableEffect(pdfPage) {
@@ -101,12 +100,12 @@ private fun PdfPageView(
bitmap = state.bitmap.asImageBitmap(),
contentDescription = stringResource(id = CommonStrings.a11y_page_n, pdfPage.pageIndex),
contentScale = ContentScale.FillWidth,
- modifier = modifier.fillMaxWidth()
+ modifier = Modifier.fillMaxWidth()
)
}
is PdfPage.State.Loading -> {
Box(
- modifier = modifier
+ modifier = Modifier
.fillMaxWidth()
.height(state.height.toDp())
.background(color = Color.White)
diff --git a/libraries/mediaviewer/api/src/main/kotlin/io/element/android/libraries/mediaviewer/api/viewer/MediaViewerView.kt b/libraries/mediaviewer/api/src/main/kotlin/io/element/android/libraries/mediaviewer/api/viewer/MediaViewerView.kt
index 2d5412cc25..2e4497e5bf 100644
--- a/libraries/mediaviewer/api/src/main/kotlin/io/element/android/libraries/mediaviewer/api/viewer/MediaViewerView.kt
+++ b/libraries/mediaviewer/api/src/main/kotlin/io/element/android/libraries/mediaviewer/api/viewer/MediaViewerView.kt
@@ -259,10 +259,8 @@ private fun ErrorView(
errorMessage: String,
onRetry: () -> Unit,
onDismiss: () -> Unit,
- modifier: Modifier = Modifier,
) {
RetryDialog(
- modifier = modifier,
content = errorMessage,
onRetry = onRetry,
onDismiss = onDismiss
diff --git a/libraries/permissions/api/src/main/res/values-be/translations.xml b/libraries/permissions/api/src/main/res/values-be/translations.xml
new file mode 100644
index 0000000000..5a489ba844
--- /dev/null
+++ b/libraries/permissions/api/src/main/res/values-be/translations.xml
@@ -0,0 +1,7 @@
+
+
+ "Каб дазволіць праграме выкарыстоўваць камеру, дайце дазвол у наладах сістэмы."
+ "Калі ласка, дайце дазвол у наладах сістэмы."
+ "Каб дазволіць праграме выкарыстоўваць мікрафон, дайце дазвол у наладах сістэмы."
+ "Каб дазволіць праграме паказваць апавяшчэнні, дайце дазвол у наладах сістэмы."
+
diff --git a/libraries/preferences/api/src/main/kotlin/io/element/android/features/preferences/api/store/SessionPreferencesStore.kt b/libraries/preferences/api/src/main/kotlin/io/element/android/features/preferences/api/store/SessionPreferencesStore.kt
index 0174d8d1eb..948e9acb75 100644
--- a/libraries/preferences/api/src/main/kotlin/io/element/android/features/preferences/api/store/SessionPreferencesStore.kt
+++ b/libraries/preferences/api/src/main/kotlin/io/element/android/features/preferences/api/store/SessionPreferencesStore.kt
@@ -19,8 +19,20 @@ package io.element.android.features.preferences.api.store
import kotlinx.coroutines.flow.Flow
interface SessionPreferencesStore {
+ suspend fun setSharePresence(enabled: Boolean)
+ fun isSharePresenceEnabled(): Flow
+
suspend fun setSendPublicReadReceipts(enabled: Boolean)
fun isSendPublicReadReceiptsEnabled(): Flow
+ suspend fun setRenderReadReceipts(enabled: Boolean)
+ fun isRenderReadReceiptsEnabled(): Flow
+
+ suspend fun setSendTypingNotifications(enabled: Boolean)
+ fun isSendTypingNotificationsEnabled(): Flow
+
+ suspend fun setRenderTypingNotifications(enabled: Boolean)
+ fun isRenderTypingNotificationsEnabled(): Flow
+
suspend fun clear()
}
diff --git a/libraries/preferences/impl/src/main/kotlin/io/element/android/libraries/preferences/impl/store/DefaultSessionPreferencesStore.kt b/libraries/preferences/impl/src/main/kotlin/io/element/android/libraries/preferences/impl/store/DefaultSessionPreferencesStore.kt
index eb2fffb045..770ca699fe 100644
--- a/libraries/preferences/impl/src/main/kotlin/io/element/android/libraries/preferences/impl/store/DefaultSessionPreferencesStore.kt
+++ b/libraries/preferences/impl/src/main/kotlin/io/element/android/libraries/preferences/impl/store/DefaultSessionPreferencesStore.kt
@@ -29,7 +29,9 @@ import io.element.android.libraries.di.annotations.SessionCoroutineScope
import io.element.android.libraries.matrix.api.core.SessionId
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.first
import kotlinx.coroutines.flow.map
+import kotlinx.coroutines.runBlocking
import java.io.File
class DefaultSessionPreferencesStore(
@@ -43,13 +45,41 @@ class DefaultSessionPreferencesStore(
return context.preferencesDataStoreFile("session_${hashedUserId}_preferences")
}
}
+
+ private val sharePresenceKey = booleanPreferencesKey("sharePresence")
private val sendPublicReadReceiptsKey = booleanPreferencesKey("sendPublicReadReceipts")
+ private val renderReadReceiptsKey = booleanPreferencesKey("renderReadReceipts")
+ private val sendTypingNotificationsKey = booleanPreferencesKey("sendTypingNotifications")
+ private val renderTypingNotificationsKey = booleanPreferencesKey("renderTypingNotifications")
private val dataStoreFile = storeFile(context, sessionId)
private val store = PreferenceDataStoreFactory.create(scope = sessionCoroutineScope) { dataStoreFile }
+ override suspend fun setSharePresence(enabled: Boolean) {
+ update(sharePresenceKey, enabled)
+ // Also update all the other settings
+ setSendPublicReadReceipts(enabled)
+ setRenderReadReceipts(enabled)
+ setSendTypingNotifications(enabled)
+ setRenderTypingNotifications(enabled)
+ }
+
+ override fun isSharePresenceEnabled(): Flow {
+ // Migration, if sendPublicReadReceiptsKey was false, consider that sharing presence is false.
+ return get(sharePresenceKey) { runBlocking { isSendPublicReadReceiptsEnabled().first() } }
+ }
+
override suspend fun setSendPublicReadReceipts(enabled: Boolean) = update(sendPublicReadReceiptsKey, enabled)
- override fun isSendPublicReadReceiptsEnabled(): Flow = get(sendPublicReadReceiptsKey, true)
+ override fun isSendPublicReadReceiptsEnabled(): Flow = get(sendPublicReadReceiptsKey) { true }
+
+ override suspend fun setRenderReadReceipts(enabled: Boolean) = update(renderReadReceiptsKey, enabled)
+ override fun isRenderReadReceiptsEnabled(): Flow = get(renderReadReceiptsKey) { true }
+
+ override suspend fun setSendTypingNotifications(enabled: Boolean) = update(sendTypingNotificationsKey, enabled)
+ override fun isSendTypingNotificationsEnabled(): Flow = get(sendTypingNotificationsKey) { true }
+
+ override suspend fun setRenderTypingNotifications(enabled: Boolean) = update(renderTypingNotificationsKey, enabled)
+ override fun isRenderTypingNotificationsEnabled(): Flow = get(renderTypingNotificationsKey) { true }
override suspend fun clear() {
dataStoreFile.safeDelete()
@@ -59,7 +89,7 @@ class DefaultSessionPreferencesStore(
store.edit { prefs -> prefs[key] = value }
}
- private fun get(key: Preferences.Key, default: T): Flow {
- return store.data.map { prefs -> prefs[key] ?: default }
+ private fun get(key: Preferences.Key, default: () -> T): Flow {
+ return store.data.map { prefs -> prefs[key] ?: default() }
}
}
diff --git a/libraries/preferences/impl/src/main/kotlin/io/element/android/libraries/preferences/impl/store/DefaultSessionPreferencesStoreFactory.kt b/libraries/preferences/impl/src/main/kotlin/io/element/android/libraries/preferences/impl/store/DefaultSessionPreferencesStoreFactory.kt
index 84dcbac289..745dd42615 100644
--- a/libraries/preferences/impl/src/main/kotlin/io/element/android/libraries/preferences/impl/store/DefaultSessionPreferencesStoreFactory.kt
+++ b/libraries/preferences/impl/src/main/kotlin/io/element/android/libraries/preferences/impl/store/DefaultSessionPreferencesStoreFactory.kt
@@ -21,6 +21,8 @@ import io.element.android.libraries.di.AppScope
import io.element.android.libraries.di.ApplicationContext
import io.element.android.libraries.di.SingleIn
import io.element.android.libraries.matrix.api.core.SessionId
+import io.element.android.libraries.sessionstorage.api.observer.SessionListener
+import io.element.android.libraries.sessionstorage.api.observer.SessionObserver
import kotlinx.coroutines.CoroutineScope
import java.util.concurrent.ConcurrentHashMap
import javax.inject.Inject
@@ -28,9 +30,20 @@ import javax.inject.Inject
@SingleIn(AppScope::class)
class DefaultSessionPreferencesStoreFactory @Inject constructor(
@ApplicationContext private val context: Context,
+ sessionObserver: SessionObserver,
) {
private val cache = ConcurrentHashMap()
+ init {
+ sessionObserver.addListener(object : SessionListener {
+ override suspend fun onSessionCreated(userId: String) = Unit
+ override suspend fun onSessionDeleted(userId: String) {
+ val sessionPreferences = cache.remove(SessionId(userId))
+ sessionPreferences?.clear()
+ }
+ })
+ }
+
fun get(sessionId: SessionId, sessionCoroutineScope: CoroutineScope): DefaultSessionPreferencesStore = cache.getOrPut(sessionId) {
DefaultSessionPreferencesStore(context, sessionId, sessionCoroutineScope)
}
diff --git a/libraries/preferences/test/src/main/kotlin/io/element/android/libraries/featureflag/test/InMemorySessionPreferencesStore.kt b/libraries/preferences/test/src/main/kotlin/io/element/android/libraries/featureflag/test/InMemorySessionPreferencesStore.kt
index 1f6f7a6724..9e9fc7ba2a 100644
--- a/libraries/preferences/test/src/main/kotlin/io/element/android/libraries/featureflag/test/InMemorySessionPreferencesStore.kt
+++ b/libraries/preferences/test/src/main/kotlin/io/element/android/libraries/featureflag/test/InMemorySessionPreferencesStore.kt
@@ -21,19 +21,50 @@ import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableStateFlow
class InMemorySessionPreferencesStore(
+ isSharePresenceEnabled: Boolean = true,
isSendPublicReadReceiptsEnabled: Boolean = true,
+ isRenderReadReceiptsEnabled: Boolean = true,
+ isSendTypingNotificationsEnabled: Boolean = true,
+ isRenderTypingNotificationsEnabled: Boolean = true,
) : SessionPreferencesStore {
+ private val isSharePresenceEnabled = MutableStateFlow(isSharePresenceEnabled)
private val isSendPublicReadReceiptsEnabled = MutableStateFlow(isSendPublicReadReceiptsEnabled)
+ private val isRenderReadReceiptsEnabled = MutableStateFlow(isRenderReadReceiptsEnabled)
+ private val isSendTypingNotificationsEnabled = MutableStateFlow(isSendTypingNotificationsEnabled)
+ private val isRenderTypingNotificationsEnabled = MutableStateFlow(isRenderTypingNotificationsEnabled)
var clearCallCount = 0
private set
+ override suspend fun setSharePresence(enabled: Boolean) {
+ isSharePresenceEnabled.tryEmit(enabled)
+ }
+
+ override fun isSharePresenceEnabled(): Flow = isSharePresenceEnabled
+
override suspend fun setSendPublicReadReceipts(enabled: Boolean) {
isSendPublicReadReceiptsEnabled.tryEmit(enabled)
}
- override fun isSendPublicReadReceiptsEnabled(): Flow {
- return isSendPublicReadReceiptsEnabled
+
+ override fun isSendPublicReadReceiptsEnabled(): Flow = isSendPublicReadReceiptsEnabled
+
+ override suspend fun setRenderReadReceipts(enabled: Boolean) {
+ isRenderReadReceiptsEnabled.tryEmit(enabled)
}
+ override fun isRenderReadReceiptsEnabled(): Flow = isRenderReadReceiptsEnabled
+
+ override suspend fun setSendTypingNotifications(enabled: Boolean) {
+ isSendTypingNotificationsEnabled.tryEmit(enabled)
+ }
+
+ override fun isSendTypingNotificationsEnabled(): Flow = isSendTypingNotificationsEnabled
+
+ override suspend fun setRenderTypingNotifications(enabled: Boolean) {
+ isRenderTypingNotificationsEnabled.tryEmit(enabled)
+ }
+
+ override fun isRenderTypingNotificationsEnabled(): Flow = isRenderTypingNotificationsEnabled
+
override suspend fun clear() {
clearCallCount++
isSendPublicReadReceiptsEnabled.tryEmit(true)
diff --git a/libraries/push/impl/src/main/res/values-be/translations.xml b/libraries/push/impl/src/main/res/values-be/translations.xml
new file mode 100644
index 0000000000..bdeaf9b5f6
--- /dev/null
+++ b/libraries/push/impl/src/main/res/values-be/translations.xml
@@ -0,0 +1,58 @@
+
+
+ "Выклік"
+ "Праслухоўванне падзей"
+ "Шумныя апавяшчэнні"
+ "Ціхія апавяшчэнні"
+ "** Не атрымалася даслаць - калі ласка, адкрыйце пакой"
+ "Адхіліць"
+ "Запрасіў вас у чат"
+ "Згадаў вас: %1$s"
+ "Новыя паведамленні"
+ "Адрэагаваў на %1$s"
+ "Запрасіў вас далучыцца да пакоя"
+ "Я"
+ "Вы праглядаеце апавяшчэнне! Націсніце мяне!"
+ "%1$s: %2$s"
+ "%1$s: %2$s %3$s"
+ "%1$s і %2$s"
+ "%1$s у %2$s"
+ "%1$s у %2$s і %3$s"
+
+ - "%1$s: %2$d паведамленне"
+ - "%1$s: %2$d паведамленняў"
+ - "%1$s: %2$d паведамленняў"
+
+
+ - "%d апавяшчэнне"
+ - "%d апавяшчэнняў"
+ - "%d апавяшчэнняў"
+
+
+ - "%d запрашэнне"
+ - "%d запрашэнняў"
+ - "%d запрашэнняў"
+
+
+ - "%d новае паведамленне"
+ - "%d новых паведамленняў"
+ - "%d новых паведамленняў"
+
+
+ - "%d непрачытанае апавяшчэнне"
+ - "%d непрачытаных апавяшчэнняў"
+ - "%d непрачытаных апавяшчэнняў"
+
+
+ - "%d пакой"
+ - "%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 2b76d7b93e..22a0ba078c 100644
--- a/libraries/push/impl/src/main/res/values-cs/translations.xml
+++ b/libraries/push/impl/src/main/res/values-cs/translations.xml
@@ -5,13 +5,11 @@
"Hlasitá oznámení"
"Tichá oznámení"
"** Nepodařilo se odeslat - otevřete prosím místnost"
- "Vstoupit"
"Odmítnout"
"Vás pozval(a) do chatu"
"Zmínili vás: %1$s"
"Nové zprávy"
"Reagoval(a) s %1$s"
- "Označit jako přečtené"
"Vás pozval(a) do místnosti"
"Já"
"Prohlížíte si oznámení! Klikněte na mě!"
@@ -55,5 +53,7 @@
"Služby Google"
"Nebyly nalezeny žádné funkční služby Google Play. Oznámení nemusí fungovat správně."
"Oznámení"
+ "Vstoupit"
+ "Označit jako přečtené"
"Rychlá odpověď"
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 b807d7548e..ad90ed6e39 100644
--- a/libraries/push/impl/src/main/res/values-de/translations.xml
+++ b/libraries/push/impl/src/main/res/values-de/translations.xml
@@ -5,13 +5,11 @@
"Laute Benachrichtigungen"
"Stumme Benachrichtigungen"
"** Fehler beim Senden - bitte Raum öffnen"
- "Beitreten"
"Ablehnen"
"Du wurdest zu einem Chat eingeladen"
"Hat Dich erwähnt: %1$s"
"Neue Nachrichten"
"Reagiert mit %1$s"
- "Als gelesen markieren"
"Du wurdest eingeladen, den Raum zu betreten"
"Ich"
"Du siehst dir die Benachrichtigung an! Klicke hier!"
@@ -49,5 +47,7 @@
"Google-Dienste"
"Keine gültigen Google Play-Dienste gefunden. Benachrichtigungen funktionieren möglicherweise nicht richtig."
"Mitteilung"
+ "Beitreten"
+ "Als gelesen markieren"
"Schnelle Antwort"
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 6f5baf70d7..362614f6d8 100644
--- a/libraries/push/impl/src/main/res/values-es/translations.xml
+++ b/libraries/push/impl/src/main/res/values-es/translations.xml
@@ -5,13 +5,11 @@
"Notificaciones ruidosas"
"Notificaciones silenciosas"
"** No se ha podido enviar - por favor, abre la sala"
- "Unirse"
"Rechazar"
"Te invitó a chatear"
"Te mencionó: %1$s"
"Mensajes nuevos"
"Reaccionó con %1$s"
- "Marcar como leído"
"Te invitó a unirte a la sala"
"Yo"
"¡Estás viendo la notificación! ¡Haz clic en mí!"
@@ -49,5 +47,6 @@
"Servicios de Google"
"No se han encontrado Servicios de Google Play válidos. Es posible que las notificaciones no funcionen correctamente."
"Notificación"
+ "Unirse"
"Respuesta rápida"
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 daf8a092a6..2a1328503f 100644
--- a/libraries/push/impl/src/main/res/values-fr/translations.xml
+++ b/libraries/push/impl/src/main/res/values-fr/translations.xml
@@ -5,13 +5,11 @@
"Notifications bruyantes"
"Notifications silencieuses"
"** Échec de l’envoi - veuillez ouvrir le salon"
- "Rejoindre"
"Rejeter"
"Vous a invité(e) à discuter"
"Mentionné(e): %1$s"
"Nouveaux messages"
"A réagi avec %1$s"
- "Marquer comme lu"
"Vous a invité(e) à rejoindre le salon"
"Moi"
"Vous êtes en train de voir la notification ! Cliquez-moi !"
@@ -49,5 +47,7 @@
"Services Google"
"Aucun service Google Play valide n’a été trouvé. Les notifications peuvent ne pas fonctionner correctement."
"Notification"
+ "Rejoindre"
+ "Marquer comme lu"
"Réponse rapide"
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 23c3998bb8..1ef970fb28 100644
--- a/libraries/push/impl/src/main/res/values-hu/translations.xml
+++ b/libraries/push/impl/src/main/res/values-hu/translations.xml
@@ -5,14 +5,12 @@
"Zajos értesítések"
"Csendes értesítések"
"** Nem sikerült elküldeni – kérlek nyisd meg a szobát"
- "Csatlakozás"
"Elutasítás"
"Meghívta, hogy csevegjen"
"Megemlítette Önt: %1$s"
"Új üzenetek"
"Ezzel reagált: %1$s"
- "Megjelölés olvasottként"
- "Meghívta, hogy csatlakozzon a szobához"
+ "Meghívott, hogy csatlakozz a szobához"
"Én"
"Az értesítést nézed! Kattints ide!"
"%1$s: %2$s"
@@ -49,5 +47,7 @@
"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."
"Értesítés"
+ "Csatlakozás"
+ "Megjelölés olvasottként"
"Gyors válasz"
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 0e3f3699f0..1698df3597 100644
--- a/libraries/push/impl/src/main/res/values-in/translations.xml
+++ b/libraries/push/impl/src/main/res/values-in/translations.xml
@@ -5,13 +5,11 @@
"Pemberitahuan berisik"
"Pemberitahuan diam"
"** Gagal mengirim — silakan buka ruangan"
- "Bergabung"
"Tolak"
"Mengundang Anda untuk mengobrol"
"Menyebutkan Anda: %1$s"
"Pesan Baru"
"Menghapus dengan %1$s"
- "Tandai sebagai dibaca"
"Mengundang Anda untuk bergabung ke ruangan"
"Saya"
"Anda sedang melihat pemberitahuan ini! Klik saya!"
@@ -43,5 +41,6 @@
"Layanan Google"
"Tidak ditemukan Layanan Google Play yang valid. Pemberitahuan mungkin tidak berfungsi dengan baik."
"Notifikasi"
+ "Gabung"
"Balas cepat"
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 9e512001be..b167dd2299 100644
--- a/libraries/push/impl/src/main/res/values-it/translations.xml
+++ b/libraries/push/impl/src/main/res/values-it/translations.xml
@@ -1,15 +1,15 @@
"Chiamata"
+ "Ascolto degli eventi"
+ "Notifiche con suono"
"Notifiche silenziose"
"** Invio fallito - si prega di aprire la stanza"
- "Entra"
"Rifiuta"
"Ti ha invitato a chattare"
"Ti ha menzionato: %1$s"
"Nuovi messaggi"
"Ha reagito con %1$s"
- "Segna come letto"
"Ti ha invitato ad entrare nella stanza"
"Io"
"Stai visualizzando la notifica! Cliccami!"
@@ -47,5 +47,7 @@
"Servizi Google"
"Google Play Services non trovato. Le notifiche non funzioneranno bene."
"Notifica"
+ "Entra"
+ "Segna come letto"
"Risposta rapida"
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 8cabe414a2..4241ff1572 100644
--- a/libraries/push/impl/src/main/res/values-ro/translations.xml
+++ b/libraries/push/impl/src/main/res/values-ro/translations.xml
@@ -5,12 +5,10 @@
"Notificări zgomotoase"
"Notificări silențioase"
"** Trimiterea eșuată - vă rugăm să deschideți camera"
- "Alăturați-vă"
"Respingeți"
"V-a invitat la o discuție"
"Mesaje noi"
"A reacționat cu %1$s"
- "Marcați ca citit"
"V-a invitat să vă alăturați camerei"
"Eu"
"Vizualizați o notificare! Faceți clic pe mine!"
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 f183396dbc..171b8a3298 100644
--- a/libraries/push/impl/src/main/res/values-ru/translations.xml
+++ b/libraries/push/impl/src/main/res/values-ru/translations.xml
@@ -5,13 +5,11 @@
"Шумные уведомления"
"Бесшумные уведомления"
"** Не удалось отправить - пожалуйста, откройте комнату"
- "Присоединиться"
"Отклонить"
"Пригласил вас в чат"
"Упомянул вас: %1$s"
"Новые сообщения"
"Отреагировал на %1$s"
- "Отметить как прочитанное"
"Пригласил вас в комнату"
"Я"
"Вы просматриваете уведомление! Нажмите на меня!"
@@ -55,5 +53,7 @@
"Сервисы 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 bd79b42fc3..2f77c4cf39 100644
--- a/libraries/push/impl/src/main/res/values-sk/translations.xml
+++ b/libraries/push/impl/src/main/res/values-sk/translations.xml
@@ -5,13 +5,11 @@
"Hlasité oznámenia"
"Tiché oznámenia"
"** Nepodarilo sa odoslať - prosím otvorte miestnosť"
- "Pripojiť sa"
"Zamietnuť"
"Vás pozval/a na konverzáciu"
"Spomenul/a vás: %1$s"
"Nové správy"
"Reagoval/a s %1$s"
- "Označiť ako prečítané"
"Vás pozval do miestnosti"
"Ja"
"Prezeráte si oznámenie! Kliknite na mňa!"
@@ -55,5 +53,7 @@
"Služby Google"
"Nenašli sa žiadne platné služby Google Play. Oznámenia nemusia fungovať správne."
"Oznámenie"
+ "Pripojiť sa"
+ "Označiť ako prečítané"
"Rýchla odpoveď"
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 76a2ada95b..3239ea6d4b 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
@@ -3,13 +3,11 @@
"通話"
"無聲通知"
"** 無法傳送,請開啟聊天室"
- "加入"
"拒絕"
"邀請您聊天"
"提及您:%1$s"
"新訊息"
"回應 %1$s"
- "標示為已讀"
"邀請您加入聊天室"
"我"
"您正在查看通知!點我!"
@@ -34,5 +32,6 @@
"背景同步"
"Google 服務"
"通知"
+ "加入"
"快速回覆"
diff --git a/libraries/push/impl/src/main/res/values/localazy.xml b/libraries/push/impl/src/main/res/values/localazy.xml
index 7d50cd2864..a4fb529b7a 100644
--- a/libraries/push/impl/src/main/res/values/localazy.xml
+++ b/libraries/push/impl/src/main/res/values/localazy.xml
@@ -5,13 +5,11 @@
"Noisy notifications"
"Silent notifications"
"** Failed to send - please open room"
- "Join"
"Reject"
"Invited you to chat"
"Mentioned you: %1$s"
"New Messages"
"Reacted with %1$s"
- "Mark as read"
"Invited you to join the room"
"Me"
"You are viewing the notification! Click me!"
@@ -49,5 +47,7 @@
"Google Services"
"No valid Google Play Services found. Notifications may not work properly."
"Notification"
+ "Join"
+ "Mark as read"
"Quick reply"
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 05400e87f2..e28d67ecf7 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
@@ -105,7 +105,6 @@ class VectorUnifiedPushMessagingReceiver : MessagingReceiver() {
*/
override fun onUnregistered(context: Context, instance: String) {
Timber.tag(loggerTag.value).d("Unifiedpush: Unregistered")
- TODO()
/*
val mode = BackgroundSyncMode.FDROID_BACKGROUND_SYNC_MODE_FOR_REALTIME
pushDataStore.setFdroidSyncBackgroundMode(mode)
diff --git a/libraries/roomselect/impl/src/main/kotlin/io/element/android/libraries/roomselect/impl/RoomSelectView.kt b/libraries/roomselect/impl/src/main/kotlin/io/element/android/libraries/roomselect/impl/RoomSelectView.kt
index d7453ec264..9851a8c7c2 100644
--- a/libraries/roomselect/impl/src/main/kotlin/io/element/android/libraries/roomselect/impl/RoomSelectView.kt
+++ b/libraries/roomselect/impl/src/main/kotlin/io/element/android/libraries/roomselect/impl/RoomSelectView.kt
@@ -209,10 +209,9 @@ private fun RoomSummaryView(
summary: RoomSummaryDetails,
isSelected: Boolean,
onSelection: (RoomSummaryDetails) -> Unit,
- modifier: Modifier = Modifier
) {
Row(
- modifier = modifier
+ modifier = Modifier
.clickable { onSelection(summary) }
.fillMaxWidth()
.padding(start = 16.dp, end = 4.dp)
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 7542194bab..a88f036fd5 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
@@ -58,6 +58,11 @@ object TestTags {
*/
val richTextEditor = TestTag("rich_text_editor")
+ /**
+ * Message bubble.
+ */
+ val messageBubble = TestTag("message_bubble")
+
/**
* Dialogs.
*/
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 13359c1c0c..bd8cdd5215 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
@@ -405,14 +405,13 @@ private fun TextInput(
onError: (Throwable) -> Unit,
onTyping: (Boolean) -> Unit,
onRichContentSelected: ((Uri) -> Unit)?,
- modifier: Modifier = Modifier,
) {
val bgColor = ElementTheme.colors.bgSubtleSecondary
val borderColor = ElementTheme.colors.borderDisabled
val roundedCorners = textInputRoundedCornerShape(composerMode = composerMode)
Column(
- modifier = modifier
+ modifier = Modifier
.clip(roundedCorners)
.border(0.5.dp, borderColor, roundedCorners)
.background(color = bgColor)
@@ -464,15 +463,14 @@ private fun TextInput(
private fun ComposerModeView(
composerMode: MessageComposerMode,
onResetComposerMode: () -> Unit,
- modifier: Modifier = Modifier,
) {
when (composerMode) {
is MessageComposerMode.Edit -> {
- EditingModeView(onResetComposerMode = onResetComposerMode, modifier = modifier)
+ EditingModeView(onResetComposerMode = onResetComposerMode)
}
is MessageComposerMode.Reply -> {
ReplyToModeView(
- modifier = modifier.padding(8.dp),
+ modifier = Modifier.padding(8.dp),
senderName = composerMode.senderName,
text = composerMode.defaultContent,
attachmentThumbnailInfo = composerMode.attachmentThumbnailInfo,
@@ -486,12 +484,11 @@ private fun ComposerModeView(
@Composable
private fun EditingModeView(
onResetComposerMode: () -> Unit,
- modifier: Modifier = Modifier,
) {
Row(
horizontalArrangement = Arrangement.spacedBy(4.dp),
verticalAlignment = Alignment.CenterVertically,
- modifier = modifier
+ modifier = Modifier
.fillMaxWidth()
.padding(start = 12.dp)
) {
@@ -881,11 +878,8 @@ internal fun TextComposerVoicePreview() = ElementPreview {
@Composable
private fun PreviewColumn(
items: ImmutableList<@Composable () -> Unit>,
- modifier: Modifier = Modifier,
) {
- Column(
- modifier = modifier
- ) {
+ Column {
items.forEach { item ->
Box(
modifier = Modifier.height(IntrinsicSize.Min)
diff --git a/libraries/textcomposer/impl/src/main/kotlin/io/element/android/libraries/textcomposer/components/TextFormatting.kt b/libraries/textcomposer/impl/src/main/kotlin/io/element/android/libraries/textcomposer/components/TextFormatting.kt
index 81fd1ca81c..4ed978d7f0 100644
--- a/libraries/textcomposer/impl/src/main/kotlin/io/element/android/libraries/textcomposer/components/TextFormatting.kt
+++ b/libraries/textcomposer/impl/src/main/kotlin/io/element/android/libraries/textcomposer/components/TextFormatting.kt
@@ -43,6 +43,7 @@ import io.element.android.wysiwyg.view.models.LinkAction
import kotlinx.coroutines.launch
import uniffi.wysiwyg_composer.ActionState
import uniffi.wysiwyg_composer.ComposerAction
+
@Composable
internal fun TextFormatting(
state: RichTextEditorState,
diff --git a/libraries/textcomposer/impl/src/main/kotlin/io/element/android/libraries/textcomposer/components/VoiceMessagePreview.kt b/libraries/textcomposer/impl/src/main/kotlin/io/element/android/libraries/textcomposer/components/VoiceMessagePreview.kt
index db6a489321..e1ca066402 100644
--- a/libraries/textcomposer/impl/src/main/kotlin/io/element/android/libraries/textcomposer/components/VoiceMessagePreview.kt
+++ b/libraries/textcomposer/impl/src/main/kotlin/io/element/android/libraries/textcomposer/components/VoiceMessagePreview.kt
@@ -124,11 +124,10 @@ private fun PlayerButton(
type: PlayerButtonType,
enabled: Boolean,
onClick: () -> Unit,
- modifier: Modifier = Modifier,
) {
IconButton(
onClick = onClick,
- modifier = modifier
+ modifier = Modifier
.background(color = ElementTheme.colors.bgCanvasDefault, shape = CircleShape)
.size(30.dp),
enabled = enabled,
diff --git a/libraries/textcomposer/impl/src/main/kotlin/io/element/android/libraries/textcomposer/components/VoiceMessageRecording.kt b/libraries/textcomposer/impl/src/main/kotlin/io/element/android/libraries/textcomposer/components/VoiceMessageRecording.kt
index f98fbd5b9e..353b7bf70f 100644
--- a/libraries/textcomposer/impl/src/main/kotlin/io/element/android/libraries/textcomposer/components/VoiceMessageRecording.kt
+++ b/libraries/textcomposer/impl/src/main/kotlin/io/element/android/libraries/textcomposer/components/VoiceMessageRecording.kt
@@ -88,9 +88,7 @@ internal fun VoiceMessageRecording(
}
@Composable
-private fun RedRecordingDot(
- modifier: Modifier = Modifier,
-) {
+private fun RedRecordingDot() {
val infiniteTransition = rememberInfiniteTransition("RedRecordingDot")
val alpha by infiniteTransition.animateFloat(
initialValue = 1f,
@@ -102,7 +100,7 @@ private fun RedRecordingDot(
label = "RedRecordingDotAlpha",
)
Box(
- modifier = modifier
+ modifier = Modifier
.size(8.dp)
.alpha(alpha)
.background(color = ElementTheme.colors.textCriticalPrimary, shape = CircleShape)
diff --git a/libraries/textcomposer/impl/src/main/res/values-be/translations.xml b/libraries/textcomposer/impl/src/main/res/values-be/translations.xml
new file mode 100644
index 0000000000..10aa56cf99
--- /dev/null
+++ b/libraries/textcomposer/impl/src/main/res/values-be/translations.xml
@@ -0,0 +1,25 @@
+
+
+ "Пераключыць маркіраваны спіс"
+ "Закрыць параметры фарматавання"
+ "Пераключыць блок кода"
+ "Паведамленне…"
+ "Стварыце спасылку"
+ "Рэдагаваць спасылку"
+ "Ужыць тоўсты шрыфт"
+ "Ужыць курсіўны фармат"
+ "Ужыць фармат закрэслівання"
+ "Ужыць фармат падкрэслення"
+ "Пераключэнне поўнаэкраннага рэжыму"
+ "Водступ"
+ "Ужыць убудаваны фармат кода"
+ "Усталяваць спасылку"
+ "Пераключыць нумараваны спіс"
+ "Адкрыйце параметры кампазіцыі"
+ "Пераключыць цытату"
+ "Выдаліць спасылку"
+ "Без водступу"
+ "Спасылка"
+ "Дадаць далучэнне"
+ "Утрымлівайце для запісу"
+
diff --git a/libraries/ui-strings/src/main/res/values-be/translations.xml b/libraries/ui-strings/src/main/res/values-be/translations.xml
new file mode 100644
index 0000000000..358d1c7fd9
--- /dev/null
+++ b/libraries/ui-strings/src/main/res/values-be/translations.xml
@@ -0,0 +1,249 @@
+
+
+ "Выдаліць"
+ "Схаваць пароль"
+ "Перайсці ўніз"
+ "Толькі згадкі"
+ "Гук адключаны"
+ "Старонка %1$d"
+ "Паўза"
+ "Поле PIN-кода"
+ "Прайграць"
+ "Апытанне"
+ "Апытанне скончана"
+ "Рэагаваць з %1$s"
+ "Рэагаваць з іншымі эмодзі"
+ "Прачытана %1$s і %2$s"
+ "Прачытана %1$s"
+ "Націсніце, каб паказаць усе"
+ "Выдаліць рэакцыю з %1$s"
+ "Адправіць файлы"
+ "Паказаць пароль"
+ "Пазваніць"
+ "Меню карыстальніка"
+ "Запісаць галасавое паведамленне."
+ "Спыніць запіс"
+ "Прыняць"
+ "Дадаць на часовую шкалу"
+ "Назад"
+ "Скасаваць"
+ "Выбраць фота"
+ "Ачысціць"
+ "Закрыць"
+ "Поўная праверка"
+ "Пацвердзіць"
+ "Працягнуць"
+ "Капіраваць"
+ "Скапіраваць спасылку"
+ "Скапіраваць спасылку на паведамленне"
+ "Стварыць"
+ "Стварыце пакой"
+ "Адхіліць"
+ "Выдаліць апытанне"
+ "Адключыць"
+ "Гатова"
+ "Рэдагаваць"
+ "Рэдагаваць апытанне"
+ "Уключыць"
+ "Скончыць апытанне"
+ "Увядзіце PIN-код"
+ "Забылі пароль?"
+ "Пераслаць"
+ "Запрасіць"
+ "Запрасіць карыстальникаў"
+ "Запрасіць карыстальнікаў у %1$s"
+ "Запрасіць карыстальнікаў у %1$s"
+ "Запрашэнні"
+ "Далучыцца"
+ "Падрабязней"
+ "Пакінуць"
+ "Пакінуць размову"
+ "Пакінуць пакой"
+ "Кіраванне ўліковым запісам"
+ "Кіраванне прыладамі"
+ "Далей"
+ "Не"
+ "Не зараз"
+ "Добра"
+ "Налады"
+ "Адкрыць з дапамогай"
+ "Хуткі адказ"
+ "Цытата"
+ "Рэакцыя"
+ "Выдаліць"
+ "Адказаць"
+ "Адказаць у гутаркі"
+ "Паведаміць пра памылку"
+ "Паскардзіцца на змест"
+ "Паўтарыць"
+ "Паўтарыце расшыфроўку"
+ "Захаваць"
+ "Пошук"
+ "Адправіць"
+ "Адправіць паведамленне"
+ "Падзяліцца"
+ "Абагуліць спасылку"
+ "Увайдзіце яшчэ раз"
+ "Выйсці"
+ "Усё роўна выйсці"
+ "Прапусціць"
+ "Пачаць"
+ "Пачаць чат"
+ "Пачаць праверку"
+ "Націсніце, каб загрузіць карту"
+ "Зрабіць фота"
+ "Дакраніцеся, каб убачыць параметры"
+ "Паўтарыць спробу"
+ "Паказаць крыніцу"
+ "Так"
+ "Загрузіць больш"
+ "Аб праграме"
+ "Палітыка дапушчальнага выкарыстання"
+ "Пашыраныя налады"
+ "Аналітыка"
+ "Знешні выгляд"
+ "Аўдыё"
+ "Бурбалкі"
+ "Рэзервовае капіраванне чата"
+ "Аўтарскае права"
+ "Стварэнне пакоя…"
+ "Выйшаў з пакоя"
+ "Цёмная"
+ "Памылка расшыфроўкі"
+ "Параметры распрацоўшчыка"
+ "Прамы чат"
+ "(Адрэдагавана)"
+ "Рэдагаванне"
+ "* %1$s %2$s"
+ "Шыфраванне ўключана"
+ "Увядзіце свой PIN-код"
+ "Памылка"
+ "Усе"
+ "Файл"
+ "Файл захаваны ў папку Спампоўкі"
+ "Перасылка паведамлення"
+ "GIF"
+ "Выява"
+ "У адказ на %1$s"
+ "Усталяваць APK"
+ "Гэты Matrix ID не знойдзены, таму запрашэнне можа быць не атрымана."
+ "Пакінуць пакой"
+ "Светлая"
+ "Спасылка скапіравана ў буфер абмену"
+ "Загрузка…"
+ "Паведамленне"
+ "Дзеянні з паведамленням"
+ "Паведамленне выдалена"
+ "Сучасны"
+ "Адключыць гук"
+ "Вынікаў няма"
+ "Па-за сеткай"
+ "Пароль"
+ "Людзі"
+ "Пастаянная спасылка"
+ "Дазвол"
+ "Усяго галасоў: %1$s"
+ "Вынікі будуць паказаны пасля завяршэння апытання"
+ "Палітыка прыватнасці"
+ "Рэакцыя"
+ "Рэакцыі"
+ "Ключ аднаўлення"
+ "Абнаўленне…"
+ "Адказвае на %1$s"
+ "Паведаміць пра памылку"
+ "Паведаміць аб праблеме"
+ "Скарга прынята"
+ "Рэдактар фарматаванага тэксту"
+ "Пакой"
+ "Назва пакоя"
+ "напрыклад, назва вашага праекта"
+ "Блакіроўка экрана"
+ "Шукаць карыстальніка"
+ "Вынікі пошуку"
+ "Бяспека"
+ "Прагледжана"
+ "Адпраўка…"
+ "Памылка адпраўкі"
+ "Адпраўлена"
+ "Сервер не падтрымліваецца"
+ "URL-адрас сервера"
+ "Налады"
+ "Выхад"
+ "Пачатак чата…"
+ "Стыкер"
+ "Поспех"
+ "Прапановы"
+ "Сінхранізацыя"
+ "Сістэма"
+ "Тэкст"
+ "Паведамленні трэціх асоб"
+ "Гутарка"
+ "Тэма"
+ "Пра што гэты пакой?"
+ "Немагчыма расшыфраваць"
+ "Не ўдалося адправіць запрашэнні аднаму або некалькім карыстальнікам."
+ "Немагчыма адправіць запрашэнне(я)"
+ "Разблакіраваць"
+ "Уключыць гук"
+ "Падзея не падтрымліваецца"
+ "Імя карыстальніка"
+ "Праверка адменена"
+ "Праверка завершана"
+ "Відэа"
+ "Галасавое паведамленне"
+ "Чакаем…"
+ "Чакаю гэтага паведамлення"
+ "Вы ўпэўнены, што хочаце скончыць гэтае апытанне?"
+ "Апытанне: %1$s"
+ "Праверце прыладу"
+ "Пацвярджэнне"
+ "Папярэджанне"
+ "Не атрымалася стварыць пастаянную спасылку"
+ "%1$s не атрымалася загрузіць карту. Калі ласка паспрабуйце зноў пазней."
+ "Не ўдалося загрузіць паведамленні"
+ "%1$s не магчыма атрымаць доступ да вашага месцазнаходжання. Калі ласка паспрабуйце зноў пазней."
+ "Не ўдалося загрузіць ваша галасавое паведамленне."
+ "У %1$s няма дазволу на доступ да вашага месцазнаходжання. Вы можаце даць доступ у Наладах."
+ "У %1$s няма дазволу на доступ да вашага месцазнаходжання. Дазвольце доступ ніжэй."
+ "%1$s не мае дазволу на доступ да вашага мікрафона. Дазвольце доступ да запісу галасавога паведамлення."
+ "Некаторыя паведамленні не былі адпраўлены"
+ "На жаль, адбылася памылка"
+ "🔐️ Далучайцеся да мяне %1$s"
+ "Гэй, пагавары са мной у %1$s: %2$s"
+ "%1$s Android"
+
+ - "Уведзеная лічба %1$d"
+ - "Уведзена %1$d лічбы"
+ - "Уведзена %1$d лічб"
+
+
+ - "Прачытана %1$s і %2$d іншым"
+ - "Прачытана %1$s і %2$d іншымі"
+ - "Прачытана %1$s і %2$d іншымі"
+
+
+ - "%1$d карыстальнік"
+ - "%1$d карыстальнікаў"
+ - "%1$d карыстальнікаў"
+
+
+ - "%d голас"
+ - "%d галасоў"
+ - "%d галасоў"
+
+ "Rageshake паведаміць пра памылку"
+ "Не ўдалося выбраць носьбіт, паўтарыце спробу."
+ "Не атрымалася апрацаваць медыяфайл для загрузкі, паспрабуйце яшчэ раз."
+ "Не атрымалася загрузіць медыяфайлы, паспрабуйце яшчэ раз."
+ "Падзяліцца месцазнаходжаннем"
+ "Падзяліцца маім месцазнаходжаннем"
+ "Адкрыць у Apple Maps"
+ "Адкрыць у Google Maps"
+ "Адкрыць у OpenStreetMap"
+ "Падзяліцеся гэтым месцазнаходжаннем"
+ "Месцазнаходжанне"
+ "Версія: %1$s (%2$s)"
+ "be"
+ "Памылка"
+ "Поспех"
+
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 3145967bf0..ae71ff19b0 100644
--- a/libraries/ui-strings/src/main/res/values-cs/translations.xml
+++ b/libraries/ui-strings/src/main/res/values-cs/translations.xml
@@ -119,6 +119,7 @@
"Zadejte svůj PIN"
"Chyba"
"Všichni"
+ "Oblíbené"
"Soubor"
"Soubor byl uložen do složky Stažené soubory"
"Přeposlat zprávu"
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 1578326b9f..9c362e4400 100644
--- a/libraries/ui-strings/src/main/res/values-de/translations.xml
+++ b/libraries/ui-strings/src/main/res/values-de/translations.xml
@@ -57,6 +57,7 @@
"Beitreten"
"Mehr erfahren"
"Verlassen"
+ "Unterhaltung verlassen"
"Raum verlassen"
"Konto verwalten"
"Geräte verwalten"
@@ -118,6 +119,7 @@
"PIN eingeben"
"Fehler"
"Alle"
+ "Favorit"
"Datei"
"Datei wurde unter Downloads gespeichert"
"Nachricht weiterleiten"
diff --git a/libraries/ui-strings/src/main/res/values-fr/translations.xml b/libraries/ui-strings/src/main/res/values-fr/translations.xml
index c56ad20a88..740138e116 100644
--- a/libraries/ui-strings/src/main/res/values-fr/translations.xml
+++ b/libraries/ui-strings/src/main/res/values-fr/translations.xml
@@ -119,6 +119,7 @@
"Saisissez votre code PIN"
"Erreur"
"Tout le monde"
+ "Favori"
"Fichier"
"Fichier enregistré dans Téléchargements"
"Transférer le message"
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 102320bf83..dfaac3446a 100644
--- a/libraries/ui-strings/src/main/res/values-hu/translations.xml
+++ b/libraries/ui-strings/src/main/res/values-hu/translations.xml
@@ -46,7 +46,7 @@
"Szavazás szerkesztése"
"Engedélyezés"
"Szavazás lezárása"
- "Adja meg a PIN-kódot"
+ "Add meg a PIN-kódot"
"Elfelejtetted a jelszavadat?"
"Tovább"
"Meghívás"
@@ -57,6 +57,7 @@
"Csatlakozás"
"További tudnivalók"
"Elhagyás"
+ "Beszélgetés elhagyása"
"Szoba elhagyása"
"Fiók kezelése"
"Eszközök kezelése"
@@ -91,7 +92,7 @@
"Ellenőrzés elindítása"
"Koppints a térkép betöltéséhez"
"Fénykép készítése"
- "Koppintson a lehetőségekért"
+ "Koppints a beállításokért"
"Próbáld újra"
"Forrás megtekintése"
"Igen"
@@ -118,6 +119,7 @@
"Add meg a PIN-kódodat"
"Hiba"
"Mindenki"
+ "Kedvenc"
"Fájl"
"A fájl a Letöltések mappába mentve"
"Üzenet továbbítása"
@@ -200,13 +202,13 @@
"Megerősítés"
"Figyelmeztetés"
"Nem sikerült létrehozni az állandó hivatkozást"
- "Az %1$s nem tudta betölteni a térképet. Próbálja meg újra később."
+ "A(z) %1$s nem tudta betölteni a térképet. Próbáld meg újra később."
"Nem sikerült betölteni az üzeneteket"
"A(z) %1$s nem tudta elérni a tartózkodási helyét. Próbáld meg újra később."
"Nem sikerült feltölteni a hangüzenetét."
"Az %1$snek nincs engedélye, hogy hozzáférjen a tartózkodási helyedhez. Ezt a beállításokban engedélyezheted."
"Az %1$snek nincs engedélye, hogy hozzáférjen a tartózkodási helyéhez. Engedélyezze alább az elérését."
- "Az %1$snek nincs engedélye, hogy hozzáférjen a mikrofonjához. Engedélyezze, hogy tudjon hangüzenetet felvenni."
+ "Az %1$snek nincs engedélye, hogy hozzáférjen a mikrofonhoz. Engedélyezd, hogy tudjon hangüzenetet felvenni."
"Néhány üzenet nem került elküldésre"
"Elnézést, hiba történt"
"🔐️ Csatlakozz hozzám itt: %1$s"
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 ad2738557c..50c0f5b545 100644
--- a/libraries/ui-strings/src/main/res/values-it/translations.xml
+++ b/libraries/ui-strings/src/main/res/values-it/translations.xml
@@ -119,6 +119,7 @@
"Inserisci il PIN"
"Errore"
"Tutti"
+ "Preferiti"
"File"
"File salvato in Download"
"Inoltra messaggio"
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 5477f03af9..b75bd7680e 100644
--- a/libraries/ui-strings/src/main/res/values-ru/translations.xml
+++ b/libraries/ui-strings/src/main/res/values-ru/translations.xml
@@ -119,6 +119,7 @@
"Введите свой PIN-код"
"Ошибка"
"Для всех"
+ "Избранное"
"Файл"
"Файл сохранен в «Загрузки»"
"Переслать сообщение"
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 343bbbf3ae..56606bd1c4 100644
--- a/libraries/ui-strings/src/main/res/values-sk/translations.xml
+++ b/libraries/ui-strings/src/main/res/values-sk/translations.xml
@@ -119,6 +119,7 @@
"Zadajte svoj PIN"
"Chyba"
"Všetci"
+ "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/localazy.xml b/libraries/ui-strings/src/main/res/values/localazy.xml
index 26874d4a19..4865698362 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 @@
"Enter your PIN"
"Error"
"Everyone"
+ "Favourite"
"File"
"File saved to Downloads"
"Forward message"
diff --git a/plugins/src/main/kotlin/extension/DependencyHandleScope.kt b/plugins/src/main/kotlin/extension/DependencyHandleScope.kt
index 1ba4b60b4d..cc254511bd 100644
--- a/plugins/src/main/kotlin/extension/DependencyHandleScope.kt
+++ b/plugins/src/main/kotlin/extension/DependencyHandleScope.kt
@@ -56,16 +56,6 @@ fun DependencyHandlerScope.composeDependencies(libs: LibrariesForLibs) {
implementation(libs.androidx.compose.ui)
implementation(libs.androidx.compose.material)
implementation(libs.androidx.compose.material3)
-
- // Remove these constraints once `material3` updates its internal dependencies
- constraints {
- implementation("androidx.compose.foundation:foundation:1.6.0-beta02") {
- because("The transitive version inside `material3` (1.6.0-beta01) causes a scrolling issue. " +
- "See https://android.googlesource.com/platform/frameworks/support/+/2d15876146ccf201f7e15cacc78bfca762060624"
- )
- }
- }
-
implementation(libs.androidx.compose.material.icons)
implementation(libs.androidx.compose.ui.tooling.preview)
implementation(libs.androidx.activity.compose)
diff --git a/samples/minimal/build.gradle.kts b/samples/minimal/build.gradle.kts
index edf2527572..f9bfc63932 100644
--- a/samples/minimal/build.gradle.kts
+++ b/samples/minimal/build.gradle.kts
@@ -54,6 +54,7 @@ dependencies {
implementation(projects.libraries.network)
implementation(projects.libraries.dateformatter.impl)
implementation(projects.libraries.eventformatter.impl)
+ implementation(projects.libraries.preferences.impl)
implementation(projects.libraries.indicator.impl)
implementation(projects.features.invitelist.impl)
implementation(projects.features.roomlist.impl)
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 286a80d71d..218dfdd697 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
@@ -28,6 +28,8 @@ import io.element.android.features.roomlist.impl.RoomListView
import io.element.android.features.roomlist.impl.datasource.DefaultInviteStateDataSource
import io.element.android.features.roomlist.impl.datasource.RoomListDataSource
import io.element.android.features.roomlist.impl.datasource.RoomListRoomSummaryFactory
+import io.element.android.features.roomlist.impl.migration.MigrationScreenPresenter
+import io.element.android.features.roomlist.impl.migration.SharedPrefsMigrationScreenStore
import io.element.android.libraries.core.coroutine.CoroutineDispatchers
import io.element.android.libraries.dateformatter.impl.DateFormatters
import io.element.android.libraries.dateformatter.impl.DefaultLastMessageTimestampFormatter
@@ -43,6 +45,7 @@ import io.element.android.libraries.indicator.impl.DefaultIndicatorService
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.preferences.impl.store.DefaultSessionPreferencesStore
import io.element.android.services.toolbox.impl.strings.AndroidStringProvider
import kotlinx.coroutines.launch
import kotlinx.coroutines.runBlocking
@@ -103,6 +106,15 @@ class RoomListScreen(
featureFlagService = featureFlagService,
),
featureFlagService = featureFlagService,
+ migrationScreenPresenter = MigrationScreenPresenter(
+ matrixClient = matrixClient,
+ migrationScreenStore = SharedPrefsMigrationScreenStore(context.getSharedPreferences("migration", Context.MODE_PRIVATE))
+ ),
+ sessionPreferencesStore = DefaultSessionPreferencesStore(
+ context = context,
+ sessionId = matrixClient.sessionId,
+ sessionCoroutineScope = Singleton.appScope
+ ),
)
@Composable
diff --git a/tests/testutils/src/main/kotlin/io/element/android/tests/testutils/EnsureCalledOnce.kt b/tests/testutils/src/main/kotlin/io/element/android/tests/testutils/EnsureCalledOnce.kt
index ddc8e22a5c..b2c943e1ca 100644
--- a/tests/testutils/src/main/kotlin/io/element/android/tests/testutils/EnsureCalledOnce.kt
+++ b/tests/testutils/src/main/kotlin/io/element/android/tests/testutils/EnsureCalledOnce.kt
@@ -35,15 +35,17 @@ fun ensureCalledOnce(block: (callback: EnsureCalledOnce) -> Unit) {
callback.assertSuccess()
}
-class EnsureCalledOnceWithParam(
- private val expectedParam: T
-) : (T) -> Unit {
+class EnsureCalledOnceWithParam(
+ private val expectedParam: T,
+ private val result: R,
+) : (T) -> R {
private var counter = 0
- override fun invoke(p1: T) {
+ override fun invoke(p1: T): R {
if (p1 != expectedParam) {
throw AssertionError("Expected to be called with $expectedParam, but was called with $p1")
}
counter++
+ return result
}
fun assertSuccess() {
@@ -53,8 +55,15 @@ class EnsureCalledOnceWithParam(
}
}
-fun ensureCalledOnceWithParam(param: T, block: (callback: EnsureCalledOnceWithParam) -> Unit) {
- val callback = EnsureCalledOnceWithParam(param)
+/**
+ * Shortcut for [ ensureCalledOnceWithParam] with Unit result.
+ */
+fun ensureCalledOnceWithParam(param: T, block: (callback: EnsureCalledOnceWithParam) -> Unit) {
+ ensureCalledOnceWithParam(param, block, Unit)
+}
+
+fun ensureCalledOnceWithParam(param: T, block: (callback: EnsureCalledOnceWithParam) -> R, result: R) {
+ val callback = EnsureCalledOnceWithParam(param, result)
block(callback)
callback.assertSuccess()
}
diff --git a/tests/testutils/src/main/kotlin/io/element/android/tests/testutils/EnsureNeverCalled.kt b/tests/testutils/src/main/kotlin/io/element/android/tests/testutils/EnsureNeverCalled.kt
index e98c025238..f2f2c31fed 100644
--- a/tests/testutils/src/main/kotlin/io/element/android/tests/testutils/EnsureNeverCalled.kt
+++ b/tests/testutils/src/main/kotlin/io/element/android/tests/testutils/EnsureNeverCalled.kt
@@ -27,3 +27,15 @@ class EnsureNeverCalledWithParam : (T) -> Unit {
throw AssertionError("Should not be called and is called with $p1")
}
}
+
+class EnsureNeverCalledWithParamAndResult : (T) -> R {
+ override fun invoke(p1: T): R {
+ throw AssertionError("Should not be called and is called with $p1")
+ }
+}
+
+class EnsureNeverCalledWithTwoParams : (T, U) -> Unit {
+ override fun invoke(p1: T, p2: U) {
+ throw AssertionError("Should not be called and is called with $p1 and $p2")
+ }
+}
diff --git a/tests/testutils/src/main/kotlin/io/element/android/tests/testutils/EventsRecorder.kt b/tests/testutils/src/main/kotlin/io/element/android/tests/testutils/EventsRecorder.kt
index 4cc9bd078c..3a1c4babff 100644
--- a/tests/testutils/src/main/kotlin/io/element/android/tests/testutils/EventsRecorder.kt
+++ b/tests/testutils/src/main/kotlin/io/element/android/tests/testutils/EventsRecorder.kt
@@ -31,6 +31,10 @@ class EventsRecorder(
}
}
+ fun assertEmpty() {
+ assertThat(events).isEmpty()
+ }
+
fun assertSingle(event: T) {
assertList(listOf(event))
}
diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.analytics.impl_AnalyticsOptInView_null_AnalyticsOptInView-Day-0_1_null_0,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.analytics.impl_AnalyticsOptInView_null_AnalyticsOptInView-Day-0_1_null_0,NEXUS_5,1.0,en].png
index ef4f316ea1..f594008e01 100644
--- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.analytics.impl_AnalyticsOptInView_null_AnalyticsOptInView-Day-0_1_null_0,NEXUS_5,1.0,en].png
+++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.analytics.impl_AnalyticsOptInView_null_AnalyticsOptInView-Day-0_1_null_0,NEXUS_5,1.0,en].png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:c6664fe1c30fee448945a238795a60f4ddbc8fefec0bc7e48e9345e6b5b429e5
-size 50702
+oid sha256:0707a78bd738d570d258d5e65a2b0256d0e76ed78a49d79bed49330defeb7cf2
+size 50637
diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.analytics.impl_AnalyticsOptInView_null_AnalyticsOptInView-Night-0_2_null_0,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.analytics.impl_AnalyticsOptInView_null_AnalyticsOptInView-Night-0_2_null_0,NEXUS_5,1.0,en].png
index 34a414aed1..fa6c0514d8 100644
--- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.analytics.impl_AnalyticsOptInView_null_AnalyticsOptInView-Night-0_2_null_0,NEXUS_5,1.0,en].png
+++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.analytics.impl_AnalyticsOptInView_null_AnalyticsOptInView-Night-0_2_null_0,NEXUS_5,1.0,en].png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:91e2590fa78c1dbc1a24eb13602df844259b5c9e7a14fd0d3cfbf2d9086e0453
-size 49543
+oid sha256:b8734b34987f4972b604a589856d03af8def1202fc57617e2e9833141c6b4a79
+size 49523
diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.ftue.impl.migration_MigrationView_null_MigrationView-Night-0_2_null,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.ftue.impl.migration_MigrationView_null_MigrationView-Night-0_2_null,NEXUS_5,1.0,en].png
deleted file mode 100644
index 99a9e03973..0000000000
--- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.ftue.impl.migration_MigrationView_null_MigrationView-Night-0_2_null,NEXUS_5,1.0,en].png
+++ /dev/null
@@ -1,3 +0,0 @@
-version https://git-lfs.github.com/spec/v1
-oid sha256:4c9d9aa75b2b01e9b0106377fbcd88a92fb8b4d6a34323b18264fed8f9a48cab
-size 133347
diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.ftue.impl.notifications_NotificationsOptInView_null_NotificationsOptInView-Day-0_1_null_0,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.ftue.impl.notifications_NotificationsOptInView_null_NotificationsOptInView-Day-0_1_null_0,NEXUS_5,1.0,en].png
new file mode 100644
index 0000000000..11da2d3322
--- /dev/null
+++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.ftue.impl.notifications_NotificationsOptInView_null_NotificationsOptInView-Day-0_1_null_0,NEXUS_5,1.0,en].png
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:779ce59665e92ed1419dbba576b8f887e11363bcef07c42608a8d3634bbc00d2
+size 37172
diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.ftue.impl.notifications_NotificationsOptInView_null_NotificationsOptInView-Day-1_2_null_0,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.ftue.impl.notifications_NotificationsOptInView_null_NotificationsOptInView-Day-1_2_null_0,NEXUS_5,1.0,en].png
deleted file mode 100644
index 10ec2fb2cb..0000000000
--- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.ftue.impl.notifications_NotificationsOptInView_null_NotificationsOptInView-Day-1_2_null_0,NEXUS_5,1.0,en].png
+++ /dev/null
@@ -1,3 +0,0 @@
-version https://git-lfs.github.com/spec/v1
-oid sha256:556ac89ad4a4f4a2f204f84634ce63ad8fef43bdb26edba8a78f7bc06d13b374
-size 37179
diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.ftue.impl.notifications_NotificationsOptInView_null_NotificationsOptInView-Night-0_2_null_0,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.ftue.impl.notifications_NotificationsOptInView_null_NotificationsOptInView-Night-0_2_null_0,NEXUS_5,1.0,en].png
new file mode 100644
index 0000000000..bd19065570
--- /dev/null
+++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.ftue.impl.notifications_NotificationsOptInView_null_NotificationsOptInView-Night-0_2_null_0,NEXUS_5,1.0,en].png
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:699739584aab66a1f67ac8f5fb6a5ff535e3ca02696eacff05adf1c64d2d5646
+size 33709
diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.ftue.impl.notifications_NotificationsOptInView_null_NotificationsOptInView-Night-1_3_null_0,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.ftue.impl.notifications_NotificationsOptInView_null_NotificationsOptInView-Night-1_3_null_0,NEXUS_5,1.0,en].png
deleted file mode 100644
index 2fc8eaee08..0000000000
--- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.ftue.impl.notifications_NotificationsOptInView_null_NotificationsOptInView-Night-1_3_null_0,NEXUS_5,1.0,en].png
+++ /dev/null
@@ -1,3 +0,0 @@
-version https://git-lfs.github.com/spec/v1
-oid sha256:636756772f8e4eba11e88a7903f04c545cc93045961c7747ddfa2fcb24533754
-size 33710
diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.ftue.impl.welcome_WelcomeView_null_WelcomeView-Day-1_2_null,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.ftue.impl.welcome_WelcomeView_null_WelcomeView-Day-1_2_null,NEXUS_5,1.0,en].png
new file mode 100644
index 0000000000..36be4e7755
--- /dev/null
+++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.ftue.impl.welcome_WelcomeView_null_WelcomeView-Day-1_2_null,NEXUS_5,1.0,en].png
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:0ce8844085506f4efec8eb1c461f416d240545fc0119cfd28b71cf8fe4a92ae5
+size 286645
diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.ftue.impl.welcome_WelcomeView_null_WelcomeView-Day-2_3_null,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.ftue.impl.welcome_WelcomeView_null_WelcomeView-Day-2_3_null,NEXUS_5,1.0,en].png
deleted file mode 100644
index ff92f02572..0000000000
--- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.ftue.impl.welcome_WelcomeView_null_WelcomeView-Day-2_3_null,NEXUS_5,1.0,en].png
+++ /dev/null
@@ -1,3 +0,0 @@
-version https://git-lfs.github.com/spec/v1
-oid sha256:8d56633c5bddf14c18ebab5859b0f2aaee9c37c1ff8a8923b508827880e708b3
-size 288239
diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.ftue.impl.welcome_WelcomeView_null_WelcomeView-Night-1_3_null,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.ftue.impl.welcome_WelcomeView_null_WelcomeView-Night-1_3_null,NEXUS_5,1.0,en].png
new file mode 100644
index 0000000000..846e49c61a
--- /dev/null
+++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.ftue.impl.welcome_WelcomeView_null_WelcomeView-Night-1_3_null,NEXUS_5,1.0,en].png
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:0f88c69dbd38cdd2f6c8ed953901dc7655dc6157a01c73060ee1dc6e82ace110
+size 390198
diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.ftue.impl.welcome_WelcomeView_null_WelcomeView-Night-2_4_null,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.ftue.impl.welcome_WelcomeView_null_WelcomeView-Night-2_4_null,NEXUS_5,1.0,en].png
deleted file mode 100644
index 3440c75136..0000000000
--- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.ftue.impl.welcome_WelcomeView_null_WelcomeView-Night-2_4_null,NEXUS_5,1.0,en].png
+++ /dev/null
@@ -1,3 +0,0 @@
-version https://git-lfs.github.com/spec/v1
-oid sha256:04b8af7d14aff6edd9db4e4c6187381c9efbdba1721e1688da5823038f1aa31f
-size 391103
diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.lockscreen.impl.setup.biometric_SetupBiometricView_null_SetupBiometricView-Day-2_3_null_0,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.lockscreen.impl.setup.biometric_SetupBiometricView_null_SetupBiometricView-Day-2_3_null_0,NEXUS_5,1.0,en].png
index 5ecc718c8f..12b8bc6a3a 100644
--- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.lockscreen.impl.setup.biometric_SetupBiometricView_null_SetupBiometricView-Day-2_3_null_0,NEXUS_5,1.0,en].png
+++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.lockscreen.impl.setup.biometric_SetupBiometricView_null_SetupBiometricView-Day-2_3_null_0,NEXUS_5,1.0,en].png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:fb7cf95951b4cae20445929a7b0ce7d3fb4cb1ff0d6ce735e890106754485856
-size 37651
+oid sha256:c4338ca6512f08eee0bb3171b2d0cb0cbd813d4644be5500f14e47c9f071243b
+size 37263
diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.lockscreen.impl.setup.biometric_SetupBiometricView_null_SetupBiometricView-Night-2_4_null_0,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.lockscreen.impl.setup.biometric_SetupBiometricView_null_SetupBiometricView-Night-2_4_null_0,NEXUS_5,1.0,en].png
index 652efd1ba4..4be5500a4e 100644
--- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.lockscreen.impl.setup.biometric_SetupBiometricView_null_SetupBiometricView-Night-2_4_null_0,NEXUS_5,1.0,en].png
+++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.lockscreen.impl.setup.biometric_SetupBiometricView_null_SetupBiometricView-Night-2_4_null_0,NEXUS_5,1.0,en].png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:38e9a9481637e9fafbc2bf4083b1024e735bd40f6b4bdcda4f50b403df475e96
-size 35595
+oid sha256:181c745a8d624eacaa85e43b2f98fd24e006d9d93155cf66480d51213064bf19
+size 35255
diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.login.impl.screens.confirmaccountprovider_ConfirmAccountProviderView_null_ConfirmAccountProviderView-Day-5_6_null_0,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.login.impl.screens.confirmaccountprovider_ConfirmAccountProviderView_null_ConfirmAccountProviderView-Day-5_6_null_0,NEXUS_5,1.0,en].png
index 6459387bca..5bace8e94e 100644
--- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.login.impl.screens.confirmaccountprovider_ConfirmAccountProviderView_null_ConfirmAccountProviderView-Day-5_6_null_0,NEXUS_5,1.0,en].png
+++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.login.impl.screens.confirmaccountprovider_ConfirmAccountProviderView_null_ConfirmAccountProviderView-Day-5_6_null_0,NEXUS_5,1.0,en].png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:5e5b2bdd159234708bc988bedeafc62ef8bfadeba71211fb6838bdc522990acb
-size 39654
+oid sha256:a2c1530f2b1d34dee8ebf59ba05165f195226ae77d6098d22f446e62799f90f5
+size 39577
diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.login.impl.screens.confirmaccountprovider_ConfirmAccountProviderView_null_ConfirmAccountProviderView-Night-5_7_null_0,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.login.impl.screens.confirmaccountprovider_ConfirmAccountProviderView_null_ConfirmAccountProviderView-Night-5_7_null_0,NEXUS_5,1.0,en].png
index 600bf55cbb..2e943e28c2 100644
--- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.login.impl.screens.confirmaccountprovider_ConfirmAccountProviderView_null_ConfirmAccountProviderView-Night-5_7_null_0,NEXUS_5,1.0,en].png
+++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.login.impl.screens.confirmaccountprovider_ConfirmAccountProviderView_null_ConfirmAccountProviderView-Night-5_7_null_0,NEXUS_5,1.0,en].png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:a87c902caeaae97acc949d5465f8abcba4bbed81abddea42dcb2b4485e7d29fa
-size 37219
+oid sha256:7ce7ad067efe9b9158395982211077c1d13fbfb46c6b317900cd30fd5836ddfe
+size 37196
diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.login.impl.screens.loginpassword_LoginPasswordView_null_LoginPasswordView-Day-6_7_null_0,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.login.impl.screens.loginpassword_LoginPasswordView_null_LoginPasswordView-Day-6_7_null_0,NEXUS_5,1.0,en].png
index 3bdb7f4d9c..4dd3f033ec 100644
--- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.login.impl.screens.loginpassword_LoginPasswordView_null_LoginPasswordView-Day-6_7_null_0,NEXUS_5,1.0,en].png
+++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.login.impl.screens.loginpassword_LoginPasswordView_null_LoginPasswordView-Day-6_7_null_0,NEXUS_5,1.0,en].png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:9cc2c0ee0df61c3b071185daeb2e20d64f129db2b3e9b5f2d9bb68dd2b04ca71
-size 39655
+oid sha256:f4df53da4792d6058a3fb3edda32652612185006b52efef772331e09dd5b1194
+size 40018
diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.login.impl.screens.loginpassword_LoginPasswordView_null_LoginPasswordView-Day-6_7_null_1,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.login.impl.screens.loginpassword_LoginPasswordView_null_LoginPasswordView-Day-6_7_null_1,NEXUS_5,1.0,en].png
index 54fb4fa2dd..95f9d62944 100644
--- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.login.impl.screens.loginpassword_LoginPasswordView_null_LoginPasswordView-Day-6_7_null_1,NEXUS_5,1.0,en].png
+++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.login.impl.screens.loginpassword_LoginPasswordView_null_LoginPasswordView-Day-6_7_null_1,NEXUS_5,1.0,en].png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:27b8b17d2f628e9bfa5f0d97bf2cf68424261596967d1b2621a5bb879f2ce2d1
-size 40815
+oid sha256:57b400403ffc577cce65aede9880e023fb022ce0aae447d7c621308203a7f053
+size 41151
diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.login.impl.screens.loginpassword_LoginPasswordView_null_LoginPasswordView-Day-6_7_null_2,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.login.impl.screens.loginpassword_LoginPasswordView_null_LoginPasswordView-Day-6_7_null_2,NEXUS_5,1.0,en].png
index f198ed2c07..8f10ceed70 100644
--- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.login.impl.screens.loginpassword_LoginPasswordView_null_LoginPasswordView-Day-6_7_null_2,NEXUS_5,1.0,en].png
+++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.login.impl.screens.loginpassword_LoginPasswordView_null_LoginPasswordView-Day-6_7_null_2,NEXUS_5,1.0,en].png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:ec89cd219a741b98ae046b2c90db9d36d418570f05d0edf41cfe831cf71b1303
-size 30745
+oid sha256:77dbd62af4d2ee97e157cdf407c62807aef0979192d95d2fce9f880a1387714a
+size 31171
diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.login.impl.screens.loginpassword_LoginPasswordView_null_LoginPasswordView-Night-6_8_null_0,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.login.impl.screens.loginpassword_LoginPasswordView_null_LoginPasswordView-Night-6_8_null_0,NEXUS_5,1.0,en].png
index 179219d286..78c5aecd8b 100644
--- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.login.impl.screens.loginpassword_LoginPasswordView_null_LoginPasswordView-Night-6_8_null_0,NEXUS_5,1.0,en].png
+++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.login.impl.screens.loginpassword_LoginPasswordView_null_LoginPasswordView-Night-6_8_null_0,NEXUS_5,1.0,en].png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:0a240b641665c15d79663a4f35fa7af923bebf88eeac6355c9c1ff127794ba77
-size 37585
+oid sha256:50495c30c23802a747c9d423d8e227d0e034dbf3b403f64cb4607d9ab258607c
+size 37952
diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.login.impl.screens.loginpassword_LoginPasswordView_null_LoginPasswordView-Night-6_8_null_1,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.login.impl.screens.loginpassword_LoginPasswordView_null_LoginPasswordView-Night-6_8_null_1,NEXUS_5,1.0,en].png
index 44a81090b6..df9f611f99 100644
--- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.login.impl.screens.loginpassword_LoginPasswordView_null_LoginPasswordView-Night-6_8_null_1,NEXUS_5,1.0,en].png
+++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.login.impl.screens.loginpassword_LoginPasswordView_null_LoginPasswordView-Night-6_8_null_1,NEXUS_5,1.0,en].png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:7e32c7c81e3def45b6df8aa8f1da70012f656a2289f0db562fd5df57c00ca104
-size 38574
+oid sha256:93773786e103f7f02d716906700f7f0e80a1d54d16ab6a31995703673d1df241
+size 38975
diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.login.impl.screens.loginpassword_LoginPasswordView_null_LoginPasswordView-Night-6_8_null_2,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.login.impl.screens.loginpassword_LoginPasswordView_null_LoginPasswordView-Night-6_8_null_2,NEXUS_5,1.0,en].png
index dfadb50fef..15e4d8478d 100644
--- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.login.impl.screens.loginpassword_LoginPasswordView_null_LoginPasswordView-Night-6_8_null_2,NEXUS_5,1.0,en].png
+++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.login.impl.screens.loginpassword_LoginPasswordView_null_LoginPasswordView-Night-6_8_null_2,NEXUS_5,1.0,en].png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:b8a15fc7d605ed1c4ba2bbfa901ca01b44ce0fb5c678be6b5fb484b721f95c87
-size 27410
+oid sha256:0ae46f9ad861a896b8b6d7210908ada04ac387675d333b8528761790555a093d
+size 27467
diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.login.impl.screens.waitlistscreen_WaitListView_null_WaitListView-Day-8_9_null_0,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.login.impl.screens.waitlistscreen_WaitListView_null_WaitListView-Day-8_9_null_0,NEXUS_5,1.0,en].png
index 412475009c..54f60964f3 100644
--- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.login.impl.screens.waitlistscreen_WaitListView_null_WaitListView-Day-8_9_null_0,NEXUS_5,1.0,en].png
+++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.login.impl.screens.waitlistscreen_WaitListView_null_WaitListView-Day-8_9_null_0,NEXUS_5,1.0,en].png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:ce7cb3f4a50912cd7aa96340ff850d438a26e5efc331173c658448fdbecc7b65
-size 145047
+oid sha256:9db077d2e2981e9b3d431312b171741505e22816fa4b2bb3699f6ae4e00b48e9
+size 145160
diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.login.impl.screens.waitlistscreen_WaitListView_null_WaitListView-Day-8_9_null_1,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.login.impl.screens.waitlistscreen_WaitListView_null_WaitListView-Day-8_9_null_1,NEXUS_5,1.0,en].png
index f89a48fbdf..e9fdb0d176 100644
--- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.login.impl.screens.waitlistscreen_WaitListView_null_WaitListView-Day-8_9_null_1,NEXUS_5,1.0,en].png
+++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.login.impl.screens.waitlistscreen_WaitListView_null_WaitListView-Day-8_9_null_1,NEXUS_5,1.0,en].png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:b06c44fcc0afee1a398dbddeb18253f25002c3c8e77929d049edd878b3927e8a
-size 145776
+oid sha256:de09324bd0a41e25eff91ae77d5d88d96289a379ecf24e626fa9ea09a5acd43b
+size 145928
diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.login.impl.screens.waitlistscreen_WaitListView_null_WaitListView-Day-8_9_null_2,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.login.impl.screens.waitlistscreen_WaitListView_null_WaitListView-Day-8_9_null_2,NEXUS_5,1.0,en].png
index f24b59907d..c5b8dcbb18 100644
--- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.login.impl.screens.waitlistscreen_WaitListView_null_WaitListView-Day-8_9_null_2,NEXUS_5,1.0,en].png
+++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.login.impl.screens.waitlistscreen_WaitListView_null_WaitListView-Day-8_9_null_2,NEXUS_5,1.0,en].png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:30a12c0e23d30c5841fef2f705af3fc4ea691ff06425d84a5c33f34809b78d8c
-size 65492
+oid sha256:54f47ca8a687adf5528e5ff8ddd87d901d2aa1280e6252ec962c176d6a207237
+size 65584
diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.login.impl.screens.waitlistscreen_WaitListView_null_WaitListView-Day-8_9_null_3,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.login.impl.screens.waitlistscreen_WaitListView_null_WaitListView-Day-8_9_null_3,NEXUS_5,1.0,en].png
index 412475009c..54f60964f3 100644
--- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.login.impl.screens.waitlistscreen_WaitListView_null_WaitListView-Day-8_9_null_3,NEXUS_5,1.0,en].png
+++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.login.impl.screens.waitlistscreen_WaitListView_null_WaitListView-Day-8_9_null_3,NEXUS_5,1.0,en].png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:ce7cb3f4a50912cd7aa96340ff850d438a26e5efc331173c658448fdbecc7b65
-size 145047
+oid sha256:9db077d2e2981e9b3d431312b171741505e22816fa4b2bb3699f6ae4e00b48e9
+size 145160
diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.login.impl.screens.waitlistscreen_WaitListView_null_WaitListView-Night-8_10_null_0,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.login.impl.screens.waitlistscreen_WaitListView_null_WaitListView-Night-8_10_null_0,NEXUS_5,1.0,en].png
index 412475009c..5bdbb9dbff 100644
--- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.login.impl.screens.waitlistscreen_WaitListView_null_WaitListView-Night-8_10_null_0,NEXUS_5,1.0,en].png
+++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.login.impl.screens.waitlistscreen_WaitListView_null_WaitListView-Night-8_10_null_0,NEXUS_5,1.0,en].png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:ce7cb3f4a50912cd7aa96340ff850d438a26e5efc331173c658448fdbecc7b65
-size 145047
+oid sha256:5d5c0f2cf39d75b09a8cc1f4ffbd65912cab79ce5881ed5da5fdadeb9f57cb00
+size 170070
diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.login.impl.screens.waitlistscreen_WaitListView_null_WaitListView-Night-8_10_null_1,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.login.impl.screens.waitlistscreen_WaitListView_null_WaitListView-Night-8_10_null_1,NEXUS_5,1.0,en].png
index f89a48fbdf..91a55dee0f 100644
--- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.login.impl.screens.waitlistscreen_WaitListView_null_WaitListView-Night-8_10_null_1,NEXUS_5,1.0,en].png
+++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.login.impl.screens.waitlistscreen_WaitListView_null_WaitListView-Night-8_10_null_1,NEXUS_5,1.0,en].png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:b06c44fcc0afee1a398dbddeb18253f25002c3c8e77929d049edd878b3927e8a
-size 145776
+oid sha256:c23b11ebcc1e73255714b07cee27c4583a9923112cdf0eda60983925d8074bb7
+size 170640
diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.login.impl.screens.waitlistscreen_WaitListView_null_WaitListView-Night-8_10_null_2,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.login.impl.screens.waitlistscreen_WaitListView_null_WaitListView-Night-8_10_null_2,NEXUS_5,1.0,en].png
index f6aaba2f2d..17bd0f8204 100644
--- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.login.impl.screens.waitlistscreen_WaitListView_null_WaitListView-Night-8_10_null_2,NEXUS_5,1.0,en].png
+++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.login.impl.screens.waitlistscreen_WaitListView_null_WaitListView-Night-8_10_null_2,NEXUS_5,1.0,en].png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:a6687f1be6e8abab9ae846152cc4edeb5fe1becda4ec9bcf64c255ded9dc937a
-size 63857
+oid sha256:026200b29fb2599e1f04ae19ab75cfed41a8c4aff5b0ef0086a6948244733830
+size 67437
diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.login.impl.screens.waitlistscreen_WaitListView_null_WaitListView-Night-8_10_null_3,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.login.impl.screens.waitlistscreen_WaitListView_null_WaitListView-Night-8_10_null_3,NEXUS_5,1.0,en].png
index 412475009c..5bdbb9dbff 100644
--- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.login.impl.screens.waitlistscreen_WaitListView_null_WaitListView-Night-8_10_null_3,NEXUS_5,1.0,en].png
+++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.login.impl.screens.waitlistscreen_WaitListView_null_WaitListView-Night-8_10_null_3,NEXUS_5,1.0,en].png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:ce7cb3f4a50912cd7aa96340ff850d438a26e5efc331173c658448fdbecc7b65
-size 145047
+oid sha256:5d5c0f2cf39d75b09a8cc1f4ffbd65912cab79ce5881ed5da5fdadeb9f57cb00
+size 170070
diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.login.impl.screens.waitlistscreen_WaitListView_null_WaitListView-Night-8_10_null_4,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.login.impl.screens.waitlistscreen_WaitListView_null_WaitListView-Night-8_10_null_4,NEXUS_5,1.0,en].png
index 220fb6de61..9b7088595f 100644
--- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.login.impl.screens.waitlistscreen_WaitListView_null_WaitListView-Night-8_10_null_4,NEXUS_5,1.0,en].png
+++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.login.impl.screens.waitlistscreen_WaitListView_null_WaitListView-Night-8_10_null_4,NEXUS_5,1.0,en].png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:ddf3e62bd00f179fbeed4e432bd9a7a21321e83dd1d5192e3dc213fcfbc8c372
-size 128199
+oid sha256:97aa5dbc8ddcd05a44ae56771a13085096f11b2469c1a7edb3281e242d86ad21
+size 150264
diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.logout.impl_LogoutView_null_LogoutView-Day-0_1_null_0,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.logout.impl_LogoutView_null_LogoutView-Day-0_1_null_0,NEXUS_5,1.0,en].png
index c930a5e486..a0db2c925d 100644
--- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.logout.impl_LogoutView_null_LogoutView-Day-0_1_null_0,NEXUS_5,1.0,en].png
+++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.logout.impl_LogoutView_null_LogoutView-Day-0_1_null_0,NEXUS_5,1.0,en].png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:78edb2f0cbb3a7c975999aa31f90e5a82e7b73a21f2923e420f364da3c0118fd
-size 13706
+oid sha256:cab6223e7adc7db6f882f563a1398af3815d52e187557d3b7b294f9f4877e4b6
+size 13647
diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.logout.impl_LogoutView_null_LogoutView-Day-0_1_null_1,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.logout.impl_LogoutView_null_LogoutView-Day-0_1_null_1,NEXUS_5,1.0,en].png
index 4bd4efb227..1baec3dd08 100644
--- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.logout.impl_LogoutView_null_LogoutView-Day-0_1_null_1,NEXUS_5,1.0,en].png
+++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.logout.impl_LogoutView_null_LogoutView-Day-0_1_null_1,NEXUS_5,1.0,en].png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:186d3f45a3e8b294e523ede9787563399d97b26d7181ad687afcd8b48f8be506
-size 41247
+oid sha256:644a4f196e60808b48c1a582f5bf8b1930fcca68658b3acdd06c57546bc7ae9d
+size 41107
diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.logout.impl_LogoutView_null_LogoutView-Day-0_1_null_2,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.logout.impl_LogoutView_null_LogoutView-Day-0_1_null_2,NEXUS_5,1.0,en].png
index 99ff03c0d8..61d189a9a0 100644
--- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.logout.impl_LogoutView_null_LogoutView-Day-0_1_null_2,NEXUS_5,1.0,en].png
+++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.logout.impl_LogoutView_null_LogoutView-Day-0_1_null_2,NEXUS_5,1.0,en].png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:6c6252e151e747259945691f9461e4e4d893abd6f048be336df5fb75ff558be7
-size 30679
+oid sha256:bc64a63b73f24ad8ef0d77bd8c6f9a0659d1bcebce238f060bfb56642043c07f
+size 30574
diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.logout.impl_LogoutView_null_LogoutView-Day-0_1_null_3,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.logout.impl_LogoutView_null_LogoutView-Day-0_1_null_3,NEXUS_5,1.0,en].png
index 4bd4efb227..1baec3dd08 100644
--- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.logout.impl_LogoutView_null_LogoutView-Day-0_1_null_3,NEXUS_5,1.0,en].png
+++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.logout.impl_LogoutView_null_LogoutView-Day-0_1_null_3,NEXUS_5,1.0,en].png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:186d3f45a3e8b294e523ede9787563399d97b26d7181ad687afcd8b48f8be506
-size 41247
+oid sha256:644a4f196e60808b48c1a582f5bf8b1930fcca68658b3acdd06c57546bc7ae9d
+size 41107
diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.logout.impl_LogoutView_null_LogoutView-Day-0_1_null_4,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.logout.impl_LogoutView_null_LogoutView-Day-0_1_null_4,NEXUS_5,1.0,en].png
index 4e3d0eab1c..63d1ff7ae8 100644
--- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.logout.impl_LogoutView_null_LogoutView-Day-0_1_null_4,NEXUS_5,1.0,en].png
+++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.logout.impl_LogoutView_null_LogoutView-Day-0_1_null_4,NEXUS_5,1.0,en].png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:2d8dfacb3767fe7e9de7996cd0fb9bcb7f208e49498bfdc7b599546669b7b396
-size 27632
+oid sha256:b87ac5dd5a9a24720a2dc587c16832709401129e3ee71fef60a32213fe7027df
+size 27626
diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.logout.impl_LogoutView_null_LogoutView-Day-0_1_null_5,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.logout.impl_LogoutView_null_LogoutView-Day-0_1_null_5,NEXUS_5,1.0,en].png
index e9f9d8d5db..ca0009bf97 100644
--- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.logout.impl_LogoutView_null_LogoutView-Day-0_1_null_5,NEXUS_5,1.0,en].png
+++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.logout.impl_LogoutView_null_LogoutView-Day-0_1_null_5,NEXUS_5,1.0,en].png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:51528fe646b2ac7f679861af28443b22fe1a710586ac70aa730d98cf7c1e8856
-size 21842
+oid sha256:0c457ab756a8b4edfd32ba3eb4379d96f2393b3e738452990cd284fd1c9782ea
+size 21837
diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.logout.impl_LogoutView_null_LogoutView-Day-0_1_null_6,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.logout.impl_LogoutView_null_LogoutView-Day-0_1_null_6,NEXUS_5,1.0,en].png
index 72f4c9d66e..d00e196535 100644
--- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.logout.impl_LogoutView_null_LogoutView-Day-0_1_null_6,NEXUS_5,1.0,en].png
+++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.logout.impl_LogoutView_null_LogoutView-Day-0_1_null_6,NEXUS_5,1.0,en].png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:47f4ac4fb71f8a4adc3890101244c4ee9fbbf87d0da0e0381a85792b79896a5f
-size 26372
+oid sha256:5a85634f4ee86bde474fb43df2f5583abf573e2c3fc939d815011aae399ed67f
+size 26370
diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.logout.impl_LogoutView_null_LogoutView-Day-0_1_null_7,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.logout.impl_LogoutView_null_LogoutView-Day-0_1_null_7,NEXUS_5,1.0,en].png
index 4e8080e3cf..4997ef394b 100644
--- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.logout.impl_LogoutView_null_LogoutView-Day-0_1_null_7,NEXUS_5,1.0,en].png
+++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.logout.impl_LogoutView_null_LogoutView-Day-0_1_null_7,NEXUS_5,1.0,en].png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:394d3da2d14c0c9438632d54c0999a6ecae9b2ca8cf8bb77986d761d2dfa0a1d
-size 39116
+oid sha256:256f55b114ccfbc7cf464bad2670d02e6e201005d0bfacbafee6e57aff6c3edb
+size 39002
diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.logout.impl_LogoutView_null_LogoutView-Day-0_1_null_8,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.logout.impl_LogoutView_null_LogoutView-Day-0_1_null_8,NEXUS_5,1.0,en].png
index b23d4ec921..e6a0eb8ed8 100644
--- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.logout.impl_LogoutView_null_LogoutView-Day-0_1_null_8,NEXUS_5,1.0,en].png
+++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.logout.impl_LogoutView_null_LogoutView-Day-0_1_null_8,NEXUS_5,1.0,en].png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:87010d4aae66e1030d4b9557e4f065df777324495459c08513040e6793d2d00d
-size 36675
+oid sha256:cb978a661027d7b390fdb2f129b5804246c2de03adbcaa25b94fe3b5339baf3d
+size 36551
diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.logout.impl_LogoutView_null_LogoutView-Day-0_1_null_9,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.logout.impl_LogoutView_null_LogoutView-Day-0_1_null_9,NEXUS_5,1.0,en].png
index 00eb708f14..df32e11ac4 100644
--- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.logout.impl_LogoutView_null_LogoutView-Day-0_1_null_9,NEXUS_5,1.0,en].png
+++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.logout.impl_LogoutView_null_LogoutView-Day-0_1_null_9,NEXUS_5,1.0,en].png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:2c2f057c86716407a4cd3491612f57b9d4b800cf4ef749c2e6dce3e12fbbf632
-size 37972
+oid sha256:de65298c0876e02a818de70cde17140e3526612e2a422eb52c350198a3149219
+size 37854
diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.logout.impl_LogoutView_null_LogoutView-Night-0_2_null_0,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.logout.impl_LogoutView_null_LogoutView-Night-0_2_null_0,NEXUS_5,1.0,en].png
index 5915ad7d40..d4b890a58d 100644
--- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.logout.impl_LogoutView_null_LogoutView-Night-0_2_null_0,NEXUS_5,1.0,en].png
+++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.logout.impl_LogoutView_null_LogoutView-Night-0_2_null_0,NEXUS_5,1.0,en].png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:dd5acfa31ca9994634286aa59bdb67d86e438165296164db82e152cd56868585
-size 13044
+oid sha256:71074dc46126df100436179a90d1488ed39b642d046e19a0bfe2446cb465d188
+size 13005
diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.logout.impl_LogoutView_null_LogoutView-Night-0_2_null_1,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.logout.impl_LogoutView_null_LogoutView-Night-0_2_null_1,NEXUS_5,1.0,en].png
index b28650d35e..a7a4d01916 100644
--- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.logout.impl_LogoutView_null_LogoutView-Night-0_2_null_1,NEXUS_5,1.0,en].png
+++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.logout.impl_LogoutView_null_LogoutView-Night-0_2_null_1,NEXUS_5,1.0,en].png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:49df4ac1a7ec108308b82d0fdb6f0e0d8ca2063960070fa9865562e59774ec21
-size 38623
+oid sha256:552ebfbd3a498b7ce008915846e5f2803450cfd83aa494fa8619a927abbbf7a7
+size 38528
diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.logout.impl_LogoutView_null_LogoutView-Night-0_2_null_2,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.logout.impl_LogoutView_null_LogoutView-Night-0_2_null_2,NEXUS_5,1.0,en].png
index 9fc78733b4..a5e98ce937 100644
--- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.logout.impl_LogoutView_null_LogoutView-Night-0_2_null_2,NEXUS_5,1.0,en].png
+++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.logout.impl_LogoutView_null_LogoutView-Night-0_2_null_2,NEXUS_5,1.0,en].png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:d8406ed0ada582c9436be5937d8cb010f3b4692962e5357c0a919471574aabb3
-size 28958
+oid sha256:5345a21405c403064db7691aff0f0071cb40fe62bc3baeb73b50a5a722bbda31
+size 28893
diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.logout.impl_LogoutView_null_LogoutView-Night-0_2_null_3,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.logout.impl_LogoutView_null_LogoutView-Night-0_2_null_3,NEXUS_5,1.0,en].png
index b28650d35e..a7a4d01916 100644
--- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.logout.impl_LogoutView_null_LogoutView-Night-0_2_null_3,NEXUS_5,1.0,en].png
+++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.logout.impl_LogoutView_null_LogoutView-Night-0_2_null_3,NEXUS_5,1.0,en].png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:49df4ac1a7ec108308b82d0fdb6f0e0d8ca2063960070fa9865562e59774ec21
-size 38623
+oid sha256:552ebfbd3a498b7ce008915846e5f2803450cfd83aa494fa8619a927abbbf7a7
+size 38528
diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.logout.impl_LogoutView_null_LogoutView-Night-0_2_null_4,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.logout.impl_LogoutView_null_LogoutView-Night-0_2_null_4,NEXUS_5,1.0,en].png
index 1906882931..66f14bd622 100644
--- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.logout.impl_LogoutView_null_LogoutView-Night-0_2_null_4,NEXUS_5,1.0,en].png
+++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.logout.impl_LogoutView_null_LogoutView-Night-0_2_null_4,NEXUS_5,1.0,en].png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:51af5a971e3bb5958646ec1866ba41fd4d46e281713573b005bc71b4762ec7b4
-size 24085
+oid sha256:53248519a1ed41bd21902e21b3dabf9ccb91d6e859c4d294ec79a9e417f36c05
+size 24040
diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.logout.impl_LogoutView_null_LogoutView-Night-0_2_null_5,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.logout.impl_LogoutView_null_LogoutView-Night-0_2_null_5,NEXUS_5,1.0,en].png
index 2c7916bd2b..f2368a5ea6 100644
--- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.logout.impl_LogoutView_null_LogoutView-Night-0_2_null_5,NEXUS_5,1.0,en].png
+++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.logout.impl_LogoutView_null_LogoutView-Night-0_2_null_5,NEXUS_5,1.0,en].png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:6efe41b16360b4cfc891a5ffc99ff147ea5c5324341d5f8b8a2f574d360b5aad
-size 19117
+oid sha256:f34078246c32c14414523890609bd52d48cf5d6de6cefc561cccdf3f1531b9d3
+size 19078
diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.logout.impl_LogoutView_null_LogoutView-Night-0_2_null_6,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.logout.impl_LogoutView_null_LogoutView-Night-0_2_null_6,NEXUS_5,1.0,en].png
index 8de5498d31..b0dc94329b 100644
--- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.logout.impl_LogoutView_null_LogoutView-Night-0_2_null_6,NEXUS_5,1.0,en].png
+++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.logout.impl_LogoutView_null_LogoutView-Night-0_2_null_6,NEXUS_5,1.0,en].png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:6a2a05a5d4f528302ca1a6f8bd799418f97d511bb808dadbfe806077ab2a9bab
-size 22756
+oid sha256:9cb1578b4f6f11f395aa93c6e3a091f71d5ebf020477ddbfa4ebb70a70b9bde8
+size 22724
diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.logout.impl_LogoutView_null_LogoutView-Night-0_2_null_7,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.logout.impl_LogoutView_null_LogoutView-Night-0_2_null_7,NEXUS_5,1.0,en].png
index 968ebc3569..e8aa9de326 100644
--- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.logout.impl_LogoutView_null_LogoutView-Night-0_2_null_7,NEXUS_5,1.0,en].png
+++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.logout.impl_LogoutView_null_LogoutView-Night-0_2_null_7,NEXUS_5,1.0,en].png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:b923a90e9e8f4c16aac3afdda71b60c52db6ab6a08d046be49c9c7a1e91277c0
-size 37107
+oid sha256:fc8e0ed5cd39c3118062931c9735324c84e28f0a0a80f4abd6de8ba1d33093dc
+size 37054
diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.logout.impl_LogoutView_null_LogoutView-Night-0_2_null_8,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.logout.impl_LogoutView_null_LogoutView-Night-0_2_null_8,NEXUS_5,1.0,en].png
index b61e420d85..821f87b9cf 100644
--- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.logout.impl_LogoutView_null_LogoutView-Night-0_2_null_8,NEXUS_5,1.0,en].png
+++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.logout.impl_LogoutView_null_LogoutView-Night-0_2_null_8,NEXUS_5,1.0,en].png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:3961ac676e29ac3d6f8dede3aed1c0c22d400e6a95ca8c4333691102f1616c42
-size 34922
+oid sha256:9d2b0f5732d4eaea745050d8f3aaa0c893aba732746bfa894924a8d10d4ffd15
+size 34824
diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.logout.impl_LogoutView_null_LogoutView-Night-0_2_null_9,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.logout.impl_LogoutView_null_LogoutView-Night-0_2_null_9,NEXUS_5,1.0,en].png
index 3a2db9c9ab..d5b7cf0706 100644
--- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.logout.impl_LogoutView_null_LogoutView-Night-0_2_null_9,NEXUS_5,1.0,en].png
+++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.logout.impl_LogoutView_null_LogoutView-Night-0_2_null_9,NEXUS_5,1.0,en].png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:52bf6e6334dd36e2e39f6957a60c7d54839caffdf47a32a0bb463124fc2c27d4
-size 35820
+oid sha256:ee04bbd259ccc5d3a8accf8db7a8ea76b89a2a489159839b655636e9bf807cd4
+size 35721
diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.typing_MessagesViewWithTyping_null_MessagesViewWithTyping-Day-59_59_null,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.typing_MessagesViewWithTyping_null_MessagesViewWithTyping-Day-59_59_null,NEXUS_5,1.0,en].png
new file mode 100644
index 0000000000..9e5eb38198
--- /dev/null
+++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.typing_MessagesViewWithTyping_null_MessagesViewWithTyping-Day-59_59_null,NEXUS_5,1.0,en].png
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:0dda5041c16d690fe8e0c13aaca813a06acbcee8e9ab6268256ad8925defe5d0
+size 55428
diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.typing_MessagesViewWithTyping_null_MessagesViewWithTyping-Night-59_60_null,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.typing_MessagesViewWithTyping_null_MessagesViewWithTyping-Night-59_60_null,NEXUS_5,1.0,en].png
new file mode 100644
index 0000000000..aeb62038c2
--- /dev/null
+++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.typing_MessagesViewWithTyping_null_MessagesViewWithTyping-Night-59_60_null,NEXUS_5,1.0,en].png
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:6946a2d952a72e29aaa54543ce0e8a73b7ab7c6db2c6fd23ac833fa7f61f8425
+size 54141
diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.typing_TypingNotificationView_null_TypingNotificationView-Day-60_60_null_0,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.typing_TypingNotificationView_null_TypingNotificationView-Day-60_60_null_0,NEXUS_5,1.0,en].png
new file mode 100644
index 0000000000..665c8811ac
--- /dev/null
+++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.typing_TypingNotificationView_null_TypingNotificationView-Day-60_60_null_0,NEXUS_5,1.0,en].png
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:bb0d3bfcfd75cbd75fd9270ff1dc27090e5dbac79ca8db8a46d91a4c12bc966b
+size 4457
diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.typing_TypingNotificationView_null_TypingNotificationView-Day-60_60_null_1,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.typing_TypingNotificationView_null_TypingNotificationView-Day-60_60_null_1,NEXUS_5,1.0,en].png
new file mode 100644
index 0000000000..ae320c8dbc
--- /dev/null
+++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.typing_TypingNotificationView_null_TypingNotificationView-Day-60_60_null_1,NEXUS_5,1.0,en].png
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:ff84eecce0c3e489e0596c524a361e277679fc0f6b1c3f3011e50bb666074574
+size 8953
diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.typing_TypingNotificationView_null_TypingNotificationView-Day-60_60_null_2,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.typing_TypingNotificationView_null_TypingNotificationView-Day-60_60_null_2,NEXUS_5,1.0,en].png
new file mode 100644
index 0000000000..5b271ff6fb
--- /dev/null
+++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.typing_TypingNotificationView_null_TypingNotificationView-Day-60_60_null_2,NEXUS_5,1.0,en].png
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:c46396fd61ca8188bf3ea7745dee0456f3f944c2a1fcbf04402cfb1127d8bbef
+size 6856
diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.typing_TypingNotificationView_null_TypingNotificationView-Day-60_60_null_3,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.typing_TypingNotificationView_null_TypingNotificationView-Day-60_60_null_3,NEXUS_5,1.0,en].png
new file mode 100644
index 0000000000..45e0208327
--- /dev/null
+++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.typing_TypingNotificationView_null_TypingNotificationView-Day-60_60_null_3,NEXUS_5,1.0,en].png
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:272038adab5288f287dcf81c815de34945092ca20c67dad15b7e0a3715663be4
+size 9932
diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.typing_TypingNotificationView_null_TypingNotificationView-Day-60_60_null_4,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.typing_TypingNotificationView_null_TypingNotificationView-Day-60_60_null_4,NEXUS_5,1.0,en].png
new file mode 100644
index 0000000000..fc071c13d3
--- /dev/null
+++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.typing_TypingNotificationView_null_TypingNotificationView-Day-60_60_null_4,NEXUS_5,1.0,en].png
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:3200b2363f50db05157314f5c5d9d491ffb51860e66ffe28bd4c024b6857dda0
+size 8161
diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.typing_TypingNotificationView_null_TypingNotificationView-Day-60_60_null_5,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.typing_TypingNotificationView_null_TypingNotificationView-Day-60_60_null_5,NEXUS_5,1.0,en].png
new file mode 100644
index 0000000000..39402506e6
--- /dev/null
+++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.typing_TypingNotificationView_null_TypingNotificationView-Day-60_60_null_5,NEXUS_5,1.0,en].png
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:3409d9e8e10bae9e90f2f9088897261619ecd8d0e6e32441671396d50fed8ac0
+size 8940
diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.typing_TypingNotificationView_null_TypingNotificationView-Day-60_60_null_6,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.typing_TypingNotificationView_null_TypingNotificationView-Day-60_60_null_6,NEXUS_5,1.0,en].png
new file mode 100644
index 0000000000..f4281d3fe3
--- /dev/null
+++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.typing_TypingNotificationView_null_TypingNotificationView-Day-60_60_null_6,NEXUS_5,1.0,en].png
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:0ca0ccfd706c8dca696481f7d1f60de83ed15435b1096c46d9dc79e21573817b
+size 9265
diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.typing_TypingNotificationView_null_TypingNotificationView-Day-60_60_null_7,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.typing_TypingNotificationView_null_TypingNotificationView-Day-60_60_null_7,NEXUS_5,1.0,en].png
new file mode 100644
index 0000000000..919be03513
--- /dev/null
+++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.typing_TypingNotificationView_null_TypingNotificationView-Day-60_60_null_7,NEXUS_5,1.0,en].png
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:18f8d2c5c872598293ac759a074e88ba38062e54ca9348a12aff62f3d91c34f4
+size 11149
diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.typing_TypingNotificationView_null_TypingNotificationView-Night-60_61_null_0,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.typing_TypingNotificationView_null_TypingNotificationView-Night-60_61_null_0,NEXUS_5,1.0,en].png
new file mode 100644
index 0000000000..fae8a6fca3
--- /dev/null
+++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.typing_TypingNotificationView_null_TypingNotificationView-Night-60_61_null_0,NEXUS_5,1.0,en].png
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:8c89ac73df77c2bccb0c2aa80cee1420f78e7d07f0eda89a90bffef55e8cf753
+size 4464
diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.typing_TypingNotificationView_null_TypingNotificationView-Night-60_61_null_1,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.typing_TypingNotificationView_null_TypingNotificationView-Night-60_61_null_1,NEXUS_5,1.0,en].png
new file mode 100644
index 0000000000..3e8ac12a44
--- /dev/null
+++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.typing_TypingNotificationView_null_TypingNotificationView-Night-60_61_null_1,NEXUS_5,1.0,en].png
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:f5c002a4929aa725cf22ca46840ff3374efe4c4e1757e3b76c3a064911525ce6
+size 8875
diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.typing_TypingNotificationView_null_TypingNotificationView-Night-60_61_null_2,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.typing_TypingNotificationView_null_TypingNotificationView-Night-60_61_null_2,NEXUS_5,1.0,en].png
new file mode 100644
index 0000000000..a4bb07b2ab
--- /dev/null
+++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.typing_TypingNotificationView_null_TypingNotificationView-Night-60_61_null_2,NEXUS_5,1.0,en].png
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:a227b3aca2f20d895c483ca72e3c3b49a3b6263e01f10cd59dda7147f750ecc8
+size 6840
diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.typing_TypingNotificationView_null_TypingNotificationView-Night-60_61_null_3,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.typing_TypingNotificationView_null_TypingNotificationView-Night-60_61_null_3,NEXUS_5,1.0,en].png
new file mode 100644
index 0000000000..1e529c35db
--- /dev/null
+++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.typing_TypingNotificationView_null_TypingNotificationView-Night-60_61_null_3,NEXUS_5,1.0,en].png
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:b2d151892e95c633ef8bd6960f32eca0e00b2ddbcaba01cbca830fea356471f9
+size 9877
diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.typing_TypingNotificationView_null_TypingNotificationView-Night-60_61_null_4,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.typing_TypingNotificationView_null_TypingNotificationView-Night-60_61_null_4,NEXUS_5,1.0,en].png
new file mode 100644
index 0000000000..83ead64bd3
--- /dev/null
+++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.typing_TypingNotificationView_null_TypingNotificationView-Night-60_61_null_4,NEXUS_5,1.0,en].png
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:f3e0ec1f6946fa12c56d17f7ff72e7fca50ad52e41864b0351a36842a220df02
+size 8093
diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.typing_TypingNotificationView_null_TypingNotificationView-Night-60_61_null_5,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.typing_TypingNotificationView_null_TypingNotificationView-Night-60_61_null_5,NEXUS_5,1.0,en].png
new file mode 100644
index 0000000000..dc9eb04e55
--- /dev/null
+++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.typing_TypingNotificationView_null_TypingNotificationView-Night-60_61_null_5,NEXUS_5,1.0,en].png
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:59ed8a9b93f09875de225096a7c7c044840c603c31e0f525522f5be13fa116a8
+size 8786
diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.typing_TypingNotificationView_null_TypingNotificationView-Night-60_61_null_6,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.typing_TypingNotificationView_null_TypingNotificationView-Night-60_61_null_6,NEXUS_5,1.0,en].png
new file mode 100644
index 0000000000..4819f10183
--- /dev/null
+++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.typing_TypingNotificationView_null_TypingNotificationView-Night-60_61_null_6,NEXUS_5,1.0,en].png
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:32087f3ad5e63e8075d2b981881ba36e7fb36464a10b3d7506ed1cf6d00c2e3d
+size 9106
diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.typing_TypingNotificationView_null_TypingNotificationView-Night-60_61_null_7,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.typing_TypingNotificationView_null_TypingNotificationView-Night-60_61_null_7,NEXUS_5,1.0,en].png
new file mode 100644
index 0000000000..4540dee44e
--- /dev/null
+++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.typing_TypingNotificationView_null_TypingNotificationView-Night-60_61_null_7,NEXUS_5,1.0,en].png
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:833aa5ba2891ca8a0f81534ca2b36b6971dc851a2842507b1ae3f2f5b701961f
+size 11004
diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.onboarding.impl_OnBoardingScreen_null_OnBoardingScreen-Day-0_1_null_0,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.onboarding.impl_OnBoardingScreen_null_OnBoardingScreen-Day-0_1_null_0,NEXUS_5,1.0,en].png
index 1618c3e638..10061b344b 100644
--- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.onboarding.impl_OnBoardingScreen_null_OnBoardingScreen-Day-0_1_null_0,NEXUS_5,1.0,en].png
+++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.onboarding.impl_OnBoardingScreen_null_OnBoardingScreen-Day-0_1_null_0,NEXUS_5,1.0,en].png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:4595089f2c885b73cdbd79d626c3eab79da657fef1a2ce2390e761e2469a4e0b
-size 313738
+oid sha256:380998b59449eeba94f716a5295a003f7fbafc43a79b55d42c8105526dde0d63
+size 316491
diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.onboarding.impl_OnBoardingScreen_null_OnBoardingScreen-Day-0_1_null_1,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.onboarding.impl_OnBoardingScreen_null_OnBoardingScreen-Day-0_1_null_1,NEXUS_5,1.0,en].png
index df970a3ce3..f87365fb1a 100644
--- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.onboarding.impl_OnBoardingScreen_null_OnBoardingScreen-Day-0_1_null_1,NEXUS_5,1.0,en].png
+++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.onboarding.impl_OnBoardingScreen_null_OnBoardingScreen-Day-0_1_null_1,NEXUS_5,1.0,en].png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:452876b1189da12691bca146c63202324593c791e854a1f8918a71c556a2c454
-size 305809
+oid sha256:984a1146d31e908a9945719926cdbaa07811e8cf9d0a9dfa042041bed4f2769c
+size 311287
diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.onboarding.impl_OnBoardingScreen_null_OnBoardingScreen-Day-0_1_null_2,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.onboarding.impl_OnBoardingScreen_null_OnBoardingScreen-Day-0_1_null_2,NEXUS_5,1.0,en].png
index ac4bd00348..119e802731 100644
--- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.onboarding.impl_OnBoardingScreen_null_OnBoardingScreen-Day-0_1_null_2,NEXUS_5,1.0,en].png
+++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.onboarding.impl_OnBoardingScreen_null_OnBoardingScreen-Day-0_1_null_2,NEXUS_5,1.0,en].png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:f496246dd0186280943dbf3057956eef19fdfd64ccd8458c49edb32cb97f24d3
-size 315968
+oid sha256:a3eaf72d0716767f7acb7a796353138034f9234da86a7762d415b5edb6fb3ae5
+size 317991
diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.onboarding.impl_OnBoardingScreen_null_OnBoardingScreen-Day-0_1_null_3,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.onboarding.impl_OnBoardingScreen_null_OnBoardingScreen-Day-0_1_null_3,NEXUS_5,1.0,en].png
index 254fa69e4f..5de0fcb890 100644
--- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.onboarding.impl_OnBoardingScreen_null_OnBoardingScreen-Day-0_1_null_3,NEXUS_5,1.0,en].png
+++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.onboarding.impl_OnBoardingScreen_null_OnBoardingScreen-Day-0_1_null_3,NEXUS_5,1.0,en].png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:a127838495bdd790e1eeb6632d9fcfb256edd8ebe5d83f222434458b9687679c
-size 307141
+oid sha256:17d055188d8548d847c991f4eb4e944c682a569a59eb8b34dc0a46787c803f26
+size 311514
diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.onboarding.impl_OnBoardingScreen_null_OnBoardingScreen-Day-0_1_null_4,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.onboarding.impl_OnBoardingScreen_null_OnBoardingScreen-Day-0_1_null_4,NEXUS_5,1.0,en].png
index 148df5143d..0ff4445f75 100644
--- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.onboarding.impl_OnBoardingScreen_null_OnBoardingScreen-Day-0_1_null_4,NEXUS_5,1.0,en].png
+++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.onboarding.impl_OnBoardingScreen_null_OnBoardingScreen-Day-0_1_null_4,NEXUS_5,1.0,en].png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:c5c86f4f08460382392eb9404fecdc93b6ff056e0d4116f39fc6308d1061c163
-size 314537
+oid sha256:8b0feb213813e17ffef6a1a4c58bb14056ac28b953fc8ab38f47d27c15270230
+size 317281
diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.onboarding.impl_OnBoardingScreen_null_OnBoardingScreen-Night-0_2_null_0,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.onboarding.impl_OnBoardingScreen_null_OnBoardingScreen-Night-0_2_null_0,NEXUS_5,1.0,en].png
index 7cd11d4937..04064b98f7 100644
--- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.onboarding.impl_OnBoardingScreen_null_OnBoardingScreen-Night-0_2_null_0,NEXUS_5,1.0,en].png
+++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.onboarding.impl_OnBoardingScreen_null_OnBoardingScreen-Night-0_2_null_0,NEXUS_5,1.0,en].png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:9df131c8d7482b7b00df587cca8b385d0cd57954240368f349a24e8e6ae36322
-size 405021
+oid sha256:f9d815ff280835ec6ed5cf43ef61711a079142c1024b5b6597595ceb9b57552b
+size 410811
diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.onboarding.impl_OnBoardingScreen_null_OnBoardingScreen-Night-0_2_null_1,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.onboarding.impl_OnBoardingScreen_null_OnBoardingScreen-Night-0_2_null_1,NEXUS_5,1.0,en].png
index b5ca95ff71..7958c0afb7 100644
--- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.onboarding.impl_OnBoardingScreen_null_OnBoardingScreen-Night-0_2_null_1,NEXUS_5,1.0,en].png
+++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.onboarding.impl_OnBoardingScreen_null_OnBoardingScreen-Night-0_2_null_1,NEXUS_5,1.0,en].png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:d5070637e034d7ecc1db4944cb05ec056e0cbea342769a32ee030b47110f8e4b
-size 386301
+oid sha256:dd31e46ae32037a519030d1264bdb923208ea0b0d4f27f1072d5923618b67b9b
+size 396666
diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.onboarding.impl_OnBoardingScreen_null_OnBoardingScreen-Night-0_2_null_2,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.onboarding.impl_OnBoardingScreen_null_OnBoardingScreen-Night-0_2_null_2,NEXUS_5,1.0,en].png
index a6d71eb418..a5ab2c2a95 100644
--- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.onboarding.impl_OnBoardingScreen_null_OnBoardingScreen-Night-0_2_null_2,NEXUS_5,1.0,en].png
+++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.onboarding.impl_OnBoardingScreen_null_OnBoardingScreen-Night-0_2_null_2,NEXUS_5,1.0,en].png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:662e5beadd1baea7825ce047df87c4429f720ea7b4dd53f8ea576ada91814568
-size 399093
+oid sha256:18a918db52e87b21312b888e74732ad9483b5edd1b5fa3f82471ab7739a12618
+size 403275
diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.onboarding.impl_OnBoardingScreen_null_OnBoardingScreen-Night-0_2_null_3,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.onboarding.impl_OnBoardingScreen_null_OnBoardingScreen-Night-0_2_null_3,NEXUS_5,1.0,en].png
index 8791e1399c..f3a5fda140 100644
--- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.onboarding.impl_OnBoardingScreen_null_OnBoardingScreen-Night-0_2_null_3,NEXUS_5,1.0,en].png
+++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.onboarding.impl_OnBoardingScreen_null_OnBoardingScreen-Night-0_2_null_3,NEXUS_5,1.0,en].png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:3a76b73d9e5e94b8dd8b27addd07593bae43423b92048110b213413e1185100e
-size 373027
+oid sha256:35c7dbdebc92344948be74a22d171827aba09bf93b8150a96469fcf31b01ab35
+size 381498
diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.onboarding.impl_OnBoardingScreen_null_OnBoardingScreen-Night-0_2_null_4,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.onboarding.impl_OnBoardingScreen_null_OnBoardingScreen-Night-0_2_null_4,NEXUS_5,1.0,en].png
index 36442edf97..768132db23 100644
--- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.onboarding.impl_OnBoardingScreen_null_OnBoardingScreen-Night-0_2_null_4,NEXUS_5,1.0,en].png
+++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.onboarding.impl_OnBoardingScreen_null_OnBoardingScreen-Night-0_2_null_4,NEXUS_5,1.0,en].png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:d1a672fea8d9f8b6a1c9646982438bf3dc66874a472c0c2269d74fccffed3a98
-size 405810
+oid sha256:601c93ac65d44b65e72cf99c2885ff76c5a1442fb67213622d0bd174d9b34146
+size 411641
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 da1d8ddbfd..99f1da2d6f 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:da3f8614862ddacfd9b54afcd3bf091bec335e1489d7cbffc826059a89ae5478
-size 58453
+oid sha256:41d892f8a97bb9d89d6a6128c7acae4d5c509dadee0e1758c7fec9d76bc4216d
+size 56386
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 c99349ac0c..0cee409bf8 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:1fd599f2e93432d5d5555f086b60059e84452a0da3c2a69d932042b7ee4d3bac
-size 57922
+oid sha256:478e8c2d3dd29baf88f2641813760c623631d53446f31bca2f1372c05d4ca914
+size 55856
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 b228d561bd..7366bd20c2 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:9e9641228e0482c8e5500bb999b180e79cbfcb6a13e121f3be68aae5c58a6839
-size 57953
+oid sha256:6e174f5f0b15343f5f02cc716cb371aa89d87e298104ac8e5df83bdab2db573d
+size 55887
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 3df61a1ef4..7ba5c4b13b 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:1c1c5b00098e5860d4c69ef9a652483ea1192d9fa10f5449fb817769ab054183
-size 36128
+oid sha256:d044628791909fdb8f621b3693cb63726e6a1dbc1fd6e12e1b3a4e3c9be1e868
+size 36288
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 50da3b5d6c..bfc79dca12 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:4fe6625641cf06c45a817e9d10bc0d7296aa59160fc5a3e9dc28304e5b794125
-size 57943
+oid sha256:62762b55b56ee307e15a2aa488e8426714771d6e9d76d68ee82185b3420a348f
+size 55831
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 47fbdb6c0f..7324db05b6 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:e85b252d0d6c166f987974ebcf9a6b58b924316733b868ad0ed5a61413bda381
-size 54577
+oid sha256:923619c9af298ce1a250c5094429b6b820b560c62a55ec8baa40144478e42358
+size 53102
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 10d7a6c5e1..b1a1b5e134 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:4f246ce9f60b25d9739d73e2aed98132dfb3a0a694acbf320ff796f35f805fdc
-size 54273
+oid sha256:1125869fdf539f15103bef1a380e46af9b56c44262a1986009099e2700206038
+size 52799
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 4b03ace56b..6b82d8a9ff 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:d0403a4bb8da3d36922cb5362977af9b3052624525def05e5236f4f922384c31
-size 54297
+oid sha256:ecee6cd60257a931f717c8ae23f256ded8dd6ac8fa7af7430082c6a3f837b274
+size 52821
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 01e0e907a6..5f4b3fa5fc 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:824774a1e19974090de4cb32e06a7f984b5db238c3dc8d04a35d3457e647ac84
-size 31999
+oid sha256:8449c20314175d6e829df65b2b1ba3cf36944a679b2e360ee5d2ed4d8333ad07
+size 32149
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 449fb69524..fbe1510225 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:c0820b462a0dc103b66aef78528ae5ce13a55e2614a7a197e06713366c422893
-size 54313
+oid sha256:5c38a6f66d48174c6e2b3ac8525906cd371030f15ac3ca8727a8ca83f528916e
+size 52823
diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.rageshake.impl.bugreport_BugReportView_null_BugReportView-Day-0_1_null_0,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.rageshake.impl.bugreport_BugReportView_null_BugReportView-Day-0_1_null_0,NEXUS_5,1.0,en].png
index 1c8b28b5ad..ad82505d3e 100644
--- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.rageshake.impl.bugreport_BugReportView_null_BugReportView-Day-0_1_null_0,NEXUS_5,1.0,en].png
+++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.rageshake.impl.bugreport_BugReportView_null_BugReportView-Day-0_1_null_0,NEXUS_5,1.0,en].png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:b80e48cadbb6e76fc6675eb0a2c49d6495be6a8145d649ad90c2bce10e8695a6
-size 72701
+oid sha256:96172e8f6a0283ae1abde6eac27d2ce5fde9e74f20ad89bfb2bb188a2f474fe3
+size 73080
diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.rageshake.impl.bugreport_BugReportView_null_BugReportView-Day-0_1_null_3,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.rageshake.impl.bugreport_BugReportView_null_BugReportView-Day-0_1_null_3,NEXUS_5,1.0,en].png
index 1c8b28b5ad..ad82505d3e 100644
--- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.rageshake.impl.bugreport_BugReportView_null_BugReportView-Day-0_1_null_3,NEXUS_5,1.0,en].png
+++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.rageshake.impl.bugreport_BugReportView_null_BugReportView-Day-0_1_null_3,NEXUS_5,1.0,en].png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:b80e48cadbb6e76fc6675eb0a2c49d6495be6a8145d649ad90c2bce10e8695a6
-size 72701
+oid sha256:96172e8f6a0283ae1abde6eac27d2ce5fde9e74f20ad89bfb2bb188a2f474fe3
+size 73080
diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.rageshake.impl.bugreport_BugReportView_null_BugReportView-Day-0_1_null_4,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.rageshake.impl.bugreport_BugReportView_null_BugReportView-Day-0_1_null_4,NEXUS_5,1.0,en].png
new file mode 100644
index 0000000000..ee76b9944b
--- /dev/null
+++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.rageshake.impl.bugreport_BugReportView_null_BugReportView-Day-0_1_null_4,NEXUS_5,1.0,en].png
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:53089b8e5b88e494ef1565e6b9e759f46cd26b1b3f786221dcc047af31835daf
+size 55195
diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.rageshake.impl.bugreport_BugReportView_null_BugReportView-Night-0_2_null_0,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.rageshake.impl.bugreport_BugReportView_null_BugReportView-Night-0_2_null_0,NEXUS_5,1.0,en].png
index 6ae1a1f2ed..ce0d1a50fb 100644
--- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.rageshake.impl.bugreport_BugReportView_null_BugReportView-Night-0_2_null_0,NEXUS_5,1.0,en].png
+++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.rageshake.impl.bugreport_BugReportView_null_BugReportView-Night-0_2_null_0,NEXUS_5,1.0,en].png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:7696307abd3ca96ae3c036cbf3088c2be08b4e4aabb861b0c7472460ab795303
-size 69558
+oid sha256:2eb33de5998edbdb79ff57b39dddcc7aecdd588613c9f5706fecd7b3f668a3a2
+size 69971
diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.rageshake.impl.bugreport_BugReportView_null_BugReportView-Night-0_2_null_3,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.rageshake.impl.bugreport_BugReportView_null_BugReportView-Night-0_2_null_3,NEXUS_5,1.0,en].png
index 6ae1a1f2ed..ce0d1a50fb 100644
--- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.rageshake.impl.bugreport_BugReportView_null_BugReportView-Night-0_2_null_3,NEXUS_5,1.0,en].png
+++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.rageshake.impl.bugreport_BugReportView_null_BugReportView-Night-0_2_null_3,NEXUS_5,1.0,en].png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:7696307abd3ca96ae3c036cbf3088c2be08b4e4aabb861b0c7472460ab795303
-size 69558
+oid sha256:2eb33de5998edbdb79ff57b39dddcc7aecdd588613c9f5706fecd7b3f668a3a2
+size 69971
diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.rageshake.impl.bugreport_BugReportView_null_BugReportView-Night-0_2_null_4,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.rageshake.impl.bugreport_BugReportView_null_BugReportView-Night-0_2_null_4,NEXUS_5,1.0,en].png
new file mode 100644
index 0000000000..8084317ee1
--- /dev/null
+++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.rageshake.impl.bugreport_BugReportView_null_BugReportView-Night-0_2_null_4,NEXUS_5,1.0,en].png
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:8fbef7e43158f49adcaf30447443deb39f5980b0970eab79874d2a7a8dbca563
+size 49958
diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.ftue.impl.migration_MigrationView_null_MigrationView-Day-0_1_null,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.migration_MigrationView_null_MigrationView-Day-10_11_null,NEXUS_5,1.0,en].png
similarity index 100%
rename from tests/uitests/src/test/snapshots/images/ui_S_t[f.ftue.impl.migration_MigrationView_null_MigrationView-Day-0_1_null,NEXUS_5,1.0,en].png
rename to tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.migration_MigrationView_null_MigrationView-Day-10_11_null,NEXUS_5,1.0,en].png
diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.migration_MigrationView_null_MigrationView-Night-10_12_null,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.migration_MigrationView_null_MigrationView-Night-10_12_null,NEXUS_5,1.0,en].png
new file mode 100644
index 0000000000..46a349cbce
--- /dev/null
+++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.migration_MigrationView_null_MigrationView-Night-10_12_null,NEXUS_5,1.0,en].png
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:fea824bf7f4c74c827fa3c1fa892b9beeb9d11e0863fc9e5c104c725236c7d10
+size 156506
diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.search_RoomListSearchResultContent_null_RoomListSearchResultContent-Day-10_11_null,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.search_RoomListSearchResultContent_null_RoomListSearchResultContent-Day-11_12_null,NEXUS_5,1.0,en].png
similarity index 100%
rename from tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.search_RoomListSearchResultContent_null_RoomListSearchResultContent-Day-10_11_null,NEXUS_5,1.0,en].png
rename to tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.search_RoomListSearchResultContent_null_RoomListSearchResultContent-Day-11_12_null,NEXUS_5,1.0,en].png
diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.search_RoomListSearchResultContent_null_RoomListSearchResultContent-Night-10_12_null,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.search_RoomListSearchResultContent_null_RoomListSearchResultContent-Night-11_13_null,NEXUS_5,1.0,en].png
similarity index 100%
rename from tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.search_RoomListSearchResultContent_null_RoomListSearchResultContent-Night-10_12_null,NEXUS_5,1.0,en].png
rename to tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.search_RoomListSearchResultContent_null_RoomListSearchResultContent-Night-11_13_null,NEXUS_5,1.0,en].png
diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl_RoomListModalBottomSheetContentForDm_null_RoomListModalBottomSheetContentForDm-Day-2_3_null,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl_RoomListModalBottomSheetContentForDm_null_RoomListModalBottomSheetContentForDm-Day-2_3_null,NEXUS_5,1.0,en].png
index d5a64e473f..111f5427d6 100644
--- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl_RoomListModalBottomSheetContentForDm_null_RoomListModalBottomSheetContentForDm-Day-2_3_null,NEXUS_5,1.0,en].png
+++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl_RoomListModalBottomSheetContentForDm_null_RoomListModalBottomSheetContentForDm-Day-2_3_null,NEXUS_5,1.0,en].png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:1bd5f590fd30facfb007050c26aa567d568ab0d797a27986b6f88a23af76f9dc
-size 14167
+oid sha256:547fe148039b4f0c4e84897af1b950d372ddb6aa5d0d79b53ca05fbc7fbdc11f
+size 17388
diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl_RoomListModalBottomSheetContentForDm_null_RoomListModalBottomSheetContentForDm-Night-2_4_null,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl_RoomListModalBottomSheetContentForDm_null_RoomListModalBottomSheetContentForDm-Night-2_4_null,NEXUS_5,1.0,en].png
index 1d1319d036..5585832f27 100644
--- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl_RoomListModalBottomSheetContentForDm_null_RoomListModalBottomSheetContentForDm-Night-2_4_null,NEXUS_5,1.0,en].png
+++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl_RoomListModalBottomSheetContentForDm_null_RoomListModalBottomSheetContentForDm-Night-2_4_null,NEXUS_5,1.0,en].png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:e609d908d159cffdc2a17ac8944413dbb52e5cd1ebdd2bd30057dc9865749bd6
-size 13369
+oid sha256:2c603ba7cecfbb554b2c1c64bfba76f5c97d1c58c3adbbe69fb944592abca54a
+size 16287
diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl_RoomListModalBottomSheetContent_null_RoomListModalBottomSheetContent-Day-1_2_null,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl_RoomListModalBottomSheetContent_null_RoomListModalBottomSheetContent-Day-1_2_null,NEXUS_5,1.0,en].png
index 6e7ba7e325..1f28bb6439 100644
--- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl_RoomListModalBottomSheetContent_null_RoomListModalBottomSheetContent-Day-1_2_null,NEXUS_5,1.0,en].png
+++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl_RoomListModalBottomSheetContent_null_RoomListModalBottomSheetContent-Day-1_2_null,NEXUS_5,1.0,en].png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:5c7e78d4f8fd595922f4bdce5263bf9c5cf7094df5edb9a0e9d35fe270b21d23
-size 12541
+oid sha256:b142adcfc92ed9ddca5c8ec788c610b11296c128a577e5766ef1b10aa6a216cb
+size 15550
diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl_RoomListModalBottomSheetContent_null_RoomListModalBottomSheetContent-Night-1_3_null,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl_RoomListModalBottomSheetContent_null_RoomListModalBottomSheetContent-Night-1_3_null,NEXUS_5,1.0,en].png
index a6395dcbd7..f8de05de07 100644
--- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl_RoomListModalBottomSheetContent_null_RoomListModalBottomSheetContent-Night-1_3_null,NEXUS_5,1.0,en].png
+++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl_RoomListModalBottomSheetContent_null_RoomListModalBottomSheetContent-Night-1_3_null,NEXUS_5,1.0,en].png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:715154a104ef257a1865be35775cc7223e7adf3494863e0d24f1f1a8c7129920
-size 11888
+oid sha256:f898bbf9dd2cc11c594261f08682d8cebaefe1b9d8e526793c6f23a51d0f696b
+size 14560
diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl_RoomListView_null_RoomListView-Day-3_4_null_10,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl_RoomListView_null_RoomListView-Day-3_4_null_10,NEXUS_5,1.0,en].png
new file mode 100644
index 0000000000..15095f8707
--- /dev/null
+++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl_RoomListView_null_RoomListView-Day-3_4_null_10,NEXUS_5,1.0,en].png
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:7f0dfd19b21ff2ba1fdbb423578f71e4d28a01d84bc7e1a41a1027b1b2d09db3
+size 55268
diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl_RoomListView_null_RoomListView-Day-3_4_null_11,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl_RoomListView_null_RoomListView-Day-3_4_null_11,NEXUS_5,1.0,en].png
new file mode 100644
index 0000000000..cc18d97b3a
--- /dev/null
+++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl_RoomListView_null_RoomListView-Day-3_4_null_11,NEXUS_5,1.0,en].png
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:a2fb4ca138fefc4d4c4e09d3c1c403bea3f54aa226bba6a836711f21093e06b6
+size 51707
diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl_RoomListView_null_RoomListView-Day-3_4_null_12,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl_RoomListView_null_RoomListView-Day-3_4_null_12,NEXUS_5,1.0,en].png
new file mode 100644
index 0000000000..f901e915e5
--- /dev/null
+++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl_RoomListView_null_RoomListView-Day-3_4_null_12,NEXUS_5,1.0,en].png
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:64c4eb481f40871925405ae317cb80927caf31cb552a8aa9549bfb5658ca91e4
+size 137589
diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl_RoomListView_null_RoomListView-Night-3_5_null_10,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl_RoomListView_null_RoomListView-Night-3_5_null_10,NEXUS_5,1.0,en].png
new file mode 100644
index 0000000000..3b31d08513
--- /dev/null
+++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl_RoomListView_null_RoomListView-Night-3_5_null_10,NEXUS_5,1.0,en].png
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:5ab5f276868ad19ac4c5f6bbce92286bd6a846c77b91cb8c76d12a9d6aeca31c
+size 57171
diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl_RoomListView_null_RoomListView-Night-3_5_null_11,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl_RoomListView_null_RoomListView-Night-3_5_null_11,NEXUS_5,1.0,en].png
new file mode 100644
index 0000000000..6c07e38044
--- /dev/null
+++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl_RoomListView_null_RoomListView-Night-3_5_null_11,NEXUS_5,1.0,en].png
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:aecfc26c04a2c1d16ae9d00a85388ac6497190c743b8b6b37b40c4337c216216
+size 53371
diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl_RoomListView_null_RoomListView-Night-3_5_null_12,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl_RoomListView_null_RoomListView-Night-3_5_null_12,NEXUS_5,1.0,en].png
new file mode 100644
index 0000000000..56f7f133f3
--- /dev/null
+++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl_RoomListView_null_RoomListView-Night-3_5_null_12,NEXUS_5,1.0,en].png
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:a7bf47b0a25c455b108d7b3585a42849f03c6652af73a175fe2147cb1ad62a66
+size 161125
diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.securebackup.impl.disable_SecureBackupDisableView_null_SecureBackupDisableView-Day-0_1_null_0,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.securebackup.impl.disable_SecureBackupDisableView_null_SecureBackupDisableView-Day-0_1_null_0,NEXUS_5,1.0,en].png
index f6271e8460..c4ae2f066f 100644
--- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.securebackup.impl.disable_SecureBackupDisableView_null_SecureBackupDisableView-Day-0_1_null_0,NEXUS_5,1.0,en].png
+++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.securebackup.impl.disable_SecureBackupDisableView_null_SecureBackupDisableView-Day-0_1_null_0,NEXUS_5,1.0,en].png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:76e7306898cbc637a811110c7dd0ae6dece0842755d3f9c3a90fd0c7c07f9b2e
-size 59005
+oid sha256:7e95a434bf45ede892d898dc1446da9b493826bf9bf3bf61ef9f00ccc6ded4f9
+size 58950
diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.securebackup.impl.disable_SecureBackupDisableView_null_SecureBackupDisableView-Day-0_1_null_1,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.securebackup.impl.disable_SecureBackupDisableView_null_SecureBackupDisableView-Day-0_1_null_1,NEXUS_5,1.0,en].png
index d059a1163e..6da6c6b540 100644
--- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.securebackup.impl.disable_SecureBackupDisableView_null_SecureBackupDisableView-Day-0_1_null_1,NEXUS_5,1.0,en].png
+++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.securebackup.impl.disable_SecureBackupDisableView_null_SecureBackupDisableView-Day-0_1_null_1,NEXUS_5,1.0,en].png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:f3148e7abdbf0b6d27d3fbebc9c237ecaa30a7724d35bd0421c89198b5e6165b
-size 47784
+oid sha256:8153dddb52ae42e3ad07afc2048f99658f3c8a54a4b07f4fe69e217132b0573f
+size 47788
diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.securebackup.impl.disable_SecureBackupDisableView_null_SecureBackupDisableView-Day-0_1_null_2,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.securebackup.impl.disable_SecureBackupDisableView_null_SecureBackupDisableView-Day-0_1_null_2,NEXUS_5,1.0,en].png
index 8491fdc798..e9850cab98 100644
--- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.securebackup.impl.disable_SecureBackupDisableView_null_SecureBackupDisableView-Day-0_1_null_2,NEXUS_5,1.0,en].png
+++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.securebackup.impl.disable_SecureBackupDisableView_null_SecureBackupDisableView-Day-0_1_null_2,NEXUS_5,1.0,en].png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:cd12f81dfc5856c5db3ae9421e05d38328ffc977aa9a778d0b4202d0e79b447e
-size 59677
+oid sha256:d2eb5b3ac0e302c29bded27f39048c16d3eb1f31ea4a03b58775bb34d3c5f285
+size 59604
diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.securebackup.impl.disable_SecureBackupDisableView_null_SecureBackupDisableView-Day-0_1_null_3,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.securebackup.impl.disable_SecureBackupDisableView_null_SecureBackupDisableView-Day-0_1_null_3,NEXUS_5,1.0,en].png
index 178750d1cb..96c9d6f178 100644
--- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.securebackup.impl.disable_SecureBackupDisableView_null_SecureBackupDisableView-Day-0_1_null_3,NEXUS_5,1.0,en].png
+++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.securebackup.impl.disable_SecureBackupDisableView_null_SecureBackupDisableView-Day-0_1_null_3,NEXUS_5,1.0,en].png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:6e4b21aaf3ff6f327041bcf169ba4d493c24f18d1b2f8fbafa20a20c19e78561
-size 30447
+oid sha256:236e68f772ab98458afa255ebce89ecf92949f07b346fa1d2e0c86a46f65f7d5
+size 30451
diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.securebackup.impl.disable_SecureBackupDisableView_null_SecureBackupDisableView-Night-0_2_null_0,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.securebackup.impl.disable_SecureBackupDisableView_null_SecureBackupDisableView-Night-0_2_null_0,NEXUS_5,1.0,en].png
index b41c7b1376..b6934ad81a 100644
--- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.securebackup.impl.disable_SecureBackupDisableView_null_SecureBackupDisableView-Night-0_2_null_0,NEXUS_5,1.0,en].png
+++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.securebackup.impl.disable_SecureBackupDisableView_null_SecureBackupDisableView-Night-0_2_null_0,NEXUS_5,1.0,en].png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:dd7d552ceb9b86f4bacbd9bd0e20b7e895d29e17b113230e4de63a9680ced233
-size 57250
+oid sha256:a3d32339cf5f0044826083659b2040691a15e1dd3c1d92091b10b3b8ee02b99b
+size 57203
diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.securebackup.impl.disable_SecureBackupDisableView_null_SecureBackupDisableView-Night-0_2_null_1,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.securebackup.impl.disable_SecureBackupDisableView_null_SecureBackupDisableView-Night-0_2_null_1,NEXUS_5,1.0,en].png
index 88031ebef1..f77060c7f7 100644
--- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.securebackup.impl.disable_SecureBackupDisableView_null_SecureBackupDisableView-Night-0_2_null_1,NEXUS_5,1.0,en].png
+++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.securebackup.impl.disable_SecureBackupDisableView_null_SecureBackupDisableView-Night-0_2_null_1,NEXUS_5,1.0,en].png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:87be047661972a3fa72e069e79028cb64b4663c1188eb747593427209edcf924
-size 41941
+oid sha256:45e274f5a693439a3b05254aa366c8de7eedfa4f04fd69b92bc9b22144b5ad79
+size 41895
diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.securebackup.impl.disable_SecureBackupDisableView_null_SecureBackupDisableView-Night-0_2_null_2,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.securebackup.impl.disable_SecureBackupDisableView_null_SecureBackupDisableView-Night-0_2_null_2,NEXUS_5,1.0,en].png
index e4c1b50917..d78db00ed9 100644
--- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.securebackup.impl.disable_SecureBackupDisableView_null_SecureBackupDisableView-Night-0_2_null_2,NEXUS_5,1.0,en].png
+++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.securebackup.impl.disable_SecureBackupDisableView_null_SecureBackupDisableView-Night-0_2_null_2,NEXUS_5,1.0,en].png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:e35b127fc263420421bb48153aa7fad1a65fca043bfd5756c92988ed3b356302
-size 57740
+oid sha256:c32f1ef0076a7f1388b9389850601a5087f641b0eb8f4bc62239b048e237dfca
+size 57686
diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.securebackup.impl.disable_SecureBackupDisableView_null_SecureBackupDisableView-Night-0_2_null_3,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.securebackup.impl.disable_SecureBackupDisableView_null_SecureBackupDisableView-Night-0_2_null_3,NEXUS_5,1.0,en].png
index b9a3c9c104..2c8cb25ffe 100644
--- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.securebackup.impl.disable_SecureBackupDisableView_null_SecureBackupDisableView-Night-0_2_null_3,NEXUS_5,1.0,en].png
+++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.securebackup.impl.disable_SecureBackupDisableView_null_SecureBackupDisableView-Night-0_2_null_3,NEXUS_5,1.0,en].png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:9ea77618be64e5cc97ccd0b80e9524b8653d5539c5e8fa0db265e202dbfd7802
-size 26831
+oid sha256:c9b47f6c36ab9e2edb7cdef8b10fe188d9dddd51d47a14e095025e192d4c526a
+size 26788
diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.securebackup.impl.enable_SecureBackupEnableView_null_SecureBackupEnableView-Day-1_2_null_0,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.securebackup.impl.enable_SecureBackupEnableView_null_SecureBackupEnableView-Day-1_2_null_0,NEXUS_5,1.0,en].png
index feb7987b41..7246823443 100644
--- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.securebackup.impl.enable_SecureBackupEnableView_null_SecureBackupEnableView-Day-1_2_null_0,NEXUS_5,1.0,en].png
+++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.securebackup.impl.enable_SecureBackupEnableView_null_SecureBackupEnableView-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:849fa392721e9b4e2232a704f45cc6163e6357651d1069fb1ab2345440aac55c
-size 15696
+oid sha256:48d9b98073f29075b695d3bf3aa82de865cf56287900ab8d092fe3093fb41cc6
+size 15643
diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.securebackup.impl.enable_SecureBackupEnableView_null_SecureBackupEnableView-Day-1_2_null_1,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.securebackup.impl.enable_SecureBackupEnableView_null_SecureBackupEnableView-Day-1_2_null_1,NEXUS_5,1.0,en].png
index 77982cc44f..42b8221a43 100644
--- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.securebackup.impl.enable_SecureBackupEnableView_null_SecureBackupEnableView-Day-1_2_null_1,NEXUS_5,1.0,en].png
+++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.securebackup.impl.enable_SecureBackupEnableView_null_SecureBackupEnableView-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:c1c1f211e73d9de972ab992a2177af2f004fd3a3372f935cf1a88a91fa3fd55d
-size 16281
+oid sha256:208ca078799b9abfc532e4e96b4b27e2982a31a137c0c8097ea2d46543eaed07
+size 16199
diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.securebackup.impl.enable_SecureBackupEnableView_null_SecureBackupEnableView-Day-1_2_null_2,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.securebackup.impl.enable_SecureBackupEnableView_null_SecureBackupEnableView-Day-1_2_null_2,NEXUS_5,1.0,en].png
index 7be35c9986..70e76acd29 100644
--- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.securebackup.impl.enable_SecureBackupEnableView_null_SecureBackupEnableView-Day-1_2_null_2,NEXUS_5,1.0,en].png
+++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.securebackup.impl.enable_SecureBackupEnableView_null_SecureBackupEnableView-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:63678a4962dba8131e64b6951dfe93ca84785b245a2540ad83f46ad18233d0db
-size 22278
+oid sha256:d1b54ade12447d53d48d41189574d577a538a8e2db0f1106f4adb0fd3d37f51d
+size 22229
diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.securebackup.impl.enable_SecureBackupEnableView_null_SecureBackupEnableView-Night-1_3_null_0,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.securebackup.impl.enable_SecureBackupEnableView_null_SecureBackupEnableView-Night-1_3_null_0,NEXUS_5,1.0,en].png
index 77fa9498f2..c75e0a7727 100644
--- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.securebackup.impl.enable_SecureBackupEnableView_null_SecureBackupEnableView-Night-1_3_null_0,NEXUS_5,1.0,en].png
+++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.securebackup.impl.enable_SecureBackupEnableView_null_SecureBackupEnableView-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:a9cebf1580d95f89cf875c9c2787798107e8c932eaa990c9ef1d423188faacdb
-size 14723
+oid sha256:25ddab1c45a5ebf26728d9f4374ea12ed3db57a4a9f826f3a815ee5da0195c2f
+size 14738
diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.securebackup.impl.enable_SecureBackupEnableView_null_SecureBackupEnableView-Night-1_3_null_1,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.securebackup.impl.enable_SecureBackupEnableView_null_SecureBackupEnableView-Night-1_3_null_1,NEXUS_5,1.0,en].png
index 44ac77db85..0abd63b28d 100644
--- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.securebackup.impl.enable_SecureBackupEnableView_null_SecureBackupEnableView-Night-1_3_null_1,NEXUS_5,1.0,en].png
+++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.securebackup.impl.enable_SecureBackupEnableView_null_SecureBackupEnableView-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:03ede18be1caac331973d48fd06c08c2914effc5aa6a20780b5606c59a5f2b6d
-size 15286
+oid sha256:8c811b7f8f94c5af8e41fa7ea9c71c42394d04e172c578725b26ea7a4382423d
+size 15272
diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.securebackup.impl.enable_SecureBackupEnableView_null_SecureBackupEnableView-Night-1_3_null_2,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.securebackup.impl.enable_SecureBackupEnableView_null_SecureBackupEnableView-Night-1_3_null_2,NEXUS_5,1.0,en].png
index f74055c74b..f1d9248af8 100644
--- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.securebackup.impl.enable_SecureBackupEnableView_null_SecureBackupEnableView-Night-1_3_null_2,NEXUS_5,1.0,en].png
+++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.securebackup.impl.enable_SecureBackupEnableView_null_SecureBackupEnableView-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:7eeb470b7327e6a662c9057858114f343410fe49e48c0cbcaf809c0e0d2b1681
-size 18985
+oid sha256:ae4d255ca1769d8436b552081b08f98806eca91cd255518e1171314b4dfc8251
+size 18951
diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.securebackup.impl.enter_SecureBackupEnterRecoveryKeyView_null_SecureBackupEnterRecoveryKeyView-Day-2_3_null_0,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.securebackup.impl.enter_SecureBackupEnterRecoveryKeyView_null_SecureBackupEnterRecoveryKeyView-Day-2_3_null_0,NEXUS_5,1.0,en].png
index f676e5c07b..37cc1b0ae5 100644
--- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.securebackup.impl.enter_SecureBackupEnterRecoveryKeyView_null_SecureBackupEnterRecoveryKeyView-Day-2_3_null_0,NEXUS_5,1.0,en].png
+++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.securebackup.impl.enter_SecureBackupEnterRecoveryKeyView_null_SecureBackupEnterRecoveryKeyView-Day-2_3_null_0,NEXUS_5,1.0,en].png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:66257f3f4d7d8178574b8b4deab2c7142f6c29aeb99c83930d5799f049dfc505
-size 34289
+oid sha256:c777028e4141f13301c87d9b0dd67622181b5e24e52f48ccbafec9c35321a4b4
+size 34189
diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.securebackup.impl.enter_SecureBackupEnterRecoveryKeyView_null_SecureBackupEnterRecoveryKeyView-Day-2_3_null_1,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.securebackup.impl.enter_SecureBackupEnterRecoveryKeyView_null_SecureBackupEnterRecoveryKeyView-Day-2_3_null_1,NEXUS_5,1.0,en].png
index b1b1f187c6..93c5ff1a69 100644
--- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.securebackup.impl.enter_SecureBackupEnterRecoveryKeyView_null_SecureBackupEnterRecoveryKeyView-Day-2_3_null_1,NEXUS_5,1.0,en].png
+++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.securebackup.impl.enter_SecureBackupEnterRecoveryKeyView_null_SecureBackupEnterRecoveryKeyView-Day-2_3_null_1,NEXUS_5,1.0,en].png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:3db584d82b7d55dc3bfa938ebad7be835fb6f06f7475961db060eb8cc9b98405
-size 46326
+oid sha256:7315273c9b9d030c1fa6938b9963ee9efb574265128268638aae22023989d856
+size 46223
diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.securebackup.impl.enter_SecureBackupEnterRecoveryKeyView_null_SecureBackupEnterRecoveryKeyView-Day-2_3_null_2,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.securebackup.impl.enter_SecureBackupEnterRecoveryKeyView_null_SecureBackupEnterRecoveryKeyView-Day-2_3_null_2,NEXUS_5,1.0,en].png
index 99e28a0f87..4b59040c96 100644
--- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.securebackup.impl.enter_SecureBackupEnterRecoveryKeyView_null_SecureBackupEnterRecoveryKeyView-Day-2_3_null_2,NEXUS_5,1.0,en].png
+++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.securebackup.impl.enter_SecureBackupEnterRecoveryKeyView_null_SecureBackupEnterRecoveryKeyView-Day-2_3_null_2,NEXUS_5,1.0,en].png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:23856a19db311a1b829dd05965154033cc4a7b4b143b73fde0cf7544bdaad9e2
-size 44649
+oid sha256:df70bdde9bc0b4299f7754923867ec8187a2daa05d56087b5ec2019ae666645b
+size 44613
diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.securebackup.impl.enter_SecureBackupEnterRecoveryKeyView_null_SecureBackupEnterRecoveryKeyView-Day-2_3_null_3,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.securebackup.impl.enter_SecureBackupEnterRecoveryKeyView_null_SecureBackupEnterRecoveryKeyView-Day-2_3_null_3,NEXUS_5,1.0,en].png
index 1f4478dff8..458100b3ac 100644
--- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.securebackup.impl.enter_SecureBackupEnterRecoveryKeyView_null_SecureBackupEnterRecoveryKeyView-Day-2_3_null_3,NEXUS_5,1.0,en].png
+++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.securebackup.impl.enter_SecureBackupEnterRecoveryKeyView_null_SecureBackupEnterRecoveryKeyView-Day-2_3_null_3,NEXUS_5,1.0,en].png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:619bc51f59ea9011a23ad43a261ae73c0c1e09b476a67e3bdca3d9ec3f1a692e
-size 43706
+oid sha256:821b60569968f6416318a62235cd4839067ef48f0fd21c9d219548da9ea2a526
+size 43672
diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.securebackup.impl.enter_SecureBackupEnterRecoveryKeyView_null_SecureBackupEnterRecoveryKeyView-Night-2_4_null_0,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.securebackup.impl.enter_SecureBackupEnterRecoveryKeyView_null_SecureBackupEnterRecoveryKeyView-Night-2_4_null_0,NEXUS_5,1.0,en].png
index 37728629fd..b53a7c0023 100644
--- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.securebackup.impl.enter_SecureBackupEnterRecoveryKeyView_null_SecureBackupEnterRecoveryKeyView-Night-2_4_null_0,NEXUS_5,1.0,en].png
+++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.securebackup.impl.enter_SecureBackupEnterRecoveryKeyView_null_SecureBackupEnterRecoveryKeyView-Night-2_4_null_0,NEXUS_5,1.0,en].png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:bc6c5fe6048fe1bcd5ee4c3a00561a705b3011b17c92cd8594f3a93f5d317533
-size 32511
+oid sha256:21bc9b421f1e88690664d264562076609a4c63d68666b6ebe1673ab9202f10a1
+size 32514
diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.securebackup.impl.enter_SecureBackupEnterRecoveryKeyView_null_SecureBackupEnterRecoveryKeyView-Night-2_4_null_1,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.securebackup.impl.enter_SecureBackupEnterRecoveryKeyView_null_SecureBackupEnterRecoveryKeyView-Night-2_4_null_1,NEXUS_5,1.0,en].png
index fb9bdcada0..cccf7049a8 100644
--- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.securebackup.impl.enter_SecureBackupEnterRecoveryKeyView_null_SecureBackupEnterRecoveryKeyView-Night-2_4_null_1,NEXUS_5,1.0,en].png
+++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.securebackup.impl.enter_SecureBackupEnterRecoveryKeyView_null_SecureBackupEnterRecoveryKeyView-Night-2_4_null_1,NEXUS_5,1.0,en].png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:e03b605d6dfabab4add9502e4e58185442d21f00f36f6ccb9f34dc49c9c98e03
-size 42992
+oid sha256:5efecc0c8b77341752cabb60a988458af292adb4da04274d5fe43e0ebfc5dad7
+size 42986
diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.securebackup.impl.enter_SecureBackupEnterRecoveryKeyView_null_SecureBackupEnterRecoveryKeyView-Night-2_4_null_2,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.securebackup.impl.enter_SecureBackupEnterRecoveryKeyView_null_SecureBackupEnterRecoveryKeyView-Night-2_4_null_2,NEXUS_5,1.0,en].png
index db94222ed0..3fafc59ea8 100644
--- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.securebackup.impl.enter_SecureBackupEnterRecoveryKeyView_null_SecureBackupEnterRecoveryKeyView-Night-2_4_null_2,NEXUS_5,1.0,en].png
+++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.securebackup.impl.enter_SecureBackupEnterRecoveryKeyView_null_SecureBackupEnterRecoveryKeyView-Night-2_4_null_2,NEXUS_5,1.0,en].png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:9c055595664b4188a8098cfc999d4172091f046878106f6c1ce858eca46fc9f3
-size 41562
+oid sha256:4457774feb41b613e9a4598541e252ccbbea7f9806c0a4ca8fbe71c3eff716a6
+size 41577
diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.securebackup.impl.enter_SecureBackupEnterRecoveryKeyView_null_SecureBackupEnterRecoveryKeyView-Night-2_4_null_3,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.securebackup.impl.enter_SecureBackupEnterRecoveryKeyView_null_SecureBackupEnterRecoveryKeyView-Night-2_4_null_3,NEXUS_5,1.0,en].png
index de6d3a8cb2..df72fb1233 100644
--- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.securebackup.impl.enter_SecureBackupEnterRecoveryKeyView_null_SecureBackupEnterRecoveryKeyView-Night-2_4_null_3,NEXUS_5,1.0,en].png
+++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.securebackup.impl.enter_SecureBackupEnterRecoveryKeyView_null_SecureBackupEnterRecoveryKeyView-Night-2_4_null_3,NEXUS_5,1.0,en].png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:12aa860192cf02e19dfba9dd8060e96568b23766dc5ef5db30f05d7eb19c403b
-size 38641
+oid sha256:9b7dbb4c98ddf1e89af7e1ca3c84bc381755da135346c08cebad1b75c4903172
+size 38613
diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.securebackup.impl.setup_SecureBackupSetupViewChange_null_SecureBackupSetupViewChange-Day-5_6_null_0,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.securebackup.impl.setup_SecureBackupSetupViewChange_null_SecureBackupSetupViewChange-Day-5_6_null_0,NEXUS_5,1.0,en].png
index bc2ae46f25..d7d3fffc1e 100644
--- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.securebackup.impl.setup_SecureBackupSetupViewChange_null_SecureBackupSetupViewChange-Day-5_6_null_0,NEXUS_5,1.0,en].png
+++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.securebackup.impl.setup_SecureBackupSetupViewChange_null_SecureBackupSetupViewChange-Day-5_6_null_0,NEXUS_5,1.0,en].png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:ce5bf5f221e71ef09f2467e160297db6a538ecaec7f423451edb521b3d743725
-size 50588
+oid sha256:87a301e27fbb5b3084791a5df778d1fc1b5788f9ec88fdc580d4791f56d993d7
+size 50523
diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.securebackup.impl.setup_SecureBackupSetupViewChange_null_SecureBackupSetupViewChange-Day-5_6_null_1,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.securebackup.impl.setup_SecureBackupSetupViewChange_null_SecureBackupSetupViewChange-Day-5_6_null_1,NEXUS_5,1.0,en].png
index 0cfd15d94e..4888c2bdda 100644
--- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.securebackup.impl.setup_SecureBackupSetupViewChange_null_SecureBackupSetupViewChange-Day-5_6_null_1,NEXUS_5,1.0,en].png
+++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.securebackup.impl.setup_SecureBackupSetupViewChange_null_SecureBackupSetupViewChange-Day-5_6_null_1,NEXUS_5,1.0,en].png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:934e4749c80b61c3b4b1fcfb7573ba12186f31260198c3b16595b5b23ab17fc9
-size 48481
+oid sha256:044ee40991f7d5812761520bb6347bfbfc18d7447151200bad244d0c1a677ea3
+size 48396
diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.securebackup.impl.setup_SecureBackupSetupViewChange_null_SecureBackupSetupViewChange-Day-5_6_null_2,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.securebackup.impl.setup_SecureBackupSetupViewChange_null_SecureBackupSetupViewChange-Day-5_6_null_2,NEXUS_5,1.0,en].png
index 4e5f1e7f9e..f94baa080b 100644
--- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.securebackup.impl.setup_SecureBackupSetupViewChange_null_SecureBackupSetupViewChange-Day-5_6_null_2,NEXUS_5,1.0,en].png
+++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.securebackup.impl.setup_SecureBackupSetupViewChange_null_SecureBackupSetupViewChange-Day-5_6_null_2,NEXUS_5,1.0,en].png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:7872cba8e1bf900d81288748b0e55e945bb551525707f20fe0711931a483c22b
-size 53234
+oid sha256:8f48a7154d43b6e3b79a2767d80035b03a819ad7bd475174e67f63d40e3faa83
+size 53124
diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.securebackup.impl.setup_SecureBackupSetupViewChange_null_SecureBackupSetupViewChange-Day-5_6_null_3,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.securebackup.impl.setup_SecureBackupSetupViewChange_null_SecureBackupSetupViewChange-Day-5_6_null_3,NEXUS_5,1.0,en].png
index 4e5f1e7f9e..f94baa080b 100644
--- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.securebackup.impl.setup_SecureBackupSetupViewChange_null_SecureBackupSetupViewChange-Day-5_6_null_3,NEXUS_5,1.0,en].png
+++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.securebackup.impl.setup_SecureBackupSetupViewChange_null_SecureBackupSetupViewChange-Day-5_6_null_3,NEXUS_5,1.0,en].png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:7872cba8e1bf900d81288748b0e55e945bb551525707f20fe0711931a483c22b
-size 53234
+oid sha256:8f48a7154d43b6e3b79a2767d80035b03a819ad7bd475174e67f63d40e3faa83
+size 53124
diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.securebackup.impl.setup_SecureBackupSetupViewChange_null_SecureBackupSetupViewChange-Day-5_6_null_4,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.securebackup.impl.setup_SecureBackupSetupViewChange_null_SecureBackupSetupViewChange-Day-5_6_null_4,NEXUS_5,1.0,en].png
index a8ed14d18d..b29bca1351 100644
--- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.securebackup.impl.setup_SecureBackupSetupViewChange_null_SecureBackupSetupViewChange-Day-5_6_null_4,NEXUS_5,1.0,en].png
+++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.securebackup.impl.setup_SecureBackupSetupViewChange_null_SecureBackupSetupViewChange-Day-5_6_null_4,NEXUS_5,1.0,en].png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:ef611386d451c8849c3c8cdcd2344d8c19aa66092cbdd52bea58a9cf882ab22a
-size 48550
+oid sha256:ed606bf9bcda44b7dbc9ee3e7a4f27e8d1c5bf12bcdffc746fea7ed29ebcd8fd
+size 48520
diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.securebackup.impl.setup_SecureBackupSetupViewChange_null_SecureBackupSetupViewChange-Night-5_7_null_0,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.securebackup.impl.setup_SecureBackupSetupViewChange_null_SecureBackupSetupViewChange-Night-5_7_null_0,NEXUS_5,1.0,en].png
index 6e8461a284..62d3da7f86 100644
--- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.securebackup.impl.setup_SecureBackupSetupViewChange_null_SecureBackupSetupViewChange-Night-5_7_null_0,NEXUS_5,1.0,en].png
+++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.securebackup.impl.setup_SecureBackupSetupViewChange_null_SecureBackupSetupViewChange-Night-5_7_null_0,NEXUS_5,1.0,en].png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:0ba7c55493f8c25285889c9c8f4e12bb838dd7827697da967d03de723e4ef766
-size 48555
+oid sha256:9604e1d8d263f3254fcdce7c79bae85510f42cee1d13fa3deb2b823a8252ac8a
+size 48568
diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.securebackup.impl.setup_SecureBackupSetupViewChange_null_SecureBackupSetupViewChange-Night-5_7_null_1,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.securebackup.impl.setup_SecureBackupSetupViewChange_null_SecureBackupSetupViewChange-Night-5_7_null_1,NEXUS_5,1.0,en].png
index c8314ad20c..348ce584fa 100644
--- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.securebackup.impl.setup_SecureBackupSetupViewChange_null_SecureBackupSetupViewChange-Night-5_7_null_1,NEXUS_5,1.0,en].png
+++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.securebackup.impl.setup_SecureBackupSetupViewChange_null_SecureBackupSetupViewChange-Night-5_7_null_1,NEXUS_5,1.0,en].png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:f60f9eb53c57170e063b296d60308214d442bda3039d570e511860babc6fff38
-size 46302
+oid sha256:f97d4a5adc6327b134d5cb4b43e45d543e7fe912b001b44deb040e6400efa675
+size 46320
diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.securebackup.impl.setup_SecureBackupSetupViewChange_null_SecureBackupSetupViewChange-Night-5_7_null_2,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.securebackup.impl.setup_SecureBackupSetupViewChange_null_SecureBackupSetupViewChange-Night-5_7_null_2,NEXUS_5,1.0,en].png
index 3a647c4592..275a6f6735 100644
--- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.securebackup.impl.setup_SecureBackupSetupViewChange_null_SecureBackupSetupViewChange-Night-5_7_null_2,NEXUS_5,1.0,en].png
+++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.securebackup.impl.setup_SecureBackupSetupViewChange_null_SecureBackupSetupViewChange-Night-5_7_null_2,NEXUS_5,1.0,en].png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:c5f3cbe3e3158a6958e12a9848dda9070b70e14a27fb5872a8d173673b93aeea
-size 50434
+oid sha256:1f4eee3cd8e4f6d2586a0ffdcf061756ef443e8bbdb3672e768ace100c9e787b
+size 50410
diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.securebackup.impl.setup_SecureBackupSetupViewChange_null_SecureBackupSetupViewChange-Night-5_7_null_3,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.securebackup.impl.setup_SecureBackupSetupViewChange_null_SecureBackupSetupViewChange-Night-5_7_null_3,NEXUS_5,1.0,en].png
index 3a647c4592..275a6f6735 100644
--- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.securebackup.impl.setup_SecureBackupSetupViewChange_null_SecureBackupSetupViewChange-Night-5_7_null_3,NEXUS_5,1.0,en].png
+++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.securebackup.impl.setup_SecureBackupSetupViewChange_null_SecureBackupSetupViewChange-Night-5_7_null_3,NEXUS_5,1.0,en].png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:c5f3cbe3e3158a6958e12a9848dda9070b70e14a27fb5872a8d173673b93aeea
-size 50434
+oid sha256:1f4eee3cd8e4f6d2586a0ffdcf061756ef443e8bbdb3672e768ace100c9e787b
+size 50410
diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.securebackup.impl.setup_SecureBackupSetupViewChange_null_SecureBackupSetupViewChange-Night-5_7_null_4,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.securebackup.impl.setup_SecureBackupSetupViewChange_null_SecureBackupSetupViewChange-Night-5_7_null_4,NEXUS_5,1.0,en].png
index 50b7e8170b..01bc072140 100644
--- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.securebackup.impl.setup_SecureBackupSetupViewChange_null_SecureBackupSetupViewChange-Night-5_7_null_4,NEXUS_5,1.0,en].png
+++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.securebackup.impl.setup_SecureBackupSetupViewChange_null_SecureBackupSetupViewChange-Night-5_7_null_4,NEXUS_5,1.0,en].png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:c31a548db85548409db4071c9ae34411d6c93de7f23b514034c0a58679fdaa20
-size 42588
+oid sha256:8aafe986067ba8e3c8c6df67f9229280fe5b78819e296d01885563711eb3645a
+size 42556
diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.securebackup.impl.setup_SecureBackupSetupView_null_SecureBackupSetupView-Day-4_5_null_0,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.securebackup.impl.setup_SecureBackupSetupView_null_SecureBackupSetupView-Day-4_5_null_0,NEXUS_5,1.0,en].png
index 6f3d6c5ae5..4bf7dcfa2f 100644
--- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.securebackup.impl.setup_SecureBackupSetupView_null_SecureBackupSetupView-Day-4_5_null_0,NEXUS_5,1.0,en].png
+++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.securebackup.impl.setup_SecureBackupSetupView_null_SecureBackupSetupView-Day-4_5_null_0,NEXUS_5,1.0,en].png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:2f7cc54d19a41c6920c51d799f17ae5d2cf4d0bbeaf58d32c83dae52c24ac1f8
-size 51883
+oid sha256:2b15b3765fdf410748cf16c04f3de34f35f6228791c4117494dbbfc59584e6bc
+size 51812
diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.securebackup.impl.setup_SecureBackupSetupView_null_SecureBackupSetupView-Day-4_5_null_1,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.securebackup.impl.setup_SecureBackupSetupView_null_SecureBackupSetupView-Day-4_5_null_1,NEXUS_5,1.0,en].png
index 2bd5b57a2b..8373a0047c 100644
--- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.securebackup.impl.setup_SecureBackupSetupView_null_SecureBackupSetupView-Day-4_5_null_1,NEXUS_5,1.0,en].png
+++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.securebackup.impl.setup_SecureBackupSetupView_null_SecureBackupSetupView-Day-4_5_null_1,NEXUS_5,1.0,en].png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:3c73f15a0a31e0e6665fc3e278f64dad957d7f717afa4213094c88edbfdb728e
-size 50018
+oid sha256:8edbf48dbf23e6b8265f6b1f3b247d765c44a23642b042db67ceb25966347830
+size 49949
diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.securebackup.impl.setup_SecureBackupSetupView_null_SecureBackupSetupView-Day-4_5_null_2,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.securebackup.impl.setup_SecureBackupSetupView_null_SecureBackupSetupView-Day-4_5_null_2,NEXUS_5,1.0,en].png
index 4e5f1e7f9e..f94baa080b 100644
--- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.securebackup.impl.setup_SecureBackupSetupView_null_SecureBackupSetupView-Day-4_5_null_2,NEXUS_5,1.0,en].png
+++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.securebackup.impl.setup_SecureBackupSetupView_null_SecureBackupSetupView-Day-4_5_null_2,NEXUS_5,1.0,en].png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:7872cba8e1bf900d81288748b0e55e945bb551525707f20fe0711931a483c22b
-size 53234
+oid sha256:8f48a7154d43b6e3b79a2767d80035b03a819ad7bd475174e67f63d40e3faa83
+size 53124
diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.securebackup.impl.setup_SecureBackupSetupView_null_SecureBackupSetupView-Day-4_5_null_3,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.securebackup.impl.setup_SecureBackupSetupView_null_SecureBackupSetupView-Day-4_5_null_3,NEXUS_5,1.0,en].png
index 4e5f1e7f9e..f94baa080b 100644
--- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.securebackup.impl.setup_SecureBackupSetupView_null_SecureBackupSetupView-Day-4_5_null_3,NEXUS_5,1.0,en].png
+++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.securebackup.impl.setup_SecureBackupSetupView_null_SecureBackupSetupView-Day-4_5_null_3,NEXUS_5,1.0,en].png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:7872cba8e1bf900d81288748b0e55e945bb551525707f20fe0711931a483c22b
-size 53234
+oid sha256:8f48a7154d43b6e3b79a2767d80035b03a819ad7bd475174e67f63d40e3faa83
+size 53124
diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.securebackup.impl.setup_SecureBackupSetupView_null_SecureBackupSetupView-Day-4_5_null_4,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.securebackup.impl.setup_SecureBackupSetupView_null_SecureBackupSetupView-Day-4_5_null_4,NEXUS_5,1.0,en].png
index a8ed14d18d..b29bca1351 100644
--- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.securebackup.impl.setup_SecureBackupSetupView_null_SecureBackupSetupView-Day-4_5_null_4,NEXUS_5,1.0,en].png
+++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.securebackup.impl.setup_SecureBackupSetupView_null_SecureBackupSetupView-Day-4_5_null_4,NEXUS_5,1.0,en].png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:ef611386d451c8849c3c8cdcd2344d8c19aa66092cbdd52bea58a9cf882ab22a
-size 48550
+oid sha256:ed606bf9bcda44b7dbc9ee3e7a4f27e8d1c5bf12bcdffc746fea7ed29ebcd8fd
+size 48520
diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.securebackup.impl.setup_SecureBackupSetupView_null_SecureBackupSetupView-Night-4_6_null_0,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.securebackup.impl.setup_SecureBackupSetupView_null_SecureBackupSetupView-Night-4_6_null_0,NEXUS_5,1.0,en].png
index 1ac830b344..4d7658bba5 100644
--- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.securebackup.impl.setup_SecureBackupSetupView_null_SecureBackupSetupView-Night-4_6_null_0,NEXUS_5,1.0,en].png
+++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.securebackup.impl.setup_SecureBackupSetupView_null_SecureBackupSetupView-Night-4_6_null_0,NEXUS_5,1.0,en].png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:757ed00bc9ff04e2a4142daf475acb3ba28d1441765c1a8b322fa9328bb62676
-size 49979
+oid sha256:31df36227486eec2337ca723784ad1a3a37fc70c9a21734f626d80588e6b9ae8
+size 49992
diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.securebackup.impl.setup_SecureBackupSetupView_null_SecureBackupSetupView-Night-4_6_null_1,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.securebackup.impl.setup_SecureBackupSetupView_null_SecureBackupSetupView-Night-4_6_null_1,NEXUS_5,1.0,en].png
index 67cb5d4067..715adcf685 100644
--- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.securebackup.impl.setup_SecureBackupSetupView_null_SecureBackupSetupView-Night-4_6_null_1,NEXUS_5,1.0,en].png
+++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.securebackup.impl.setup_SecureBackupSetupView_null_SecureBackupSetupView-Night-4_6_null_1,NEXUS_5,1.0,en].png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:15be1d03c579a5427493087f0097f76d03d6d36564d01cbd6d7149576e93f102
-size 47986
+oid sha256:ed46873416a6f26f42980a8b166914ba75a5bffb446c076f5647b2c01497d8db
+size 48000
diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.securebackup.impl.setup_SecureBackupSetupView_null_SecureBackupSetupView-Night-4_6_null_2,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.securebackup.impl.setup_SecureBackupSetupView_null_SecureBackupSetupView-Night-4_6_null_2,NEXUS_5,1.0,en].png
index 3a647c4592..275a6f6735 100644
--- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.securebackup.impl.setup_SecureBackupSetupView_null_SecureBackupSetupView-Night-4_6_null_2,NEXUS_5,1.0,en].png
+++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.securebackup.impl.setup_SecureBackupSetupView_null_SecureBackupSetupView-Night-4_6_null_2,NEXUS_5,1.0,en].png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:c5f3cbe3e3158a6958e12a9848dda9070b70e14a27fb5872a8d173673b93aeea
-size 50434
+oid sha256:1f4eee3cd8e4f6d2586a0ffdcf061756ef443e8bbdb3672e768ace100c9e787b
+size 50410
diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.securebackup.impl.setup_SecureBackupSetupView_null_SecureBackupSetupView-Night-4_6_null_3,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.securebackup.impl.setup_SecureBackupSetupView_null_SecureBackupSetupView-Night-4_6_null_3,NEXUS_5,1.0,en].png
index 3a647c4592..275a6f6735 100644
--- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.securebackup.impl.setup_SecureBackupSetupView_null_SecureBackupSetupView-Night-4_6_null_3,NEXUS_5,1.0,en].png
+++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.securebackup.impl.setup_SecureBackupSetupView_null_SecureBackupSetupView-Night-4_6_null_3,NEXUS_5,1.0,en].png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:c5f3cbe3e3158a6958e12a9848dda9070b70e14a27fb5872a8d173673b93aeea
-size 50434
+oid sha256:1f4eee3cd8e4f6d2586a0ffdcf061756ef443e8bbdb3672e768ace100c9e787b
+size 50410
diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.securebackup.impl.setup_SecureBackupSetupView_null_SecureBackupSetupView-Night-4_6_null_4,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.securebackup.impl.setup_SecureBackupSetupView_null_SecureBackupSetupView-Night-4_6_null_4,NEXUS_5,1.0,en].png
index 50b7e8170b..01bc072140 100644
--- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.securebackup.impl.setup_SecureBackupSetupView_null_SecureBackupSetupView-Night-4_6_null_4,NEXUS_5,1.0,en].png
+++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.securebackup.impl.setup_SecureBackupSetupView_null_SecureBackupSetupView-Night-4_6_null_4,NEXUS_5,1.0,en].png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:c31a548db85548409db4071c9ae34411d6c93de7f23b514034c0a58679fdaa20
-size 42588
+oid sha256:8aafe986067ba8e3c8c6df67f9229280fe5b78819e296d01885563711eb3645a
+size 42556
diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.signedout.impl_SignedOutView_null_SignedOutView-Day-0_1_null_0,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.signedout.impl_SignedOutView_null_SignedOutView-Day-0_1_null_0,NEXUS_5,1.0,en].png
index ad273f4619..49dbf2265c 100644
--- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.signedout.impl_SignedOutView_null_SignedOutView-Day-0_1_null_0,NEXUS_5,1.0,en].png
+++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.signedout.impl_SignedOutView_null_SignedOutView-Day-0_1_null_0,NEXUS_5,1.0,en].png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:8830c2822cdc08b72cf6b45d5b9becd29b1824c01002336f69dc4b8a432e28e2
-size 60504
+oid sha256:75f40e29b9e471c0920cbbb1d1300b4b8eb89fc8041470a5ed72081e4ea2f75b
+size 60457
diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.signedout.impl_SignedOutView_null_SignedOutView-Night-0_2_null_0,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.signedout.impl_SignedOutView_null_SignedOutView-Night-0_2_null_0,NEXUS_5,1.0,en].png
index 944fb938d8..b957e40f5b 100644
--- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.signedout.impl_SignedOutView_null_SignedOutView-Night-0_2_null_0,NEXUS_5,1.0,en].png
+++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.signedout.impl_SignedOutView_null_SignedOutView-Night-0_2_null_0,NEXUS_5,1.0,en].png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:d0cf3d6480619228bace599debade40ccf67ecdeb545ba1a3115700e58db55e0
-size 58730
+oid sha256:ed8a17b524b38e2d979f3464f132a87f5c7479d2a935077c6eceaa4e475324a5
+size 58712
diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.verifysession.impl_VerifySelfSessionView_null_VerifySelfSessionView-Day-0_1_null_0,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.verifysession.impl_VerifySelfSessionView_null_VerifySelfSessionView-Day-0_1_null_0,NEXUS_5,1.0,en].png
index ad10e0a111..25be545a89 100644
--- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.verifysession.impl_VerifySelfSessionView_null_VerifySelfSessionView-Day-0_1_null_0,NEXUS_5,1.0,en].png
+++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.verifysession.impl_VerifySelfSessionView_null_VerifySelfSessionView-Day-0_1_null_0,NEXUS_5,1.0,en].png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:6ddfdd4089c3ef38fc0ad5435296490ea1bf82a33c0aa23c4d0b5217c341bb1f
-size 28389
+oid sha256:3e5c225258a6b257afcfc935971df619199a8985ad87203528d27a166a6fda2a
+size 28334
diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.verifysession.impl_VerifySelfSessionView_null_VerifySelfSessionView-Day-0_1_null_2,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.verifysession.impl_VerifySelfSessionView_null_VerifySelfSessionView-Day-0_1_null_2,NEXUS_5,1.0,en].png
index de0e46a071..f239a76249 100644
--- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.verifysession.impl_VerifySelfSessionView_null_VerifySelfSessionView-Day-0_1_null_2,NEXUS_5,1.0,en].png
+++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.verifysession.impl_VerifySelfSessionView_null_VerifySelfSessionView-Day-0_1_null_2,NEXUS_5,1.0,en].png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:8425428904c58fd9a22f4505c7dbb47798efcf2f2e5007fbf3f402222cb0cf53
-size 51381
+oid sha256:c4545536311f20615a2809a067af9eabf1a9398f39a9df819dd3c0a4c3de64bd
+size 51321
diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.verifysession.impl_VerifySelfSessionView_null_VerifySelfSessionView-Day-0_1_null_3,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.verifysession.impl_VerifySelfSessionView_null_VerifySelfSessionView-Day-0_1_null_3,NEXUS_5,1.0,en].png
index 258a528e6c..4e7f01ae48 100644
--- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.verifysession.impl_VerifySelfSessionView_null_VerifySelfSessionView-Day-0_1_null_3,NEXUS_5,1.0,en].png
+++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.verifysession.impl_VerifySelfSessionView_null_VerifySelfSessionView-Day-0_1_null_3,NEXUS_5,1.0,en].png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:f5318f2a7564c319c58971daf76a60a696d0835476d06666a190849a7222c98d
-size 52689
+oid sha256:26759996939952786a94b9d860e02c40154c0903a49afb8e7be05a20787f0fa4
+size 52615
diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.verifysession.impl_VerifySelfSessionView_null_VerifySelfSessionView-Day-0_1_null_4,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.verifysession.impl_VerifySelfSessionView_null_VerifySelfSessionView-Day-0_1_null_4,NEXUS_5,1.0,en].png
index f718f8a03a..22ffbb29ae 100644
--- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.verifysession.impl_VerifySelfSessionView_null_VerifySelfSessionView-Day-0_1_null_4,NEXUS_5,1.0,en].png
+++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.verifysession.impl_VerifySelfSessionView_null_VerifySelfSessionView-Day-0_1_null_4,NEXUS_5,1.0,en].png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:b9f571f7767f7d1c41db37113346eaeb995b81a87e8957d83751b7cd6ef27058
-size 31678
+oid sha256:3ce368edd4536137fb4545fb21892c51af43d7325f21b6e34e5ac1a72b818b34
+size 31575
diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.verifysession.impl_VerifySelfSessionView_null_VerifySelfSessionView-Day-0_1_null_5,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.verifysession.impl_VerifySelfSessionView_null_VerifySelfSessionView-Day-0_1_null_5,NEXUS_5,1.0,en].png
index 799ac802fa..7dec5258da 100644
--- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.verifysession.impl_VerifySelfSessionView_null_VerifySelfSessionView-Day-0_1_null_5,NEXUS_5,1.0,en].png
+++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.verifysession.impl_VerifySelfSessionView_null_VerifySelfSessionView-Day-0_1_null_5,NEXUS_5,1.0,en].png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:70d489b8ff343e27f95065f4f201b44607837dda177eb1f331a2def661e121c1
-size 21009
+oid sha256:d4bff39ac46298be6b968326b64c632aa73b13a51f1efff512d5c6894c414a1b
+size 20951
diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.verifysession.impl_VerifySelfSessionView_null_VerifySelfSessionView-Day-0_1_null_6,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.verifysession.impl_VerifySelfSessionView_null_VerifySelfSessionView-Day-0_1_null_6,NEXUS_5,1.0,en].png
index fb2edac72f..7908dfeabd 100644
--- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.verifysession.impl_VerifySelfSessionView_null_VerifySelfSessionView-Day-0_1_null_6,NEXUS_5,1.0,en].png
+++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.verifysession.impl_VerifySelfSessionView_null_VerifySelfSessionView-Day-0_1_null_6,NEXUS_5,1.0,en].png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:22817cd770e9eb1d438128804007a33cc038f8da17788f0848ec5db26211a179
-size 35569
+oid sha256:0843965afef3d142709f377ab408866cacfb016f652107ee84dc2fd39770ff17
+size 35490
diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.verifysession.impl_VerifySelfSessionView_null_VerifySelfSessionView-Night-0_2_null_0,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.verifysession.impl_VerifySelfSessionView_null_VerifySelfSessionView-Night-0_2_null_0,NEXUS_5,1.0,en].png
index c9c0ad3e0b..0795fad021 100644
--- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.verifysession.impl_VerifySelfSessionView_null_VerifySelfSessionView-Night-0_2_null_0,NEXUS_5,1.0,en].png
+++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.verifysession.impl_VerifySelfSessionView_null_VerifySelfSessionView-Night-0_2_null_0,NEXUS_5,1.0,en].png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:5657f3d4778f66d9ba1c6138845317a336fc0d51342d26650c317fca9bf2a1c2
-size 26851
+oid sha256:8ef7b72a829b4add1f21b5f7fc06d6a260227b9c065c08ad770d70656b28f815
+size 26848
diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.verifysession.impl_VerifySelfSessionView_null_VerifySelfSessionView-Night-0_2_null_2,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.verifysession.impl_VerifySelfSessionView_null_VerifySelfSessionView-Night-0_2_null_2,NEXUS_5,1.0,en].png
index 1c24f49ca9..128acd813b 100644
--- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.verifysession.impl_VerifySelfSessionView_null_VerifySelfSessionView-Night-0_2_null_2,NEXUS_5,1.0,en].png
+++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.verifysession.impl_VerifySelfSessionView_null_VerifySelfSessionView-Night-0_2_null_2,NEXUS_5,1.0,en].png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:77668eb95611c9b72913d286956b1b5e6bafe1cf6a1facfc00a5c4fd0ceab3d2
-size 49133
+oid sha256:9fdcab5fa8620cb0ba0cc0cb822fe4a4807198dbbcd7de7dd7a230d2fe3030e0
+size 49141
diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.verifysession.impl_VerifySelfSessionView_null_VerifySelfSessionView-Night-0_2_null_3,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.verifysession.impl_VerifySelfSessionView_null_VerifySelfSessionView-Night-0_2_null_3,NEXUS_5,1.0,en].png
index dd78bc04ea..c8329b273e 100644
--- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.verifysession.impl_VerifySelfSessionView_null_VerifySelfSessionView-Night-0_2_null_3,NEXUS_5,1.0,en].png
+++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.verifysession.impl_VerifySelfSessionView_null_VerifySelfSessionView-Night-0_2_null_3,NEXUS_5,1.0,en].png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:121d1b8f9a6abf9c50a951b2db6a7e52602ec34876a55e38b009f1fdffcd725d
-size 50525
+oid sha256:06b8e6bce1573d8e39a1bf5823945733152fde066a394a3e90f2bf8dc7929ea3
+size 50526
diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.verifysession.impl_VerifySelfSessionView_null_VerifySelfSessionView-Night-0_2_null_4,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.verifysession.impl_VerifySelfSessionView_null_VerifySelfSessionView-Night-0_2_null_4,NEXUS_5,1.0,en].png
index 62205e2c19..2db49fef25 100644
--- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.verifysession.impl_VerifySelfSessionView_null_VerifySelfSessionView-Night-0_2_null_4,NEXUS_5,1.0,en].png
+++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.verifysession.impl_VerifySelfSessionView_null_VerifySelfSessionView-Night-0_2_null_4,NEXUS_5,1.0,en].png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:322ff3eb42407c0e188521ca32361819b6740d323a3ee4411441853abbe44b8a
-size 30024
+oid sha256:10c16c9a29f898a6a33f8bfa10df24d2da9adb93eeb764e2b744c6efe531890e
+size 30007
diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.verifysession.impl_VerifySelfSessionView_null_VerifySelfSessionView-Night-0_2_null_5,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.verifysession.impl_VerifySelfSessionView_null_VerifySelfSessionView-Night-0_2_null_5,NEXUS_5,1.0,en].png
index 5e3429e748..29ac2f3227 100644
--- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.verifysession.impl_VerifySelfSessionView_null_VerifySelfSessionView-Night-0_2_null_5,NEXUS_5,1.0,en].png
+++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.verifysession.impl_VerifySelfSessionView_null_VerifySelfSessionView-Night-0_2_null_5,NEXUS_5,1.0,en].png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:48a8536aa38e0bb678d87b835ace8c5811f97e2311a771ed37b04aabd142f69b
-size 19981
+oid sha256:f4786a280d694ead76992dfa75f09bd2e20c292376509f86462a359d19be3e50
+size 19984
diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.verifysession.impl_VerifySelfSessionView_null_VerifySelfSessionView-Night-0_2_null_6,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.verifysession.impl_VerifySelfSessionView_null_VerifySelfSessionView-Night-0_2_null_6,NEXUS_5,1.0,en].png
index 7fb3f28454..b2be2a2397 100644
--- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.verifysession.impl_VerifySelfSessionView_null_VerifySelfSessionView-Night-0_2_null_6,NEXUS_5,1.0,en].png
+++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.verifysession.impl_VerifySelfSessionView_null_VerifySelfSessionView-Night-0_2_null_6,NEXUS_5,1.0,en].png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:83961b489de278edf3f2646f228e059e71f381363ffb751f44244a7d12604cb9
-size 33443
+oid sha256:59cabf858188557db3f2660f71cafc9b041977c656693dc5bc009da71a5c7648
+size 33457
diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[l.designsystem.atomic.pages_OnBoardingPage_null_OnBoardingPage-Day_0_null,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[l.designsystem.atomic.pages_OnBoardingPage_null_OnBoardingPage-Day_0_null,NEXUS_5,1.0,en].png
index b73b74bbcd..842430a4a0 100644
--- a/tests/uitests/src/test/snapshots/images/ui_S_t[l.designsystem.atomic.pages_OnBoardingPage_null_OnBoardingPage-Day_0_null,NEXUS_5,1.0,en].png
+++ b/tests/uitests/src/test/snapshots/images/ui_S_t[l.designsystem.atomic.pages_OnBoardingPage_null_OnBoardingPage-Day_0_null,NEXUS_5,1.0,en].png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:579b575f467e2d4b7adaab0c5ca7f3cc62e7a5ae18d8f67406b26df48ac0887e
-size 233216
+oid sha256:ab46218fff44d542277c3a498ee7b66ecbe2d233fd302f7e58ca322363bac563
+size 233128
diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[l.designsystem.atomic.pages_OnBoardingPage_null_OnBoardingPage-Night_1_null,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[l.designsystem.atomic.pages_OnBoardingPage_null_OnBoardingPage-Night_1_null,NEXUS_5,1.0,en].png
index a030afbbd0..c499dd3801 100644
--- a/tests/uitests/src/test/snapshots/images/ui_S_t[l.designsystem.atomic.pages_OnBoardingPage_null_OnBoardingPage-Night_1_null,NEXUS_5,1.0,en].png
+++ b/tests/uitests/src/test/snapshots/images/ui_S_t[l.designsystem.atomic.pages_OnBoardingPage_null_OnBoardingPage-Night_1_null,NEXUS_5,1.0,en].png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:9771fe25cb79b032ce28bee8edf5bafe0decb3effcaa153eb7f5c7d83df01d23
-size 369766
+oid sha256:28aacc92d6ccad7586b3e5d76c2cd70cfbcc2101551ee75a213fbb269a29dbd2
+size 369703
diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[l.designsystem.atomic.pages_SunsetPage_null_SunsetPage-Night_1_null,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[l.designsystem.atomic.pages_SunsetPage_null_SunsetPage-Night_1_null,NEXUS_5,1.0,en].png
index 9a5371804e..a6b5cfab9b 100644
--- a/tests/uitests/src/test/snapshots/images/ui_S_t[l.designsystem.atomic.pages_SunsetPage_null_SunsetPage-Night_1_null,NEXUS_5,1.0,en].png
+++ b/tests/uitests/src/test/snapshots/images/ui_S_t[l.designsystem.atomic.pages_SunsetPage_null_SunsetPage-Night_1_null,NEXUS_5,1.0,en].png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:50ca2afda159bdd7f57e78b04fbe3c022a9aeee1b68f72cf4d4269b3e503f0e5
-size 127335
+oid sha256:d56b02025c9de6cca3aaa3e4cc5cd82b222790c4efa0013f957307c13e45ee40
+size 151229
diff --git a/tools/localazy/config.json b/tools/localazy/config.json
index 1bf1e9071b..2416876fa4 100644
--- a/tools/localazy/config.json
+++ b/tools/localazy/config.json
@@ -106,7 +106,8 @@
"includeRegex" : [
"screen_roomlist_.*",
"session_verification_banner_.*",
- "confirm_recovery_key_banner_.*"
+ "confirm_recovery_key_banner_.*",
+ "screen_migration_.*"
]
},
{
@@ -154,7 +155,6 @@
"name" : ":features:ftue:impl",
"includeRegex" : [
"screen_welcome_.*",
- "screen_migration_.*",
"screen_notification_optin_.*"
]
},